home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / MiscKit1.7.1 / MiscKit / Palettes / MiscClassDecoderPalette / MiscClassDecoder.subproj / MiscClassDecoder.m < prev    next >
Encoding:
Text File  |  1994-12-01  |  14.8 KB  |  760 lines

  1. //
  2. // Time-stamp: <94/12/01 20:23:30 stephan>
  3. //
  4. //    MiscClassDecoder.m -- an Object subclass that is able to analyze
  5. //    the definition of an Objective-C class.
  6. //    
  7. //        Written by Stephan Wacker <stephan@rodion.muc.de>
  8. //        Copyright (c) 1994 by Stephan Wacker.
  9. //        Version 1.0  All rights reserved.
  10. //        This notice may not be removed from this source code.
  11. //
  12. //    This object is included in the MiscKit by permission from the author
  13. //    and its use is governed by the MiscKit license, found in the file
  14. //    "LICENSE.rtf" in the MiscKit distribution.  Please refer to that file
  15. //    for a list of all applicable permissions and restrictions.
  16. //    
  17.  
  18.  
  19. #import "MiscClassDecoder.h"
  20. // #import <misckit/MiscClassDecoder.h>
  21.  
  22. #import <objc/objc-runtime.h>
  23. #import <ctype.h>
  24.  
  25.  
  26. #define K_IndentInstanceVar    4
  27. #define K_IndentStructMember    2
  28.  
  29.  
  30. //====<   Private methods   >====//
  31.  
  32. @interface MiscClassDecoder ( Private )
  33.  
  34. - clearText;
  35. - appendText: (const char *) aString, ...;
  36. - appendLine: (const char *) aString, ...;
  37. - finishOutput;
  38.  
  39. - (const char *) showType: (const char *) aTypeString;
  40. - showMethod: (Method) aMethod prefix: (char *) prefix;
  41.  
  42. - showInheritance: (Class) aClass;
  43. - showProtocols: (Class) aClass;
  44. - showInstanceVars: (Class) aClass;
  45. - showInstanceMethods: (Class) aClass;
  46. - showClassMethods: (Class) aMetaclass;
  47.  
  48. - setText: aText;
  49.  
  50. + initialize;
  51. - read: (NXTypedStream *) stream;
  52. - write: (NXTypedStream *) stream;
  53.  
  54. @end // MiscClassDecoder ( Private )
  55.  
  56.  
  57. //====<   Auxiliary functions   >====//
  58.  
  59. static
  60. const char * type_name( char type )
  61. // Decode single character `type'.
  62. {
  63.     const char    *result = NULL;
  64.     
  65.     switch( type )
  66.     {
  67.     case _C_ID    : result = "id";        break;
  68.     case _C_CLASS    : result = "Class";        break;
  69.     case _C_SEL    : result = "SEL";        break;
  70.     case _C_CHR    : result = "char";        break;
  71.     case _C_UCHR    : result = "unsigned char";    break;
  72.     case _C_SHT    : result = "short";        break;
  73.     case _C_USHT    : result = "unsigned short";    break;
  74.     case _C_INT    : result = "int";        break;
  75.     case _C_UINT    : result = "unsigned int";    break;
  76.     case _C_LNG    : result = "long";        break;
  77.     case _C_ULNG    : result = "unsigned long";    break;
  78.     case _C_FLT    : result = "float";        break;
  79.     case _C_DBL    : result = "double";        break;
  80.     case _C_VOID    : result = "void";        break;
  81.     case _C_UNDEF    : result = "<undef>";        break;
  82.     case _C_CHARPTR    : result = "char *";        break;
  83.     }
  84.     
  85.     return result;
  86.  
  87. } // type_name()
  88.  
  89.  
  90. static
  91. const char * struct_name( const char *name, int len )
  92. // Check for well-known struct names.
  93. {
  94. #define M_TEST_UNDERSCORE( type ) \
  95.     if( ! strncmp( name, "_" #type, len ) ) return (#type)
  96.     
  97.     switch( len )
  98.     // Add other common names to this list.
  99.     {
  100.       case 6:
  101.     M_TEST_UNDERSCORE( NXFSM );
  102.     M_TEST_UNDERSCORE( NXLay );
  103.     M_TEST_UNDERSCORE( NXRun );
  104.     break;
  105.       case 7:
  106.     M_TEST_UNDERSCORE( NXRect );
  107.     M_TEST_UNDERSCORE( NXSize );
  108.     M_TEST_UNDERSCORE( NXZone );
  109.     break;
  110.       case 8:
  111.     M_TEST_UNDERSCORE( NXChunk );
  112.     M_TEST_UNDERSCORE( NXColor );
  113.     M_TEST_UNDERSCORE( NXEvent );
  114.     M_TEST_UNDERSCORE( NXPoint );
  115.     M_TEST_UNDERSCORE( NXSelPt );
  116.     break;
  117.       case 9:
  118.     M_TEST_UNDERSCORE( NXScreen );
  119.     M_TEST_UNDERSCORE( NXStream );
  120.     break;
  121.       case 10:
  122.     M_TEST_UNDERSCORE( NXDefault );
  123.     M_TEST_UNDERSCORE( NXHandler );
  124.     M_TEST_UNDERSCORE( NXLayInfo );
  125.     M_TEST_UNDERSCORE( NXMessage );
  126.     M_TEST_UNDERSCORE( NXTabStop );
  127.     break;
  128.       case 11:
  129.     M_TEST_UNDERSCORE( NXFaceInfo );
  130.     M_TEST_UNDERSCORE( NXLayArray );
  131.     M_TEST_UNDERSCORE( NXResponse );
  132.     M_TEST_UNDERSCORE( NXRunArray );
  133.     break;
  134.       case 12:
  135.     M_TEST_UNDERSCORE( NXCharArray );
  136.     M_TEST_UNDERSCORE( NXTextBlock );
  137.     M_TEST_UNDERSCORE( NXTextCache );
  138.     M_TEST_UNDERSCORE( NXTextStyle );
  139.     break;
  140.       case 13:
  141.     M_TEST_UNDERSCORE( NXBreakArray );
  142.     M_TEST_UNDERSCORE( NXHeightInfo );
  143.     M_TEST_UNDERSCORE( NXWidthArray );
  144.     break;
  145.       case 14:
  146.     M_TEST_UNDERSCORE( NXAcknowledge );
  147.     M_TEST_UNDERSCORE( NXFontMetrics );
  148.     break;
  149.       case 15:
  150.     M_TEST_UNDERSCORE( NXHeightChange );
  151.     M_TEST_UNDERSCORE( NXModalSession );
  152.     M_TEST_UNDERSCORE( NXRemoteMethod );
  153.     break;
  154.       case 16:
  155.     M_TEST_UNDERSCORE( NXTrackingTimer );
  156.     break;
  157.     }
  158.     
  159.     return NULL;
  160.     
  161. #undef M_TEST_UNDERSCORE
  162.  
  163. } // structName()
  164.  
  165.  
  166. @implementation MiscClassDecoder
  167.  
  168.  
  169. //====<   Writing text   >====//
  170.  
  171. - clearText
  172. // Delete contents of `text'.
  173. {
  174.     [text selectAll: self];
  175.     [text delete: self];
  176.  
  177.     indent = 0, bol = YES, lineCount = 0;
  178.  
  179.     return self;
  180.  
  181. } // clearText
  182.  
  183.  
  184. - appendText: (const char *) aString, ...
  185. // Append `aString' to the contents of `text'.
  186. {
  187.     va_list    ap;
  188.     char    buf[4000], *buf_p = buf;
  189.     int        pos;
  190.     
  191.     pos = [text textLength];
  192.     [text setSel: pos : pos];
  193.  
  194.     if( bol )
  195.     {
  196.     sprintf( buf_p, "%*s", indent, "" );
  197.     buf_p += indent;
  198.     bol = NO;
  199.     }
  200.  
  201.     va_start(ap, aString);
  202.     vsprintf( buf_p, aString, ap );
  203.     [text replaceSel: buf];
  204.     
  205.     return self;
  206.  
  207. } // appendText:...
  208.  
  209.  
  210. - appendLine: (const char *) aString, ...
  211. // Append `aString' to `text' and start a new line.
  212. {
  213.     va_list    ap;
  214.     char    buf[4000], *buf_p = buf;
  215.     int        pos;
  216.     
  217.     pos = [text textLength];
  218.     [text setSel: pos : pos];
  219.     
  220.     if( bol )
  221.     {
  222.     sprintf( buf_p, "%*s", indent, "" );
  223.     buf_p += indent;
  224.     }
  225.     else
  226.     {
  227.     bol = YES;
  228.     }
  229.  
  230.     va_start(ap, aString);
  231.     vsprintf( buf_p, aString, ap );
  232.     strcat( buf_p, "\n" );
  233.     [text replaceSel: buf];
  234.  
  235.     if( ++ lineCount == 20 )
  236.     {
  237.     [[text window] disableDisplay];
  238.     [text setNeedsDisplay: YES];
  239.     }
  240.     
  241.     return self;
  242.  
  243. } // appendLine:...
  244.  
  245.  
  246. - finishOutput
  247. // Final actions after all text has been output.
  248. {
  249.     [classNameField selectText: self];
  250.     
  251.     if( ! [[text window] isDisplayEnabled] )
  252.     {
  253.     [[[text window] reenableDisplay] display];
  254.     }
  255.  
  256.     return self;
  257. } // finishOutput
  258.  
  259. //====<   Decoding type specifications   >====//
  260.  
  261. - (const char *) showType: (const char *) aTypeString
  262. // Recursive interpretation of the encoded `aTypeString'.
  263. // Return position after analyzed substring.
  264. {
  265.     const char    *typeName;
  266.     const char    *p = aTypeString;
  267.     const char    *pe;
  268.     const char    *memberName;
  269.     int        i;
  270.     
  271.     switch( *p )
  272.     {
  273.       case _C_PTR:        // Pointer
  274.     p = [self showType: p+1];
  275.     [self appendText: " *"];
  276.     break;
  277.     
  278.       case _C_BFLD:        // Bitfield
  279.     for( ++p, i = 0; isdigit(*p); p++ )
  280.     {
  281.         i = i * 10 + (*p - '0');
  282.     }
  283.     // We don't really know the bitfield's type,
  284.     // but `unsigned int' is a good guess.
  285.     [self appendText: "unsigned int ... : %d", i];
  286.     break;
  287.     
  288.       case _C_ARY_B:        // Array begin
  289.     for( ++p, i = 0; isdigit(*p); p++ )
  290.     {
  291.         i = i * 10 + (*p - '0');
  292.     }
  293.     p = [self showType: p];
  294.     [self appendText: " ... [%d]", i];
  295.     // TODO: correct syntax
  296.  
  297.     if( *p == _C_ARY_E )    // Array end
  298.     {
  299.         ++p;
  300.     }
  301.     else
  302.     {
  303.         // TODO: report error
  304.     }
  305.     break;
  306.     
  307.     
  308.       case _C_STRUCT_B:        // Struct begin
  309.     for( pe = ++p; *pe && *pe != '=' && *pe != _C_STRUCT_E; pe++ )
  310.     {
  311.         // keep on going
  312.     }
  313.         
  314.     if( (typeName = struct_name( p, pe-p )) != NULL )
  315.                 // it's a well-known struct
  316.     {
  317.         [self appendText: "%s", typeName];
  318.         for( p = pe-1, i = 1; *++p && i > 0; ) {
  319.         switch( *p ) {
  320.           case _C_STRUCT_B: i++; break;
  321.           case _C_STRUCT_E: i--; break;
  322.         }
  323.         } // for p
  324.     }
  325.     else
  326.     {
  327.         [self appendText: "struct %.*s", pe-p, p];
  328.         if( *(p=pe) == '=' ) {
  329.         [self appendLine: " {"];
  330.         indent += K_IndentStructMember;
  331.         for( i = 1, ++p; *p && *p != _C_STRUCT_E; i++ )
  332.         {
  333.             if( *p == '"' )
  334.             {
  335.             for( memberName = pe = p+1; *pe && *pe != '"'; pe++ )
  336.             {
  337.                 // keep on going
  338.             }
  339.             p = pe+1;
  340.             }
  341.             else
  342.             {
  343.             memberName = NULL;
  344.             }
  345.             p = [self showType: p];
  346.             if( memberName )
  347.             {
  348.             [self appendLine: " %.*s;",
  349.              pe-memberName, memberName];
  350.             }
  351.             else
  352.             {
  353.             [self appendLine: " member_%d;", i];
  354.             }
  355.         }
  356.         indent -= K_IndentStructMember;
  357.         [self appendText: "}"];
  358.         }
  359.     }
  360.  
  361.     if( *p == _C_STRUCT_E )    // Struct end
  362.     {
  363.         ++p;
  364.     }
  365.     else
  366.     {
  367.         // TODO: report error
  368.     }
  369.     break;
  370.     
  371.     
  372.       case _C_UNION_B:        // Union begin
  373.     [self appendLine: "union {"];
  374.     indent += K_IndentStructMember;
  375.     for( i = 1, ++p; *p && *p != _C_UNION_E; i++ )
  376.     {
  377.         p = [self showType: p];
  378.         [self appendLine: " case_%d;", i];
  379.     }
  380.     indent -= K_IndentStructMember;
  381.     [self appendText: "}"];
  382.     
  383.     if( *p == _C_UNION_E )
  384.     {
  385.         ++p;
  386.     }
  387.     else
  388.     {
  389.         // TODO: report error
  390.     }
  391.     break;
  392.     
  393.     
  394.       default:
  395.     if( ! (typeName = type_name( *p )) )
  396.     {
  397.         [self appendText: "<?: %c>", *p ];
  398.     }
  399.     else
  400.     {
  401.         [self appendText: "%s", typeName];
  402.     }
  403.     ++ p;
  404.     break;
  405.     
  406.     } // switch( first char of aTypeString )
  407.     
  408.     return p;
  409.  
  410. } // showType:
  411.  
  412.  
  413. - showMethod: (Method) aMethod prefix: (char *) prefix
  414. // Show declaration of `aMethod'.
  415. // `prefix' is either "-" or "+".
  416. {
  417.     const char    *name = sel_getName( aMethod->method_name );
  418.     const char    *p, *pe;
  419.     int        nArgs = method_getNumberOfArguments( aMethod );
  420.     int        i;
  421.     const char    *type;
  422.     int        offset;
  423.     
  424.     
  425.     if( prefix )
  426.     {
  427.     [self appendText: "%s ", prefix];
  428.     }
  429.     
  430.     if( nArgs <= 2 )
  431.     {
  432.     [self appendLine: "%s;", name];
  433.     }
  434.     else
  435.     {
  436.     for( i = 2, p = name; i < nArgs; i++, p = pe )
  437.     {
  438.         for( pe = p; *pe && *pe++ != ':'; )
  439.         {
  440.         // keep on going
  441.         }
  442.         [self appendText: "%s%.*s", (i == 2 ? "" : " "), pe-p, p];
  443.         
  444.         method_getArgumentInfo( aMethod, i, &type, &offset );
  445.  
  446.         // Don't print default return type `id'.
  447.         if( *type != _C_ID )
  448.         {
  449.         [self appendText: " ("];
  450.         [self showType: type];
  451.         [self appendText: ")"];
  452.         }
  453.         [self appendText: " arg_%d", i-1];
  454.  
  455.     } // for i, p
  456.     
  457.     [self appendLine: ";"];
  458.     }
  459.  
  460.     return self;
  461.  
  462. } // showMethod:prefix:
  463.  
  464.  
  465. //====<   Showing the class definition   >====//
  466.  
  467. - showInheritance: (Class) aClass
  468. // Show name of `aClass' and its superclass.
  469. {
  470.     Class    superClass = [aClass superclass];
  471.     
  472.     [self appendText: "%s", [aClass name]];
  473.     if( superClass )
  474.     {
  475.     [self appendLine: " : %s", [superClass name]];
  476.     }
  477.     else
  478.     {
  479.     [self appendLine: " // root class"];
  480.     }
  481.     
  482.     return self;
  483.  
  484. } // showInheritance:
  485.  
  486.  
  487. - showProtocols: (Class) aClass
  488. // Show all protocols adopted by `aClass'.
  489. {
  490.     if( ! aClass->protocols || aClass->protocols->count == 0 )
  491.     {
  492.     // do nothing
  493.     }
  494.     else
  495.     {
  496.     int        i;
  497.     Protocol    **pp = aClass->protocols->list;
  498.     
  499.     [self appendText: "  < %s", [*pp name]];
  500.     
  501.     for( i = 1, pp++; i < aClass->protocols->count; i++, pp++ )
  502.     {
  503.         [self appendText: ", %s", [*pp name]];
  504.     }
  505.     
  506.     [self appendLine: " >"];
  507.     }
  508.     
  509.     return self;
  510.  
  511. } // showProtocols:
  512.  
  513.  
  514. - showInstanceVars: (Class) aClass
  515. // Show definition of all instance variables defined in `aClass'.
  516. {
  517.     [self appendLine: "{"];
  518.     indent += K_IndentInstanceVar;
  519.     
  520.     if( ! aClass->ivars )
  521.     {
  522.     [self appendLine: "// no instance variables"];
  523.     }
  524.     else
  525.     {
  526.     int    i;
  527.     Ivar    ivp = aClass->ivars->ivar_list;
  528.     
  529.     for( i = 0; i < aClass->ivars->ivar_count; i++, ivp++ )
  530.     {
  531.         // [self appendLine: "// %s", ivp->ivar_type];
  532.         [self showType: ivp->ivar_type];
  533.         [self appendLine: " %s;", ivp->ivar_name];
  534.     } // for i
  535.     }
  536.     
  537.     indent -= K_IndentInstanceVar;
  538.     [self appendLine: "}"];
  539.     
  540.     return self;
  541.  
  542. } // showInstanceVars:
  543.  
  544.  
  545. - showInstanceMethods: (Class) aClass
  546. // Show declaration of all instance methods defined in `aClass'.
  547. {
  548.     if( ! aClass->methods )
  549.     {
  550.     [self appendLine: "// no instance methods"];
  551.     }
  552.     else
  553.     {
  554.     struct objc_method_list    *mlp;
  555.     int    i, m;
  556.     Method    mp;
  557.     
  558.     for( m = 1, mlp = aClass->methods;
  559.          mlp != NULL;
  560.          m++, mlp = mlp->method_next )
  561.     {
  562.         [self appendLine: ""];
  563.         [self appendLine: "// Instance method block #%d holds %d method%s",
  564.          m, mlp->method_count, (mlp->method_count == 1 ? "" : "s")];
  565.  
  566.         for( i = 0, mp = mlp->method_list;
  567.              i < mlp->method_count;
  568.          i++, mp++ )
  569.         {
  570.         [self showMethod: mp prefix: "-"];
  571.         } // for i
  572.     } // for m, mlp
  573.     }
  574.     
  575.     return self;
  576.  
  577. } // showInstanceMethods:
  578.  
  579.  
  580. - showClassMethods: (Class) aMetaclass
  581. // Show declaration of all class methods defined in aMetaclass.
  582. {
  583.     if( ! aMetaclass->methods )
  584.     {
  585.     [self appendLine: "// no class methods"];
  586.     }
  587.     else
  588.     {
  589.     struct objc_method_list    *mlp;
  590.     int    i, m;
  591.     Method    mp;
  592.     
  593.     for( m = 1, mlp = aMetaclass->methods;
  594.          mlp != NULL;
  595.          m++, mlp = mlp->method_next )
  596.     {
  597.         [self appendLine: ""];
  598.         [self appendLine: "// Class method block #%d holds %d method%s",
  599.          m, mlp->method_count, (mlp->method_count == 1 ? "" : "s")];
  600.  
  601.         for( i = 0, mp = mlp->method_list;
  602.              i < mlp->method_count;
  603.          i++, mp++ )
  604.         {
  605.         [self showMethod: mp prefix: "+"];
  606.         } // for i
  607.     } // for m, mlp
  608.     }
  609.     
  610.     return self;
  611.  
  612. } // showClassMethods:
  613.  
  614.  
  615. //====<   Actions   >====//
  616.  
  617. - analyze: sender
  618. // Analyze class specified in `classNameField'.
  619. {
  620.     const char    *className = [classNameField stringValue];
  621.     Class    class;
  622.     
  623.     
  624.     [self clearText];
  625.     
  626.     if( !(class = objc_lookUpClass( className )) )
  627.     {
  628.     [self appendLine: "No class named \"%s\".", className];
  629.     }
  630.     else
  631.     {
  632.     [self appendLine: "// Definition of class %s, Version %d",
  633.      className, class_getVersion(class)];
  634.     [self appendLine: ""];
  635.     [self appendText: "@interface "];
  636.     [self showInheritance: class];
  637.     [self showProtocols: class];
  638.     [self showInstanceVars: class];
  639.     [self appendLine: ""];
  640.     [self showClassMethods: class->isa];
  641.     [self appendLine: ""];
  642.     [self showInstanceMethods: class];
  643.     [self appendLine: ""];
  644.     [self appendLine: "@end"];
  645.     }
  646.  
  647.     [self finishOutput];
  648.     
  649.     return self;
  650.  
  651. } // analyze:
  652.  
  653.  
  654. - list: sender
  655. // List all known classes.
  656. {
  657.     NXHashTable    *classes = objc_getClasses();
  658.     NXHashState    state = NXInitHashState(classes);
  659.     Class    aClass;
  660.     
  661.  
  662.     [self clearText];
  663.     
  664.     while( NXNextHashState(classes, &state, (void **)&aClass) )
  665.     {
  666.     [self appendLine: "%s", [aClass name]];
  667.     }
  668.  
  669.     [self finishOutput];
  670.     
  671.     return self;
  672.  
  673. } // list:
  674.  
  675.  
  676. //====<   Services   >====//
  677.  
  678. - analyzeClass: (const char *) className
  679. // Analyze class given in `className'.
  680. {
  681.     [classNameField setStringValue: className];
  682.     return [self analyze: self];
  683. }
  684.  
  685.  
  686. //====<   Outlet connections   >====//
  687.  
  688. - setText: aText
  689. // Connect to `aText' and set its attributes.
  690. {
  691.     text = aText;
  692.     
  693.     [text setNoWrap];
  694.     [text setMonoFont: YES];
  695.     
  696.     return self;
  697.  
  698. } // setText:
  699.  
  700.  
  701. //====<   Archiving   >====//
  702.  
  703. + initialize
  704. {
  705.     if( self == [MiscClassDecoder class] )
  706.     {
  707.     [self setVersion: K_MiscClassDecoderVersion];
  708.     }
  709.  
  710.     return self;
  711.  
  712. } // +initialize
  713.  
  714.  
  715. - read: (NXTypedStream *) stream
  716. {
  717.     int version;
  718.     
  719.     [super read: stream];
  720.     
  721.     version = NXTypedStreamClassVersion( stream, "MiscClassDecoder" );
  722.     
  723.     switch( version )
  724.     {
  725.       case 1:
  726.     NXReadTypes( stream,
  727.              K_MiscClassDecoderRWformat_V1,
  728.              K_MiscClassDecoderRWvars_V1 );
  729.     break;
  730.  
  731.       default:
  732.     classNameField = nil;
  733.     text = nil;
  734.     break;
  735.     }
  736.  
  737.     // Initialize non-archived instance variables.
  738.     //
  739.     indent = 0;
  740.     bol = FALSE;
  741.     lineCount = 0;
  742.     
  743.     return self;
  744.  
  745. } // read:
  746.  
  747.  
  748. - write: (NXTypedStream *) stream
  749. {
  750.     [super write: stream];
  751.     
  752.     NXWriteTypes( stream,
  753.           K_MiscClassDecoderRWformat_V1,
  754.           K_MiscClassDecoderRWvars_V1 );
  755.     
  756.     return self;
  757. } // write:
  758.  
  759. @end    // MiscClassDecoder
  760.