/* 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-8 | 0
|