diff --git a/.gitignore b/.gitignore index 89ceba1..61abbfb 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,6 @@ /obj /man /p7* +/mcsfile .*.swp diff --git a/Makefile b/Makefile index 3c59e8b..1a0c727 100755 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ include Makefile.vars Makefile.msg # General targets # #******************************************************************************# # Make it all -all: all-bins $(if $(INSTALL_MANPAGES),all-doc) +all: all-bins # Mostly clean mostlyclean: mostlyclean-bins @@ -31,10 +31,10 @@ mrproper: clean re: clean all # Install it all -install: install-bins $(if $(INSTALL_MANPAGES),install-doc) +install: install-bins # Uninstall it all -uninstall: uninstall-bins uninstall-doc +uninstall: uninstall-bins # Reinstall it all reinstall: uninstall install @@ -149,7 +149,7 @@ $(eval $(call make-binaryobj-rule,$(bin),$(obj))))) define make-binary-rules $1$(if $(FOR_WINDOWS),.exe): $(SRC_$1:%=$(OBJDIR)/$1/%.o) | $(OBJDIR)/$1 $(call bcmd,ld,$$@,$(LD) -o $$@ $$^ $(LDFLAGS_$1)) - all-$1: $(CHECKCFG) $1$(if $(FOR_WINDOWS),.exe) + all-$1: $(CHECKCFG) $1$(if $(FOR_WINDOWS),.exe) all-doc-$1 clean-$1: $(call rmsg,Removing $1 and its objects directory.) @@ -176,10 +176,14 @@ $(eval $(call make-binary-rules,$(bin)))) # Install a binary define make-installbinary-rule - install-$1: $(CHECKCFG) all-$1 + install-$1: $(CHECKCFG) all-$1 $(if $(INSTALL_MANPAGES),install-doc-$1) $(call imsg,Installing $1$(if $(FOR_WINDOWS),.exe).) $(call qcmd,$(INSTALL) -m 755 -d "$(IBINDIR)") $(call qcmd,$(INSTALL) -m 755 -t "$(IBINDIR)" $1$(if $(FOR_WINDOWS),.exe)) + + uninstall-$1: $(CHECKCFG) uninstall-doc-$1 + $(call rmsg,Uninstalling $1) + $(call qcmd,$(RM) "$(IBINDIR)/$1"{,.exe}) endef $(foreach bin,$(BINARIES),\ $(eval $(call make-installbinary-rule,$(bin)))) @@ -188,62 +192,50 @@ $(eval $(call make-installbinary-rule,$(bin)))) install-bins: $(DEFAULT_BINARIES:%=install-%) # Uninstall binaries - uninstall-bins: $(CHECKCFG) - $(call rmsg,Uninstalling binaries.) - $(call qcmd,$(RM) $(patsubst %,"$(IBINDIR)/%",\ - $(BINARIES) $(BINARIES:%=%.exe))) + uninstall-bins: $(BINARIES:%=uninstall-%) .PHONY: all-bins mostlyclean-bins mclean-bins clean-bins re-bins -.PHONY: $(foreach b,$(BINARIES),all-$(b) clean-$(b) re-$(b) install-$(b)) .PHONY: install-bins uninstall-bins +.PHONY: $(foreach b,$(BINARIES),all-$(b) clean-$(b) re-$(b) \ + install-$(b) uninstall-$(b)) #******************************************************************************# # Documentation-related # #******************************************************************************# -# Make all manpages - all-doc: $(foreach s,$(MAN_SECTIONS), $(MAN_$(s):%=$(MANDIR)/man$(s)/%.$(s))) - # Make manpages directories - $(MAN_SECTIONS:%=$(MANDIR)/man%): + $(MANDIR)/man1: $(call bcmd,mkdir,$@,$(MD) $@) # Make-A-Manpage define make-manpage-rule - $(MANDIR)/man$1/%.$1: $(DOCDIR)/%.$1.txt | $(MANDIR)/man$1 + $(MANDIR)/man1/$1.%: $(DOCDIR)/$1.1.txt | $(MANDIR)/man1 $(call bcmd,a2x,$$<,$(A2X) -f manpage -D $$| $$< 2>/dev/null) + + all-doc-$1: $(MANDIR)/man1/$1.1 endef -$(foreach section, $(MAN_SECTIONS), \ -$(eval $(call make-manpage-rule,$(section)))) +$(foreach bin,$(BINARIES),\ +$(eval $(call make-manpage-rule,$(bin)))) # Remove all manpages clean-doc: $(call rmsg,Removing manpages directory.) $(call qcmd,$(RM) -r $(MANDIR)) -# Remake all manpages - re-doc: clean-doc all-doc +# Install a manpage. +define make-install-manpage-rule + install-doc-$1: $(MANDIR)/man1/$1.1 + $(call imsg,Installing $1 manpage) + $(call qcmd,$(INSTALL) -m 755 -d "$(IMANDIR)/man1") + $(call qcmd,$(INSTALL) -m 644 -t "$(IMANDIR)/man1" \ + $(MANDIR)/man1/$1.1) + $(call qcmd,$(GZIP) "$(IMANDIR)/man1/$1.1") -# Install a manpage section. -define make-installmansection-rule - install-doc-$1: $(MAN_$1:%=$(MANDIR)/man$1/%.$1) - $(call imsg,Installing manpages section $1.) - $(call qcmd,$(INSTALL) -m 755 -d "$(IMANDIR)/man$1") - $(call qcmd,$(INSTALL) -m 644 -t "$(IMANDIR)/man$1" \ - $(MAN_$1:%=$(MANDIR)/man$1/%.$1)) - $(call qcmd,$(GZIP) $(MAN_$1:%="$(IMANDIR)/man$1/%.$1")) + uninstall-doc-$1: + $(call rmsg,Removing $1 manpage) + $(call qcmd,$(RM) "$(IMANDIR)/man1/$1.1*") endef -$(foreach section, $(MAN_SECTIONS), \ -$(eval $(call make-installmansection-rule,$(section)))) +$(foreach bin,$(BINARIES), \ +$(eval $(call make-install-manpage-rule,$(bin)))) -# Install manpages - install-doc: $(CHECKCFG) $(if $(INSTALL_MANPAGES),\ - $(MAN_SECTIONS:%=install-doc-%)) - -# Uninstall manpages - uninstall-doc: $(CHECKCFG) - $(call rmsg,Removing manpages.) - $(call qcmd,$(RM) $(foreach s,$(MAN_SECTIONS),\ - $(patsubst %,"$(IMANDIR)"/man$(s)/%.$(s)*,$(MAN_$(s))))) - -.PHONY: all-doc clean-doc re-doc install-doc uninstall-doc -.PHONY: $(MAN_SECTIONS:%=install-doc-%) +.PHONY: $(foreach bin,$(BINARIES),all-doc-$(bin)) clean-doc +.PHONY: $(foreach bin,$(BINARIES),install-doc-$(bin) uninstall-doc-$(bin)) # End of file. diff --git a/Makefile.vars b/Makefile.vars index 2fd1953..504ca3b 100755 --- a/Makefile.vars +++ b/Makefile.vars @@ -98,12 +98,19 @@ endif # Look for binaries BINARIES := $(notdir $(shell find $(SRCDIR) -mindepth 1 -maxdepth 1 \ -type d | sort)) - DEFAULT_BINARIES := $(filter-out p7os,$(BINARIES)) # Get their libs define get-binary-libs - LIBS_$1 := libp7 $(shell make -f $(SRCDIR)/$1/vars.mk libs 2>/dev/null) + LIBS_$1 := $(shell make -f $(SRCDIR)/$1/vars.mk libs 2>/dev/null) + DISABLE_$1 := $(shell make -f $(SRCDIR)/$1/vars.mk disable 2>/dev/null \ + && echo y) endef +$(foreach bin,$(BINARIES), \ +$(eval $(call get-binary-libs,$(bin)))) + +# Get the default binaries + DEFAULT_BINARIES := $(foreach bin,$(BINARIES), \ + $(if $(DISABLE_$(bin)),,$(bin))) # Look for their sources define get-binary-sources @@ -112,14 +119,12 @@ define get-binary-sources \( -name "*.c" -or -name "*.exe" \) \ -printf "%P\n" | sort)) -# get the flags +# - get the flags CFLAGS_$1 := $(CFLAGS) $(shell $(PKGCONFIG) $(LIBS_$1) --cflags 2>/dev/null) \ -D BIN="$1$(if $(FOR_WINDOWS),.exe)" LDFLAGS_$1 := $(LDFLAGS) $(shell $(PKGCONFIG) $(LIBS_$1) --libs 2>/dev/null) endef $(foreach bin,$(BINARIES), \ -$(eval $(call get-binary-libs,$(bin)))) -$(foreach bin,$(BINARIES), \ $(eval $(call get-binary-sources,$(bin)))) #******************************************************************************# diff --git a/README.md b/README.md index e9ae1e8..9431918 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,12 @@ # p7utils - Shell utilities for libp7 ## Introduction **p7utils** is a set of command-line utilities that allow you to interact with -your calculator. `p7` will interact with the storage memories, `p7screen` will -display the result of the screen streaming and `p7os` will play with the -calculator's OS (backup, flash). +your CASIO calculators/files: + +* `p7` will interact with the storage memories; +* `p7screen` will display the result of the screen streaming; +* `p7os` will allow you to interact with the calculator's OS (backup, flash); +* `mcsfile` will display the content of a **g1m** file. ## Prerequisites ### Making-only dependencies @@ -17,13 +20,27 @@ calculator's OS (backup, flash). ### Making and runtime dependencies | Name | Version | | -------------------------------------------------- | --------- | -| [libp7](https://forge.touhey.fr/casio/lib/libp7/) | >= 3.0 | +| [libp7](https://p7.planet-casio.com/en.html) | >= 3.0 | +| [libg1m](https://github.com/cakeisalie5/libg1m) | >= 0.1 | | [libsdl](https://libsdl.org/) | == 1.2.15 | +Notice that dependencies varies if you only want to build some +executables: only `p7screen` will require the SDL, and `mcsfile` +is the only one to require `libg1m`. + +You should check `src//vars.mk` to see what the dependencies of +the particular executable you want (if you only want one) are (see +the `libs` target). + ## Building Just `./configure` then `make`. To install, use `make install`. Make the manpages with `make all-doc` and install them with `make install-doc`. Other useful targets : -- `clean`, `fclean`, `clean-doc`: remove built files ; -- `re`, `re-doc`: regenerate binary and/or manpages. +- `all-`: build only a given executable (and its doc); +- `install-`: install only a given executable (and its doc, if + `--noinstall-manpages` is not passed to the configure script); +- `uninstall-`: uninstall only a given executable (and its doc); +- `clean`, `clean-`, `clean-doc`: remove built files; +- `mrproper`: remove all built files, and the configuration; +- `re`: remove all built files, and build all the default executables and docs. diff --git a/doc/mcsfile.1.txt b/doc/mcsfile.1.txt new file mode 100644 index 0000000..8c2f458 --- /dev/null +++ b/doc/mcsfile.1.txt @@ -0,0 +1,36 @@ +MCSFILE(1) +========== +Thomas "Cakeisalie5" Touhey +:Email: thomas@touhey.fr +:man source: g1mutils +:man manual: g1mutils manual + +NAME +---- +mcsfile - list subfiles in a g*m/g*r casio file + +SYNOPSIS +-------- +[source,bash] +---- +mcsfile [--help] [--version] +---- + +DESCRIPTION +----------- +mcsfile is a simple utility that looks like *file*(1), excepts it lists subfiles +in a CASIO MCS archive file (g*m/g*r). + +OPTIONS +------- +Options start with one or two dashes. Some of the options require an additional +value next to them. + +*-h, --help*:: + Display command/subcommand help page and quit. +*-v, --version*:: + Display version and quit. + +SEE ALSO +-------- +*libg1m*(3) diff --git a/src/mcsfile/args.c b/src/mcsfile/args.c new file mode 100644 index 0000000..6242cae --- /dev/null +++ b/src/mcsfile/args.c @@ -0,0 +1,95 @@ +/* ************************************************************************** */ +/* _____ _ */ +/* args.c |_ _|__ _ _| |__ ___ _ _ */ +/* | Project: mcsfile | |/ _ \| | | | '_ \ / _ \ | | | */ +/* | | (_) | |_| | | | | __/ |_| | */ +/* By: thomas |_|\___/ \__,_|_| |_|\___|\__, |.fr */ +/* Last updated: 2016/12/18 01:20:51 |___/ */ +/* */ +/* ************************************************************************** */ +#include "main.h" +#include +#define Q(x) #x +#define QUOTE(x) Q(x) + +/* ************************************************************************** */ +/* Help and version messages */ +/* ************************************************************************** */ +/* Help message */ +static const char *help_message = +"Usage: mcsfile [--version|-v] [--help|-h]\n" +" \n" +"\n" +"Reads mcs files in a g1m file.\n" +"\n" +"Options are:\n" +" -h, --help Display this help message.\n" +" -v, --version Display the version message.\n" +"\n" +"Report bugs to " QUOTE(AUTHOR) "."; + +/* Version message */ +static const char *version_message = +"mcsfile - from g1mutils v" QUOTE(VERSION) + " (licensed under " QUOTE(LICENSE) ")\n" +"Made by " QUOTE(AUTHOR) ".\n" +"\n" +"This is free software; see the source for copying conditions.\n" +"There is NO warranty; not even for MERCHANTABILITY or\n" +"FITNESS FOR A PARTICULAR PURPOSE."; + +/* ************************************************************************** */ +/* Main function */ +/* ************************************************************************** */ +/** + * parse_args: + * Args parsing main function. + * + * @arg ac the arguments count. + * @arg av the arguments values. + * @arg files pointer to the file paths tab to allocate. + * @return if execution should stop. + */ + +int parse_args(int ac, char **av, const char **path) +{ + /* getopt elements */ + const char *optstring = "hv"; + const struct option longopts[] = { + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'v'}, + {} + }; + + /* get options */ + int c; opterr = 0; + int help = 0, version = 0; + while ((c = getopt_long(ac, av, optstring, longopts, NULL)) != -1) + switch (c) { + case 'h': help = 1; break; + case 'v': version = 1; break; + default: switch (optopt) { + default: + fprintf(stderr, "-%c: unknown option.\n", optopt); + } + return (1); + } + + /* check parameters */ + int pc = ac - optind; + char **pv = &av[optind]; + if (pc != 1) help = 1; + else *path = *pv; + + /* display version or help message */ + if (version) { + puts(version_message); + return (1); + } else if (help) { + puts(help_message); + return (1); + } + + /* no error */ + return (0); +} diff --git a/src/mcsfile/main.c b/src/mcsfile/main.c new file mode 100644 index 0000000..6a1af66 --- /dev/null +++ b/src/mcsfile/main.c @@ -0,0 +1,53 @@ +/* ************************************************************************** */ +/* _____ _ */ +/* main.c |_ _|__ _ _| |__ ___ _ _ */ +/* | Project: mcsfile | |/ _ \| | | | '_ \ / _ \ | | | */ +/* | | (_) | |_| | | | | __/ |_| | */ +/* By: thomas |_|\___/ \__,_|_| |_|\___|\__, |.fr */ +/* Last updated: 2016/12/18 01:19:25 |___/ */ +/* */ +/* ************************************************************************** */ +#include "main.h" +#include +#include + +/** + * main: + * Entry point of the program. + * + * @arg ac the arguments count. + * @arg av the arguments values. + * @return the status code (0 if ok). + */ + +int main(int ac, char **av) +{ + /* parse arguments */ + const char *path; + if (parse_args(ac, av, &path)) + return (0); + + /* parse */ + g1m_t *handle; int err; + if ((err = g1m_open(&handle, path, g1m_type_mcs))) switch (err) { + case g1m_error_wrong_type: + fprintf(stderr, "An MCS file was expected (g1m/g1r, g1m/g2r, g3m)\n"); + return (0); + case g1m_error_nostream: + fprintf(stderr, "Could not open file: %s\n", strerror(errno)); + return (0); + case g1m_error_magic: + fprintf(stderr, "Magic error: file might be corrupted\n"); + return (0); + case g1m_error_eof: + fprintf(stderr, "Unexpected end of file\n"); + return (0); + } + + /* read */ + put_files(handle); + + /* no error */ + g1m_free(handle); + return (0); +} diff --git a/src/mcsfile/main.h b/src/mcsfile/main.h new file mode 100644 index 0000000..6f43799 --- /dev/null +++ b/src/mcsfile/main.h @@ -0,0 +1,17 @@ +/* ************************************************************************** */ +/* _____ _ */ +/* main.h |_ _|__ _ _| |__ ___ _ _ */ +/* | Project: mcsfile | |/ _ \| | | | '_ \ / _ \ | | | */ +/* | | (_) | |_| | | | | __/ |_| | */ +/* By: thomas |_|\___/ \__,_|_| |_|\___|\__, |.fr */ +/* Last updated: 2016/12/18 01:33:41 |___/ */ +/* */ +/* ************************************************************************** */ +#ifndef MAIN_H +# define MAIN_H +# include + +int parse_args(int ac, char **av, const char **paths); +void put_files(g1m_t *handle); + +#endif /* MAIN_H */ diff --git a/src/mcsfile/print.c b/src/mcsfile/print.c new file mode 100644 index 0000000..59f1476 --- /dev/null +++ b/src/mcsfile/print.c @@ -0,0 +1,130 @@ +/* ************************************************************************** */ +/* _____ _ */ +/* line.c |_ _|__ _ _| |__ ___ _ _ */ +/* | Project: mcsfile | |/ _ \| | | | '_ \ / _ \ | | | */ +/* | | (_) | |_| | | | | __/ |_| | */ +/* By: thomas |_|\___/ \__,_|_| |_|\___|\__, |.fr */ +/* Last updated: 2016/12/18 01:43:52 |___/ */ +/* */ +/* ************************************************************************** */ +#include "main.h" +#include +#include + +/* ************************************************************************** */ +/* Sort */ +/* ************************************************************************** */ +/** + * compare: + * Compare two MCS files. + * + * @arg + */ + +static int compare(const void *vpfile1, const void *vpfile2) +{ + g1m_mcsfile_t *file1 = *((g1m_mcsfile_t**)vpfile1); + g1m_mcsfile_t *file2 = *((g1m_mcsfile_t**)vpfile2); + + /* compare dirnames */ + int dirdiff = strcmp(file1->_dirname, file2->_dirname); + if (dirdiff) return (dirdiff > 0); + + /* compare names */ + return (strcmp(file1->name, file2->name) > 0); +} + +/** + * sort_files: + * Sort MCS files. + * + * @arg handle the handle. + */ + +static void sort_files(g1m_t *handle) +{ + qsort(handle->files, (size_t)handle->count, + sizeof(g1m_mcsfile_t*), &compare); +} + +/* ************************************************************************** */ +/* Display */ +/* ************************************************************************** */ +/** + * put_description: + * Put the description (with the newline). + * + * @arg file the MCS file. + */ + +static void put_description(g1m_mcsfile_t *file) +{ + if (!file->type) + printf("unknown content (%zu octets)\n", file->content_size); + else if (file->type & g1m_mcstype_program) { + printf("program ("); + if (g1m_has_password(file)) printf("password: '%s')\n", file->password); + else printf("no password)\n"); + } else if (file->type & g1m_mcstype_list) { + printf("list %d (", g1m_get_id_minor(file->id)); + if (g1m_get_id_major(file->id)) + printf("from listfile %d, ", g1m_get_id_major(file->id)); + printf("%d columns)\n", file->columns); + } else if (file->type & g1m_mcstype_mat) + printf("matrix %c (%d columns, %d rows)\n", + 'A' + file->id - 1, file->columns, file->rows); + else if (file->type & g1m_mcstype_vct) + printf("vector %c (%d rows)\n", + 'A' + file->id - 1, file->rows); + else if (file->type & g1m_mcstype_pict) + printf("picture %d (double %dx%d image)\n", + file->id, file->width, file->height); + else if (file->type & g1m_mcstype_capt) + printf("capture %d (%dx%d)\n", + file->id, file->width, file->height); + else if (file->type & g1m_mcstype_spreadsheet) + printf("spreadsheet (%d columns, %d rows)\n", + file->columns, file->rows); + else if (file->type & g1m_mcstype_string) + printf("string %d\n", file->id); + else if (file->type & g1m_mcstype_setup) + printf("setup\n"); + else if (file->type & g1m_mcstype_alphamem) + printf("alpha memory\n"); + else + printf("unmanaged format\n"); +} + +/** + * put_files: + * Put the files. + * + * @arg handle the handle. + */ + +void put_files(g1m_t *handle) +{ + if (!handle->count) { + fprintf(stderr, "Provided file was empty.\n"); + return ; + } + + sort_files(handle); + /* get first part maximum size */ + int max_size = 0; + for (int i = 0; i < handle->count; i++) { + g1m_mcsfile_t *file = handle->files[i]; + int sz = strlen(file->name) + strlen(file->_dirname); + if (sz > max_size) max_size = sz; + } + max_size += 2; + + /* put the lines */ + char buf[max_size + 1]; + for (int i = 0; i < handle->count; i++) if (handle->files[i]) { + g1m_mcsfile_t *file = handle->files[i]; + sprintf(buf, "%s/%s:", file->_dirname, file->name); + printf("%-*s ", max_size, buf); + put_description(handle->files[i]); + } +} diff --git a/src/mcsfile/vars.mk b/src/mcsfile/vars.mk new file mode 100755 index 0000000..b9df833 --- /dev/null +++ b/src/mcsfile/vars.mk @@ -0,0 +1,4 @@ +#!/usr/bin/make -f +disable: +libs: + @echo libg1m diff --git a/src/p7/vars.mk b/src/p7/vars.mk new file mode 100755 index 0000000..c22ee31 --- /dev/null +++ b/src/p7/vars.mk @@ -0,0 +1,3 @@ +#!/usr/bin/make -f +libs: + @echo libp7 diff --git a/src/p7os/vars.mk b/src/p7os/vars.mk new file mode 100755 index 0000000..3cc5551 --- /dev/null +++ b/src/p7os/vars.mk @@ -0,0 +1,4 @@ +#!/usr/bin/make -f +disable: +libs: + @echo libp7 diff --git a/src/p7screen/vars.mk b/src/p7screen/vars.mk index 335970b..c09f426 100755 --- a/src/p7screen/vars.mk +++ b/src/p7screen/vars.mk @@ -1,3 +1,3 @@ #!/usr/bin/make -f libs: - @echo sdl + @echo libp7 sdl