Logo Search packages:      
Sourcecode: jclassinfo version File versions  Download package

main.c

/*
 * jclassinfo
 * Copyright (C) 2003  Nicos Panayides
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * Nicos Panayides
 * anarxia@gmx.net
 *
 * $Id: main.c,v 1.16 2004/05/07 12:11:22 anarxia Exp $
 */

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <unistd.h>
#include <jclass/jclass.h>
#include "common.h"
#include "string_list.h"

static void show_help(void);
static JavaClass* parse_class(const char*, int, int);

StringList* class_list;
StringList* package_list;
StringList* method_list;
StringList* interface_method_list;

ClassPath *classpath;

int main(int argc, char** argv)
{
      char* filename;
      JavaClass* temp_class;
      int i;
      int n_classes;
      int do_flag;
      JavaClass** classes;

      int classcounter; 
      
      JCVisibility visibility = V_PRIVATE;
      int option_index = 0;
      int getopt_return = 0;
      char *temp_string;
      char *class_path = NULL;
      char *bootclasspath = NULL;   

      static struct option long_options[] =
      {
            {"visibility",           1, NULL, VISIBILITY},
            {"all",                  0, NULL, 
                        (GENERAL_INFO | CONSTANT_POOL | FIELDS | METHODS | PACKAGES | 
                        CLASSES | METHOD_REF | ATTRIBUTES)},
            {"classpath",            1, NULL, CLASSPATH},
            {"bootclasspath",        1, NULL, BOOTCLASSPATH},
            {"xml",                  0, NULL,  XML_MODE},
            {"no-xml",               0, NULL,  (INVERSE|XML_MODE)},
            /* class information */
            {"general-info",         0, NULL, GENERAL_INFO},
            {"no-general-info",      0, NULL, (INVERSE|GENERAL_INFO)},
            {"constant-pool",        0, NULL, CONSTANT_POOL},
            {"no-constant-pool",     0, NULL, (INVERSE|CONSTANT_POOL)},
            {"fields",               0, NULL, FIELDS},
            {"no-fields",            0, NULL, (INVERSE|FIELDS)},
            {"methods",              0, NULL, METHODS},
            {"no-methods",           0, NULL, (INVERSE|METHODS)},
            {"disasm",               0, NULL, DISASM},
            {"no-disasm",            0, NULL, (INVERSE|DISASM)},
            {"verbose",              0, NULL, VERBOSE},
            {"no-verbose",           0, NULL, (INVERSE|VERBOSE)},
            {"method-debug-info",    0, NULL, METHOD_DEBUG_INFO},
            {"no-method-debug-info", 0, NULL, (INVERSE|METHOD_DEBUG_INFO)},
            {"attributes",           0, NULL, ATTRIBUTES},
            {"no-attributes",        0, NULL, (INVERSE|ATTRIBUTES)},
            /* dependency information */
            {"packages",             0, NULL, PACKAGES},
            {"no-packages,",         0, NULL, (INVERSE|PACKAGES)},
            {"classes",              0, NULL, CLASSES},
            {"no-classes",           0, NULL, (INVERSE|CLASSES)},
            {"methods-ref",          0, NULL, METHOD_REF},
            {"no-methods-ref",       0, NULL, (INVERSE|METHOD_REF)},
            {"find-class",           0, NULL, FIND_CLASS},
            {"recursive",            0, NULL, RECURSIVE},
            {"no-recursive",         0, NULL, (INVERSE|RECURSIVE)},
            {"quiet",                0, NULL, QUIET},
            /* usual stuff */
            {"version",              0, NULL, SHOW_VERSION},
            {"help",                 0, NULL, SHOW_HELP},
            {0, 0, 0, 0}
    };

      do_flag = 0;

      while(getopt_return != -1)
      {
            getopt_return = getopt_long(argc, argv, "", long_options, &option_index);

            switch(getopt_return)
            {
                  case -1:
                  case 0:
                        break;
                  case '?':
                        exit(2);
                        break;

                  case VISIBILITY:  /* visibility */
                        if(!strcmp(optarg, "public"))
                              visibility = V_PUBLIC;
                        else if(!strcmp(optarg, "package")) 
                              visibility = V_PACKAGE;
                        else if(!strcmp(optarg,"protected"))
                              visibility = V_PROTECTED;
                        else if(!strcmp(optarg,"private"))
                              visibility = V_PRIVATE;
                        else if(!strcmp(optarg,"synthetic"))
                              visibility = V_SYNTHETIC;
                        else
                        {
                              fprintf(stderr, PACKAGE_NAME ": invalid visibility \"%s\".\n",optarg);
                              fprintf(stderr, PACKAGE_NAME ": valid values: package, protected, private, synthetic.\n");
                              exit(3);
                        }
                        break;

                  case CLASSPATH:   /* classpath */
                        class_path = strdup(optarg);
                        break;

                  case BOOTCLASSPATH:     /* bootclasspath */
                        bootclasspath = strdup(optarg);
                        break;

                  case SHOW_HELP:
                        show_help();
                        exit(0);
                        break;

                  case SHOW_VERSION:
                        puts(PACKAGE_STRING);   
                        puts("Copyright (C) 2003-2004 Nicos Panayides");
                        exit(0);
                        break;

                  default:
                        if (getopt_return & INVERSE)
                              do_flag &= ~getopt_return;
                        else
                              do_flag |= getopt_return;
            }
      }

      if (optind >= argc)
    {
            fprintf(stderr, PACKAGE_NAME ": No class given.\n");
            exit(2);
      }
      
      classpath = jclass_classloader_get_classpath(class_path, bootclasspath);

      /* disasm and print_method_debug_info
            need methods to be turned on
      */
      if(do_flag & (DISASM | METHOD_DEBUG_INFO))
            do_flag |= METHODS;

      if(do_flag & XML_MODE)
            do_flag &= ~SECTION_TITLES;
      else
      {
            if (FUNCTION_OPTIONS(do_flag))
                  do_flag |= SECTION_TITLES;
      }

      if(!FUNCTION_OPTIONS(do_flag))
            do_flag |= GENERAL_INFO;
                  
      if (do_flag & RECURSIVE)
      {
            if (!( (do_flag & PACKAGES) || (do_flag & METHOD_REF) || (do_flag & PACKAGES) || (do_flag & CLASSES)) )
                  do_flag &= ~RECURSIVE;
      }
      
      if(do_flag & XML_MODE)
            puts("<jclassinfo version=\"" PACKAGE_VERSION "\">");

      if(do_flag & FIND_CLASS)
      {
            for(classcounter = optind; classcounter < argc; classcounter++)
            {
                  filename = jclass_classloader_get_class_filename(argv[classcounter], classpath);
                  if(filename == NULL)
                  {
                        if(do_flag & XML_MODE)
                              printf("<findclass name=\"%s\"/>", argv[classcounter]);
                        else
                              printf("Could not find class %s\n", argv[classcounter]);
                  }
                  else
                  {
                        if(do_flag & XML_MODE)
                              printf("<findclass name=\"%s\" location=\"%s\"/>", argv[classcounter], filename);
                        else
                              printf("class %s found in %s\n", argv[classcounter], filename);

                        free(filename);
                  }
            }

            if(!FUNCTION_OPTIONS(do_flag & ~FIND_CLASS))
            {
                  if(do_flag & XML_MODE)
                        puts("</jclassinfo>");
                  exit(0);
            }
      }
      
      class_list = string_list_new();
      method_list = string_list_new();
      interface_method_list = string_list_new();
      package_list = string_list_new();
      
      classes = (JavaClass**) malloc(sizeof(JavaClass*) * (argc - optind));
      n_classes = 0;
      for(classcounter = optind; classcounter < argc; classcounter++)
      {
            temp_class = parse_class(argv[classcounter], 1, do_flag);
            if(temp_class != NULL)
            {
                  classes[n_classes] = temp_class;
                  n_classes++;
            }
            if(!(do_flag & QUIET) && isatty(STDOUT_FILENO))
                  printf("\r%-70s\r", "");            
      }
      
      if(do_flag & RECURSIVE)
      {
            for(;;)
            {
                  temp_string = string_list_remove_first(class_list, IS_DEPENDENCY);
                  if(temp_string == NULL)
                        break;

                  parse_class(temp_string, 0, do_flag);
                  free(temp_string);
            }
            if(!(do_flag & QUIET) && isatty(STDOUT_FILENO))
                  printf("\r%-70s\r", "");
            
      }
      
      jclass_classloader_classpath_free(classpath);

      if(n_classes == 0)
      {
            free(classes);
            string_list_free(class_list);
            string_list_free(method_list);
            string_list_free(interface_method_list);
            string_list_free(package_list);
            return 1;
      }
      
      for(i = 0; i < n_classes; i++)
      {
            if (do_flag & XML_MODE)
                  print_class_xml(classes[i], do_flag, visibility);
            else
                  print_class(classes[i], do_flag, visibility);

            jclass_class_free(classes[i]);
      }
      free(classes);
      
      if(do_flag & PACKAGES)
      {     
            if(do_flag & XML_MODE)
            {
                  puts("<packagesref>");
                  string_list_print_xml(stdout, package_list, IS_DEPENDENCY);
                  puts("</packagesref>");
            }
            else
            {
                  if(do_flag & SECTION_TITLES)
                        puts("[PACKAGES REFERENCED]");
                  
                  string_list_print(stdout, package_list, IS_DEPENDENCY);
            }
      }
      string_list_free(package_list);

      if(do_flag & CLASSES)
      {
            if(do_flag & XML_MODE)
            {
                  puts("<classref>");
                  string_list_print_xml(stdout, class_list, IS_DEPENDENCY);
                  puts("</classref>");
            }
            else
            {
                  if(do_flag & SECTION_TITLES)
                        puts("[CLASSES/INTERFACES REFERENCED]");
                  
                  string_list_print(stdout, class_list, IS_DEPENDENCY);
            }           
      }
      string_list_free(class_list);
      
      if(do_flag & METHOD_REF)
      {     
            if(do_flag & XML_MODE)
            {
                  puts("<methodsref>");
                  string_list_print_xml(stdout, method_list, IS_DEPENDENCY);
                  puts("</methodsref>");
                  puts("<interfacemethodsref>");
                  string_list_print_xml(stdout, interface_method_list, IS_DEPENDENCY);
                  puts("</interfacemethodsref>");
            }
            else
            {
                  if(do_flag & SECTION_TITLES)
                  {
                        puts("[METHODS REFERENCED]");
                        if(string_list_is_empty(method_list))     
                              puts("none");
                  }
                  string_list_print(stdout, method_list, IS_DEPENDENCY);
            
                  if(do_flag & SECTION_TITLES)
                  {
                        puts("[INTERFACE METHODS REFERENCED]");
                        if(string_list_is_empty(interface_method_list)) 
                              puts("none");
                  }     
                  string_list_print(stdout, interface_method_list, IS_DEPENDENCY);
            }     
      }
      string_list_free(method_list);
      string_list_free(interface_method_list);

      if(do_flag & XML_MODE)
            puts("</jclassinfo>");
      
      return 0;
}

