Source file: /~heha/hs/gputils64-210929.zip/gputils/gplib.cpp

/* GNU PIC Librarian
   Copyright 2001-2005	Craig Franklin
   Copyright 2016	Molnár Károly
*/

#include "stdhdr.h"

#include "libgputils.h"
#include "gplib.h"

struct gplib_state state;

static symbol_table_t *definition_tbl = NULL;
static symbol_table_t *symbol_index   = NULL;

static const char longopts[] =
  "ccreate\0"
  "ddelete\0"
  "hhelp\0"
  "nno-index\0"
  "qquiet\0"
  "rreplace\0"
  "ssymbols\0"
  "tlist\0"
  "vversion\0"
  "xextract\0";

static const char longdesc[] =
  "Create a new library.\0"
  "Delete member from library.\0"
  "Show this usage message.\0"
  "Don't add symbol index.\0"
  "Quiet mode.\0"
  "Add or replace member from library.\0"
  "List global symbols in library.\0"
  "List members in library.\0"
  "Show version.\0"
  "Extract member from library.\0";

/*------------------------------------------------------------------------------------------------*/

static void _show_usage(const char*argv0) {
  printf("Usage: %s [options] library [member]\n",argv0);
  gp_usage(0,longopts,longdesc,20);
  exit(0);
}

/*------------------------------------------------------------------------------------------------*/

static void _select_mode(lib_modes Mode) {
  if (state.mode == AR_NULL) state.mode = Mode;
  else gp_error("Multiple library operations selected!");
}

/*------------------------------------------------------------------------------------------------*/

/* return the object name without the path */

static const char* _object_name(const char* File_name) {
  const char* name;

#ifdef HAVE_DOS_BASED_FILE_SYSTEM
  for (name = File_name + strlen(File_name) - 1; name >= File_name; --name) {
    if ((name[0] == UNIX_PATH_CHAR) || (name[0] == PATH_SEPARATOR_CHAR)) {
      return ++name;
    }
  }
  return File_name;
#else
  name = strrchr(File_name, PATH_SEPARATOR_CHAR);
  if (name) {
    return ++name;
  }
  else {
    return File_name;
  }
#endif
}

/*------------------------------------------------------------------------------------------------*/

static bool _has_path(const char* File_name) {
  const char* name;

  name = strrchr(File_name, PATH_SEPARATOR_CHAR);
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
  if (name) {
    name = strrchr(File_name, UNIX_PATH_CHAR);
  }
#endif

  return !!name;
}

/*------------------------------------------------------------------------------------------------*/
static bool usage, no_index;

static void _stdcall onOption(void*, char c, const char*arg) {
  switch (c) {
    case '?':
    case 'h': usage = true;		break;
    case 'c': _select_mode(AR_CREATE);	break;
    case 'd': _select_mode(AR_DELETE);	break;
    case 'n': no_index = true;		break;
    case 'q': gp_quiet = true;		break;
    case 'r': _select_mode(AR_REPLACE);	break;
    case 's': _select_mode(AR_SYMBOLS);	break;
    case 't': _select_mode(AR_LIST);	break;
    case 'v':
      fprintf(stderr, "%s\n", GPLIB_VERSION_STRING);
      exit(0);
    case 'x': _select_mode(AR_EXTRACT);	break;
    case 0: {	// freestanding parameter, mostly a file name
      if (state.filename) state.objectnames.push_back(arg);
      else state.filename = arg;
    }break;
  }
}

int _cdecl main(int argc, char* argv[]) {
  gp_init();
  /* symbols are case sensitive */
  definition_tbl = gp_sym_push_table(NULL, false);
  symbol_index   = gp_sym_push_table(NULL, false);

  gp_getopt(argv,longopts,onOption,0);

  // User did not select an operation.
  // User did not provide object names.
  if (state.mode == AR_NULL
   || state.mode != AR_LIST && state.mode != AR_SYMBOLS && state.objectnames.empty()
   || usage) _show_usage(*argv);

  // If we are not creating a new archive, we have to read an existing one.
  if (state.mode != AR_CREATE) {
    if (gp_identify_coff_file(state.filename) != GP_COFF_ARCHIVE) {
      gp_error("\"%s\" is not a valid archive file.", state.filename);
      exit(1);
    }

    state.archive = gp_archive_read(state.filename);
  }

  /* process the option */
  bool update_archive = false;
  std::list<const char*>::iterator it;
//  i = 0;
  switch (state.mode) {
    case AR_CREATE:
    case AR_REPLACE: {
      for (it=state.objectnames.begin(); it!=state.objectnames.end(); ++it) {
        const char*obj_name = *it;
        gp_coff_t type = gp_identify_coff_file(obj_name);
        if ((type != GP_COFF_OBJECT_V2) && (type != GP_COFF_OBJECT)) {
          gp_error("\"%s\" is not a valid object file.", obj_name);
          break;
        }
        state.archive = gp_archive_add_member(state.archive, obj_name, _object_name(obj_name));
      }
      update_archive = true;
      break;
    }

    case AR_DELETE: {
      for (it=state.objectnames.begin(); it!=state.objectnames.end(); ++it) {
        const char*obj_name = *it;
        if (_has_path(obj_name)) {
          gp_error("Invalid object name: \"%s\"", obj_name);
          break;
        }
        gp_archive_t*object = gp_archive_find_member(state.archive, obj_name);
        if (!object) {
          gp_error("Object \"%s\" not found.", obj_name);
          break;
        }

        state.archive = gp_archive_delete_member(state.archive, obj_name);
      }
      update_archive = true;
      break;
    }

    case AR_EXTRACT: {
      for (it=state.objectnames.begin(); it!=state.objectnames.end(); ++it) {
        const char*obj_name = *it;

        if (_has_path(obj_name)) {
          gp_error("Invalid object name: \"%s\"", obj_name);
          break;
        }

        gp_archive_t*object = gp_archive_find_member(state.archive, obj_name);
        if (!object) {
          gp_error("Object \"%s\" not found.", obj_name);
          break;
        }

        if (!gp_archive_extract_member(state.archive, obj_name)) {
          gp_error("Can't write this file: \"%s\"", obj_name);
          exit(1);
        }
      }
      break;
    }

    case AR_LIST:
      gp_archive_list_members(state.archive);
      break;

    case AR_SYMBOLS: {
      if (gp_archive_have_index(state.archive) == 0) {
        gp_error("This archive has no symbol index.");
      }
      else {
        gp_archive_read_index(symbol_index, state.archive);
        gp_archive_print_table(symbol_index);
      }
      break;
    }
    case AR_NULL:
    default:
      assert(0);
  }

  /* If the archive is being modified remove the old symbol index. */
  if (update_archive) {
    state.archive = gp_archive_remove_index(state.archive);
  }

  /* check for duplicate symbols */
  gp_archive_make_index(state.archive, definition_tbl);

  /* add the symbol index to the archive */
  if (update_archive && (!no_index)) {
    state.archive = gp_archive_add_index(definition_tbl, state.archive);
  }

  /* write the pnew or modified archive */
  if (update_archive && !gp_num.errors) {
    if (!gp_archive_write(state.archive, state.filename)) {
      gp_error("Can't write this pnew archive file: \"%s\"", state.filename);
      exit(1);
    }
  }

  return gp_num.errors ? EXIT_FAILURE : EXIT_SUCCESS;
}
Detected encoding: UTF-80