/**
* parse_class
* @classname: The name of the class or filename.
* @is_local: Set to 1 if the class will be fully processes.
* Set to 0 to only parse the constant pool for dependencies.
*
* Parses and returns the given class.
*
*/
JavaClass* parse_class(const char* classname, int is_local, int do_flag)
{
      JavaClass* classfile;
      ConstantPool* constant_pool;
      char* this_class;
      char* this_package;
      char* method_name;
      char* class_name;
      char* package_name;
      uint16_t count;
      int flag, method_flag;
      
      if(is_local)
      {
            classfile = jclass_class_new(classname, classpath);
            if(classfile == NULL)
                  constant_pool = NULL;
            else
                  constant_pool = classfile->constant_pool;
      }
      else
      {
            classfile = NULL;
            constant_pool = jclass_cp_new(classname, classpath);
      }

      if(constant_pool == NULL)
      {
            fprintf(stderr, PACKAGE_NAME ": Could not load class \"%s\"\n", classname);
            return NULL;
      }

      this_class = jclass_cp_get_this_class_name(constant_pool);
      this_package = jclass_get_package_from_class_name(this_class);

/* Disable message because cmd sucks */
#ifndef __WIN32__ 
      if(!(do_flag & QUIET) && isatty(STDOUT_FILENO))
      {
            printf("\rReading class %-65s ", this_class);
            fflush(stdout);
      }
#endif
      
      /* check if class has been parsed */
      flag = (is_local? IS_LOCAL: IS_DEPENDENCY);
      if(!string_list_add(class_list, this_class, (flag | IS_FINISHED)))
      {
            if(classfile != NULL)
                  jclass_class_free(classfile);
            else
                  jclass_cp_free(constant_pool);
            
            free(this_class);
            free(this_package);
            return NULL;
      }
      
      string_list_add(package_list, this_package, flag);

      for(count = 1; count < constant_pool->count; count++)
      {
            switch(constant_pool->entries[count].tag)
            {
                  case CONSTANT_Class:
                        class_name = jclass_cp_get_class_name(constant_pool, count, 1);
                        package_name = jclass_get_package_from_class_name(class_name);
                              
                        if(!jclass_string_is_primitive_type(class_name))
                        {
                              if(strcmp(class_name, this_class) != 0)
                              {
                                    if(strchr(class_name,'$') == NULL)
                                          string_list_add(class_list, class_name, IS_DEPENDENCY);
                              }
                        }
                        free(class_name);
                        
                        if(package_name != NULL)
                        {     
                              if(do_flag & PACKAGES)
                                    string_list_add(package_list, package_name, IS_DEPENDENCY);
                              free(package_name);
                        }
                        break;
                        
                  case CONSTANT_Methodref:
                  case CONSTANT_InterfaceMethodref:
                        if(do_flag & METHOD_REF)
                        {
                              method_name = jclass_cp_get_method_signature(constant_pool, count, 1);
                              if(method_name != NULL)
                              {
                                    class_name = jclass_get_class_from_method_signature(method_name);
                                    
                                    method_flag = (strcmp(class_name, this_class)? IS_DEPENDENCY: flag);
                                    if (constant_pool->entries[count].tag == CONSTANT_Methodref)
                                          string_list_add(method_list, method_name, method_flag);
                                    else
                                          string_list_add(interface_method_list, method_name, method_flag);
                                    
                                    free(class_name);
                                    free(method_name);
                              }
                              
                        }
                        break;
            }
      }
      free(this_class);
      if(this_package != NULL)
            free(this_package);
      
      if(classfile == NULL)
            jclass_cp_free(constant_pool);

      return classfile;
}

void show_help()
{
#define PRINT_OPTION(option, optionhelp) printf("  %-23s %s\n", option, optionhelp)
      
      puts("Usage: " PACKAGE_NAME  " [OPTION]... <class>...");
      puts("Provides information about java class files.");
      puts("Classes can be specified by name or filename.");
      puts("\nOptions:");
      PRINT_OPTION("--classpath=PATH", "Set classpath.");
      PRINT_OPTION("--bootclasspath=PATH", "Set bootstrap classpath.");
      PRINT_OPTION("--all", "Print all available information.");
      PRINT_OPTION("--xml", "XML output (experimental).");
      PRINT_OPTION("--version", "Print version information.");
      PRINT_OPTION("--help", "This message.");
      
      puts("\nClass information related:");
      PRINT_OPTION("--visibility=VISIBILITY", "Visibility used for printing the information.");
      PRINT_OPTION("--general-info", "Print general information about this class.");
      PRINT_OPTION("--constant-pool", "Print constant pool.");
      PRINT_OPTION("--fields", "Print fields.");
      PRINT_OPTION("--methods", "Print methods.");
      PRINT_OPTION("--disasm", "Print disassembled code.");
      PRINT_OPTION("--verbose", "Print exception table, max stack and locals for methods.");
      PRINT_OPTION("--method-debug-info", "Print line numbers and local variables.");
      PRINT_OPTION("--attributes", "Print class attributes.");
      
      puts("\nDependency information:");
      PRINT_OPTION("--find-class", "Finds the file containing the given class");
      PRINT_OPTION("--packages", "Print packages referenced.");
      PRINT_OPTION("--classes", "Print classes/interfaces referenced.");
      PRINT_OPTION("--methods-ref", "Print methods referenced.");
      PRINT_OPTION("--recursive", "Find dependencies recurcively.");
      PRINT_OPTION("--quiet", "Surpress status messages.");
      
      puts("\nVISIBILITY may be one of the following:");
      puts("public, package, protected, private, synthetic.");
      
      puts("\nNote: options can be reversed by adding the no- prefix.");
      
      puts("\nReport bugs to <" PACKAGE_BUGREPORT ">.");
}

Generated by  Doxygen 1.6.0   Back to index