diff options
| author | Timo Savinen <tjsa@iki.fi> | 2005-09-22 15:39:00 +0000 |
|---|---|---|
| committer | Hadrien Dorio <hadrien.dorio@gmail.com> | 2017-12-16 00:23:56 +0100 |
| commit | 35d0e8a808dd1382d5236d1f6f8bfe62b2ebefee (patch) | |
| tree | e84242391375fab6b6e15963b4b1e0be5296b0bd /src | |
| download | binary-block-editor-35d0e8a808dd1382d5236d1f6f8bfe62b2ebefee.tar.gz binary-block-editor-35d0e8a808dd1382d5236d1f6f8bfe62b2ebefee.zip | |
0.1.0
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.am | 6 | ||||
| -rw-r--r-- | src/Makefile.in | 408 | ||||
| -rw-r--r-- | src/bbe.c | 597 | ||||
| -rw-r--r-- | src/bbe.h | 211 | ||||
| -rw-r--r-- | src/buffer.c | 490 | ||||
| -rw-r--r-- | src/execute.c | 324 | ||||
| -rw-r--r-- | src/xmalloc.c | 35 |
7 files changed, 2071 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..be798ed --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,6 @@ +bin_PROGRAMS = bbe + +AM_CFLAGS = -I.. + +bbe_SOURCES = bbe.c xmalloc.c buffer.c execute.c +noinst_HEADERS = bbe.h diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 0000000..7afc830 --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,408 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = bbe$(EXEEXT) +subdir = src +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) +am_bbe_OBJECTS = bbe.$(OBJEXT) xmalloc.$(OBJEXT) buffer.$(OBJEXT) \ + execute.$(OBJEXT) +bbe_OBJECTS = $(am_bbe_OBJECTS) +bbe_LDADD = $(LDADD) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/config/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(bbe_SOURCES) +DIST_SOURCES = $(bbe_SOURCES) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +ISODATE = @ISODATE@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +AM_CFLAGS = -I.. +bbe_SOURCES = bbe.c xmalloc.c buffer.c execute.c +noinst_HEADERS = bbe.h +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +bbe$(EXEEXT): $(bbe_OBJECTS) $(bbe_DEPENDENCIES) + @rm -f bbe$(EXEEXT) + $(LINK) $(bbe_LDFLAGS) $(bbe_OBJECTS) $(bbe_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bbe.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/execute.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xmalloc.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-binPROGRAMS + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-exec install-exec-am \ + install-info install-info-am install-man install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-binPROGRAMS uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/bbe.c b/src/bbe.c new file mode 100644 index 0000000..7c1ed00 --- /dev/null +++ b/src/bbe.c @@ -0,0 +1,597 @@ +/* + * bbe - Binary block editor + * + * Copyright (C) 2005 Timo Savinen + * This file is part of bbe. + * + * bbe 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. + * + * bbe 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 bbe; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +/* $Id: bbe.c,v 1.23 2005/09/14 15:48:52 timo Exp $ */ + +#include "bbe.h" +#ifdef HAVE_GETOPT_H +#include <getopt.h> +#endif + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> + +#ifdef HAVE_STRING_H +#include <string.h> +#endif + +#ifdef PACKAGE +static char *program = PACKAGE; +#else +static char *program = "bbe"; +#endif + +#ifdef VERSION +static char *version = VERSION; +#else +static char *version = "0.1.0"; +#endif + +#ifdef PACKAGE_BUGREPORT +static char *email_address = PACKAGE_BUGREPORT; +#else +static char *email_address = "tjsa@iki.fi"; +#endif + + + +struct block block; +struct command *commands = NULL; +char *panic_info = NULL; + +char *convert_strings[] = { + "BCDASC", + "ASCBCD", + "", +}; + +static char short_opts[] = "b:e:f:o:?V"; + +static struct option long_opts[] = { + {"block",1,NULL,'b'}, + {"expression",1,NULL,'e'}, + {"file",1,NULL,'f'}, + {"output",1,NULL,'o'}, + {"help",0,NULL,'?'}, + {"version",0,NULL,'V'}, + {NULL,0,NULL,0} +}; + +void +panic(char *msg,char *info,char *syserror) +{ + if(panic_info != NULL) fprintf(stderr,"%s: %s",program,panic_info); + + if (info == NULL && syserror == NULL) + { + fprintf(stderr,"%s: %s\n",program,msg); + } else if(info != NULL && syserror == NULL) + { + fprintf(stderr,"%s: %s: %s\n",program,msg,info); + } else if(info != NULL && syserror != NULL) + { + fprintf(stderr,"%s: %s: %s; %s\n",program,msg,info,syserror); + } else if(info == NULL && syserror != NULL) + { + fprintf(stderr,"%s: %s; %s\n",program,msg,syserror); + } + exit(EXIT_FAILURE); +} + +/* parse a long int, can start with n (dec), x (hex), 0 (oct) */ +off_t +parse_long(char *long_int) +{ + long long int l; + char *scan = long_int; + char type='d'; // others are x and o + + + if(*scan == '0') + { + type = 'o'; + scan++; + if(*scan == 'x' || *scan == 'X') { + type = 'x'; + scan++; + } + } + + while(*scan != 0) + { + switch(type) + { + case 'd': + if(!isdigit(*scan)) panic("Error in number",long_int,NULL); + break; + case 'o': + if(!isdigit(*scan) || *scan > '8') panic("Error in number",long_int,NULL); + break; + case 'x': + if(!isxdigit(*scan)) panic("Error in number",long_int,NULL); + break; + } + scan++; + } + + if (sscanf(long_int,"%lli",&l) != 1) + { + panic("Error in number",long_int,NULL); + } + return (off_t) l; +} + +/* parse a string, string can contain \n, \xn, \0n and \\ + escape codes. memory will be allocated */ +unsigned char * +parse_string(char *string,off_t *length) +{ + char *p; + int j,k,i = 0; + int min_len; + unsigned char buf[INPUT_BUFFER_LOW+1]; + char num[5]; + unsigned char *ret; + + p = string; + + while(*p != 0) + { + if(*p == '\\') + { + p++; + if(*p == '\\') + { + num[i] = *p++; + } else + { + j = 0; + switch(*p) + { + case 'x': + case 'X': + num[j++] = '0'; + num[j++] = *p++; + while(isxdigit(*p) && j < 4) num[j++] = *p++; + min_len=3; + break; + case '0': + while(isdigit(*p) && *p <= '8' && j < 4) num[j++] = *p++; + min_len=1; + break; + default: + while(isdigit(*p) && j < 3) num[j++] = *p++; + min_len=1; + break; + } + num[j] = 0; + if (sscanf(num,"%i",&k) != 1 || j < min_len) + { + panic("Syntax error in escape code",string,NULL); + } + if (k < 0 || k > 255) + { + panic("Escape code not in range (0-255)",string,NULL); + } + buf[i] = (unsigned char) k; + } + } else + { + buf[i] = (unsigned char) *p++; + } + if(i > INPUT_BUFFER_LOW) + { + panic("string too long",string,NULL); + } + i++; + } + if(i) + { + ret = (unsigned char *) xmalloc(i); + memcpy(ret,buf,i); + } else + { + ret = NULL; + } + *length = i; + return ret; +} + + +/* parse a block definition and save it to block */ +static void +parse_block(char *bs) +{ + char slash_char; + char *p = bs; + int i = 0; + char *buf; + + if(strlen(bs) > (2*4*INPUT_BUFFER_LOW)) + { + panic("Block definition too long",NULL,NULL); + } + + buf=xmalloc(2*4*INPUT_BUFFER_LOW); + + if (*p == ':') + { + block.start.S.length = 0; + block.type |= BLOCK_START_S; + } else + { + if(*p == 'x' || *p == 'X' || isdigit(*p)) + { + switch(*p) + { + case 'x': + case 'X': + buf[i++] = '0'; + buf[i++] = *p++; + while(isxdigit(*p)) buf[i++] = *p++; + break; + case '0': + while(isdigit(*p) && *p <= '8') buf[i++] = *p++; + break; + default: + while(isdigit(*p)) buf[i++] = *p++; + break; + } + + buf[i] = 0; + block.start.N = parse_long(buf); + block.type |= BLOCK_START_M; + } else // string start + { + slash_char = *p; + p++; + while(*p != slash_char && *p != 0) buf[i++] = *p++; + if (*p == slash_char) p++; + buf[i] = 0; + block.start.S.string = parse_string(buf,&block.start.S.length); + block.type |= BLOCK_START_S; + } + } + + if (*p != ':') + { + panic("Error in block definition",bs,NULL); + } + + p++; + + if (*p == 0) + { + block.stop.S.length = 0; + block.type |= BLOCK_STOP_S; + } else + { + i = 0; + if (*p == 'x' || *p == 'X' || isxdigit(*p)) + { + switch(*p) + { + case 'x': + case 'X': + buf[i++] = '0'; + buf[i++] = *p++; + while(isxdigit(*p)) buf[i++] = *p++; + break; + case '0': + while(isdigit(*p) && *p <= '8') buf[i++] = *p++; + break; + default: + while(isdigit(*p)) buf[i++] = *p++; + break; + } + buf[i] = 0; + block.stop.M = parse_long(buf); + if(block.stop.M == 0) panic("Block length must be greater than zero",NULL,NULL); + block.type |= BLOCK_STOP_M; + } else + { + if(*p == '$') + { + block.stop.S.length = 0; + p++; + } else + { + slash_char = *p; + p++; + while(*p != slash_char && *p != 0) buf[i++] = *p++; + if (*p == slash_char) + { + p++; + } else + { + panic("syntax error in block definition",bs,NULL); + } + buf[i] = 0; + block.stop.S.string = parse_string(buf,&block.stop.S.length); + block.type |= BLOCK_STOP_S; + } + } + } + if (*p != 0) + { + panic("syntax error in block definition",bs,NULL); + } + free(buf); +} + +/* parse one command, commands are in list pointed by commands */ +void +parse_command(char *command_string) +{ + struct command *curr,*new; + char *c,*p,*buf; + char *token[10]; + char slash_char; + int i,j; + + + p = command_string; + while(isspace(*p)) p++; // remove leading spaces + c = strdup(p); + if(c == NULL) panic("Out of memory",NULL,NULL); + + i = 0; + token[i] = strtok(c," \t\n"); + i++; + while(token[i - 1] != NULL && i < 10) token[i++] = strtok(NULL," \t\n"); + i--; + + if (token[0] == NULL ) return; // empty line + if (*token[0] == '#') return; // comment + + curr = commands; + if (curr != NULL) + { + while(curr->next != NULL) curr = curr->next; + } + new = xmalloc(sizeof(struct command)); + new->next = NULL; + if(commands == NULL) + { + commands = new; + } else + { + curr->next = new; + } + + + new->letter = token[0][0]; + switch(new->letter) + { + case 'D': + if(i < 1 || i > 2 || strlen(token[0]) > 1) panic("Error in command",command_string,NULL); + if(i == 2) + { + new->offset = parse_long(token[1]); + if(new->offset < 1) panic("n for D-command must be at least 1",NULL,NULL); + } else + { + new->offset = 0; + } + break; + case 'A': + case 'I': + if(i != 2 || strlen(token[0]) > 1) panic("Error in command",command_string,NULL); + new->s1 = parse_string(token[1],&new->s1_len); + break; + case 'w': + if(i != 2 || strlen(token[0]) > 1) panic("Error in command",command_string,NULL); + new->s1 = strdup(token[1]); + break; + case 'j': + case 'J': + if(i != 2 || strlen(token[0]) > 1) panic("Error in command",command_string,NULL); + new->count = parse_long(token[1]); + break; + case 'l': + case 'L': + if(i != 2 || strlen(token[0]) > 1) panic("Error in command",command_string,NULL); + new->count = parse_long(token[1]); + break; + case 'r': + case 'i': + if(i != 3 || strlen(token[0]) > 1) panic("Error in command",command_string,NULL); + new->offset = parse_long(token[1]); + new->s1 = parse_string(token[2],&new->s1_len); + break; + case 'd': + if(i < 2 || i > 3 || strlen(token[0]) > 1) panic("Error in command",command_string,NULL); + new->offset = parse_long(token[1]); + new->count = 1; + if(i == 3) new->count = parse_long(token[2]); + break; + case 'c': + if(i != 3 || strlen(token[1]) != 3 || strlen(token[2]) != 3 || strlen(token[0]) > 1) panic("Error in command",command_string,NULL); + new->s1 = xmalloc(strlen(token[1]) + strlen(token[2]) + 2); + strcpy(new->s1,token[1]); + strcat(new->s1,token[2]); + j = 0; + while(new->s1[j] != 0) { + new->s1[j] = toupper(new->s1[j]); + j++; + } + j = 0; + while(*convert_strings[j] != 0 && strcmp(convert_strings[j],new->s1) != 0) j++; + if(*convert_strings[j] == 0) panic("Unknown conversion",command_string,NULL); + break; + case 's': + case 'y': + if(strlen(command_string) < 4) panic("Error in command",command_string,NULL); + + buf=xmalloc((4*INPUT_BUFFER_LOW) + 1); + + slash_char = command_string[1]; + p = command_string; + p += 2; + j = 0; + while(*p != 0 && *p != slash_char && j < 4*INPUT_BUFFER_LOW) buf[j++] = *p++; + if(*p != slash_char) panic("Error in command",command_string,NULL); + buf[j] = 0; + new->s1 = parse_string(buf,&new->s1_len); + if(new->s1_len > INPUT_BUFFER_LOW) panic("String in command too long",command_string,NULL); + if(new->s1_len == 0) panic("Error in command",command_string,NULL); + + p++; + + j = 0; + while(*p != 0 && *p != slash_char && j < 4*INPUT_BUFFER_LOW) buf[j++] = *p++; + buf[j] = 0; + if(*p != slash_char) panic("Error in command",command_string,NULL); + new->s2 = parse_string(buf,&new->s2_len); + if(new->s2_len > INPUT_BUFFER_LOW) panic("String in command too long",command_string,NULL); + + if(new->letter == 'y' && new->s1_len != new->s2_len) panic("Strings in y-command must have equal length",command_string,NULL); + free(buf); + break; + default: + panic("Unknown command",command_string,NULL); + break; + } + free(c); +} + +/* read commands from file */ +void +parse_command_file(char *file) +{ + FILE *fp; + char *line; + char info[1024]; + size_t line_len = 1024; + int line_no = 0; + + line = xmalloc(line_len); + + fp = fopen(file,"r"); + if (fp == NULL) panic("Error in opening file",file,strerror(errno)); + + while(getline(&line,&line_len,fp) != -1) + { + line_no++; + sprintf(info,"Error in file '%s' in line %d\n",file,line_no); + panic_info=info; + parse_command(line); + } + + free(line); + fclose(fp); + panic_info=NULL; +} + +void +help(FILE *stream) +{ + fprintf(stream,"Usage: %s [OPTION]...\n\n",program); + fprintf(stream,"-b, --block=BLOCK\n"); + fprintf(stream,"\t\tBlock definition.\n"); + fprintf(stream,"-e, --expression=COMMAND\n"); + fprintf(stream,"\t\tAdd command to the commands to be executed.\n"); + fprintf(stream,"-f, --file=script-file\n"); + fprintf(stream,"\t\tAdd commands from script-file to the commands to be executed.\n"); + fprintf(stream,"-o, --output=name\n"); + fprintf(stream,"\t\tWrite output to name instead of standard output.\n"); + fprintf(stream,"-?, --help\n"); + fprintf(stream,"\t\tDisplay this help and exit\n"); + fprintf(stream,"-V, --Version\n"); + fprintf(stream,"\t\tShow version and exit\n"); + fprintf(stream,"\nAll remaining arguments are names of input files;\n"); + fprintf(stream,"if no input files are specified, then the standard input is read.\n"); + fprintf(stream,"\nSend bug reports to %s\n",email_address); +} + +void +usage(int opt) +{ + printf("Unknown option '-%c'\n",(char) opt); + help(stderr); +} + +void +print_version() +{ + printf("%s version %s\n",program,version); + printf("Copyright (c) 2005 Timo Savinen\n\n"); + printf("This is free software; see the source for copying conditions.\n"); + printf("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"); +} + + +int +main (int argc, char **argv) +{ + int opt; + + block.type = 0; + while ((opt = getopt_long(argc,argv,short_opts,long_opts,NULL)) != -1) + { + switch(opt) + { + case 'b': + if(block.type) panic("Only one -b option allowed",NULL,NULL); + parse_block(optarg); + break; + case 'e': + parse_command(optarg); + break; + case 'f': + parse_command_file(optarg); + break; + case 'o': + set_output_file(optarg); + break; + case '?': + help(stdout); + exit(EXIT_SUCCESS); + break; + case 'V': + print_version(); + exit(EXIT_SUCCESS); + break; + default: + usage(opt); + exit(EXIT_FAILURE); + break; + } + } + if(!block.type) parse_block("0:$"); + if(out_stream.file == NULL) set_output_file(NULL); + + if(optind < argc) + { + while(optind < argc) set_input_file(argv[optind++]); + } else + { + set_input_file(NULL); + } + + init_buffer(); + init_commands(commands); + execute_program(commands); + close_commands(commands); + exit(EXIT_SUCCESS); +} diff --git a/src/bbe.h b/src/bbe.h new file mode 100644 index 0000000..93b3e0c --- /dev/null +++ b/src/bbe.h @@ -0,0 +1,211 @@ +/* + * bbe - Binary block editor + * + * Copyright (C) 2005 Timo Savinen + * This file is part of bbe. + * + * bbe 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. + * + * bbe 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 bbe; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +/* $Id: bbe.h,v 1.15 2005/09/14 15:48:52 timo Exp $ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_FEATURES_H +#include <features.h> +#endif + +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <stdio.h> + +#ifndef HAVE_OFF_T +#define long int off_t +#endif + +/* Types */ + +/* Constants */ +/* exit values */ +#define EXIT_FAILURE 1 +#define EXIT_SUCCESS 0 + +/* Input buffer size */ +#define INPUT_BUFFER_LOW (16*1024) +#define INPUT_BUFFER_SIZE (16*INPUT_BUFFER_LOW) +#define INPUT_BUFFER_SAFE (INPUT_BUFFER_SIZE - INPUT_BUFFER_LOW) + +/* Output buffer size*/ +#define OUTPUT_BUFFER_LOW INPUT_BUFFER_LOW +#define OUTPUT_BUFFER_SIZE (16*OUTPUT_BUFFER_LOW) +#define OUTPUT_BUFFER_SAFE (OUTPUT_BUFFER_SIZE - OUTPUT_BUFFER_LOW) + +/* block types */ +#define BLOCK_START_M 1 +#define BLOCK_START_S 2 +#define BLOCK_STOP_M 4 +#define BLOCK_STOP_S 8 + +/* structs */ + +/* Block definition */ +struct block { + int type; + union + { + off_t N; + struct { + unsigned char *string; + off_t length; + } S; + } start; + union + { + off_t M; + struct { + unsigned char *string; + off_t length; + } S; + } stop; +}; + +/* Commands */ + +struct command { + char letter; // command letter (D,A,s,..) + off_t offset; // n for D,r,i and d commands + off_t count; // count for d command + unsigned char *s1; // string for A,I,r,i,s,w and y commands + off_t s1_len; + unsigned char *s2; // replace for s and dest for y + off_t s2_len; + int rpos; // replace position for s,r and y + FILE *fd; // stream for w command + struct command *next; +}; + +/* in/out files */ +struct io_file { + char *file; + int fd; + struct io_file *next; +}; + +/* input buffer */ +struct input_buffer { + unsigned char *buffer; // buffer to be malloced + unsigned char *read_pos; // current read position + unsigned char *low_pos; // low water mark + unsigned char *block_end; // end of current block (if in buffer) + unsigned char *stream_end; // end of stream (if in buffer) + off_t stream_offset; // stream offset (at the beginning of buffer) current offset: offset + (read_pos - buffer) + off_t block_offset; // block offset (start = 0) number of bytes read at position read_pos + off_t block_num; // number of current block, first = 1 +}; + +/* output buffer */ +struct output_buffer { + unsigned char *buffer; + unsigned char *write_pos; // current write psotion; + unsigned char *low_pos; // low water mark + unsigned char *cycle_start; // at this position started the last command cycle + // (written bytes n curren cycle are between cycle_start and write_pos + off_t block_offset; // block offset (start = 0) number of bytes written at position write_pos +}; + + + +/* function prototypes */ +extern void +panic(char *msg,char *info,char *syserror); + +extern void * +xmalloc (size_t size); + +extern void +set_output_file(char *file); + +extern void +set_input_file(char *file); + +extern void +init_buffer(); + +extern inline unsigned char +read_byte(); + +extern inline int +get_next_byte(); + +extern void +mark_block_end(); + +extern int +find_block(); + +extern inline int +last_byte(); + +extern void +write_buffer(unsigned char *buf,off_t length); + +extern inline void +put_byte(unsigned char byte); + +extern inline void +write_next_byte(); + +extern void +flush_buffer(); + +extern void +init_commands(struct command *c); + +extern void +close_commands(struct command *c); + +extern inline void +set_cycle_start(); + +extern void +close_output_stream(); + +extern void +write_w_command(unsigned char *buf,size_t length); + +extern void +execute_program(struct command *c); + +extern void +reverse_bytes(size_t count); +/* global variables */ +extern struct block block; +extern struct command *commands; +extern struct io_file out_stream; +extern struct input_buffer in_buffer; +extern struct output_buffer out_buffer; diff --git a/src/buffer.c b/src/buffer.c new file mode 100644 index 0000000..f9b45eb --- /dev/null +++ b/src/buffer.c @@ -0,0 +1,490 @@ +/* + * bbe - Binary block editor + * + * Copyright (C) 2005 Timo Savinen + * This file is part of bbe. + * + * bbe 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. + * + * bbe 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 bbe; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +/* $Id: buffer.c,v 1.19 2005/09/14 15:48:52 timo Exp $ */ + +#include "bbe.h" +#include <stdlib.h> +#include <error.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> + +/* output file */ +struct io_file out_stream; + +/* list of input files, points to current file */ +struct io_file *in_stream = NULL; + +/* input buffer */ +struct input_buffer in_buffer; + +/* output buffer */ +struct output_buffer out_buffer; + +/* open the output file */ +void +set_output_file(char *file) +{ + if (out_stream.file != NULL) panic("Only one output file can be defined",NULL,NULL); + + if(file == NULL) + { + out_stream.fd = STDOUT_FILENO; + out_stream.file = "stdout"; + } else + { + out_stream.fd = open(file,O_WRONLY | O_CREAT | O_TRUNC,S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); + if(out_stream.fd == -1) panic("Cannot open for writing",file,strerror(errno)); + out_stream.file = strdup(file); + if (out_stream.file == NULL) panic("Out of memory",NULL,NULL); + } +} + +/* write to output stream from arbitrary buffer */ +void +write_output_stream(unsigned char *buffer, ssize_t length) +{ + if(write(out_stream.fd,buffer,length) == -1) panic("Error writing to",out_stream.file,strerror(errno)); +} + + +/* open a input file and put it in input file list */ +void +set_input_file(char *file) +{ + struct io_file *new,*curr; + + new = xmalloc(sizeof(struct io_file)); + new->next = NULL; + + if(in_stream == NULL) + { + in_stream = new; + } else + { + curr = in_stream; + while(curr->next != NULL) + { + curr = curr->next; + } + curr->next = new; + } + + if(file == NULL) + { + new->fd = STDIN_FILENO; + new->file = "stdin"; + } else + { + new->fd = open(file,O_RDONLY); + if(new->fd == -1) panic("Cannot open file for reading",file,strerror(errno)); + new->file = strdup(file); + if (new->file == NULL) panic("Out of menory",NULL,NULL); + } +} + +/* initialize in and out buffers */ +void +init_buffer() +{ + in_buffer.buffer = xmalloc(INPUT_BUFFER_SIZE); + in_buffer.read_pos = NULL; + in_buffer.stream_end = NULL; + in_buffer.low_pos = in_buffer.buffer + INPUT_BUFFER_SAFE; + in_buffer.block_num = 0; + + out_buffer.buffer = xmalloc(OUTPUT_BUFFER_SIZE); + out_buffer.write_pos = out_buffer.buffer; + out_buffer.low_pos = out_buffer.buffer + OUTPUT_BUFFER_SAFE; +} + +ssize_t +read_input_stream() +{ + ssize_t read_count,last_read,to_be_read,to_be_saved; + unsigned char *buffer_write_pos; + + if(in_buffer.stream_end != NULL) return (ssize_t) 0; // can't read more + + if(in_buffer.read_pos == NULL) // first read, so just fill buffer + { + to_be_read = INPUT_BUFFER_SIZE; + buffer_write_pos = in_buffer.buffer; + in_buffer.stream_offset = (off_t) 0; + } else //we have allready read something + { + to_be_read = in_buffer.read_pos - in_buffer.buffer; + to_be_saved = (ssize_t) INPUT_BUFFER_SIZE - to_be_read; + if (to_be_saved > INPUT_BUFFER_SIZE / 2) panic("buffer error: reading to half full buffer",NULL,NULL); + memcpy(in_buffer.buffer,in_buffer.read_pos,to_be_saved); // move "low water" part to beginning of buffer + buffer_write_pos = in_buffer.buffer + to_be_saved; + in_buffer.stream_offset += (off_t) to_be_read; + if(in_buffer.block_end != NULL) in_buffer.block_end -= to_be_read; + } + + in_buffer.read_pos = in_buffer.buffer; + + read_count = 0; + do + { + last_read = read(in_stream->fd,buffer_write_pos + read_count,(size_t) (to_be_read - read_count)); + if (last_read == -1) panic("Error reading file",in_stream->file,strerror(errno)); + if (last_read == 0) + { + if (close(in_stream->fd) == -1) panic("Error in closing file",in_stream->file,strerror(errno)); + in_stream = in_stream->next; + } + read_count += last_read; + } while (in_stream != NULL && read_count < to_be_read); + + if (read_count < to_be_read) in_buffer.stream_end = buffer_write_pos + read_count - 1; + + return read_count; +} + +/* reads byte from the buffer */ +inline unsigned char +read_byte() +{ + return *in_buffer.read_pos; +} + +/* advances the read pointer, if buffer has reached low water, get more from stream to buffer */ +/* returns false in case of end of stream */ + +inline int +get_next_byte() +{ + if(in_buffer.read_pos >= in_buffer.low_pos) + { + if(read_input_stream() && in_buffer.block_end == NULL) mark_block_end(); + } + + if(in_buffer.stream_end != NULL) + { + if(in_buffer.read_pos >= in_buffer.stream_end) + { + return 0; + } + } + + in_buffer.read_pos++; + in_buffer.block_offset++; + return 1; +} + +/* check if the eof current block is in buffer and mark it in_buffer.block_end */ +void +mark_block_end() +{ + unsigned char *safe_search,*scan; + int i; + + if(in_buffer.stream_end != NULL) + { + safe_search = in_buffer.stream_end; + } else + { + safe_search = in_buffer.buffer + INPUT_BUFFER_SIZE; + } + + in_buffer.block_end = NULL; + + if(block.type & BLOCK_STOP_M) + { + in_buffer.block_end = in_buffer.read_pos + (block.stop.M - in_buffer.block_offset - 1); + if(in_buffer.block_end > safe_search) in_buffer.block_end = NULL; + } + + + if(block.type & BLOCK_STOP_S) + { + scan = in_buffer.read_pos; + if(block.stop.S.length) + { + if(block.type & BLOCK_START_S && in_buffer.block_offset < block.start.S.length) + scan += block.start.S.length - in_buffer.block_offset; + i = 0; + while(scan <= safe_search - block.stop.S.length + 1 && i < block.stop.S.length) + { + i = 0; + while(*scan == block.stop.S.string[i] && i < block.stop.S.length) + { + scan++; + i++; + } + if(i) + { + scan -= i - 1; + } else + { + scan++; + } + } + + if (i == block.stop.S.length) + { + scan += i - 2; + in_buffer.block_end = scan; + } + } else + { + if(block.type & BLOCK_START_S) + { + if(block.start.S.length) + { + if(in_buffer.block_offset < block.start.S.length) // to skip block start + scan += block.start.S.length - in_buffer.block_offset; + + i = 0; + + while(scan <= safe_search - block.start.S.length + 1 && i < block.start.S.length) + { + i = 0; + while(*scan == block.start.S.string[i] && i < block.start.S.length) + { + scan++; + i++; + } + if(i) + { + scan -= i; + } else + { + scan++; + } + } + + if (i == block.start.S.length) + { + in_buffer.block_end = scan - 1; + } + } else + { + panic("Both block start and stop zero size",NULL,NULL); + } + } + } + } + + if(in_buffer.block_end == NULL && in_buffer.stream_end != NULL) + in_buffer.block_end = in_buffer.stream_end; +} + +/* returns true if current byte is last in block */ +inline int +last_byte() +{ + return in_buffer.block_end == in_buffer.read_pos; +} + +/* returns true if end of stream has been reached */ +inline int +end_of_stream() +{ + if(in_buffer.stream_end != NULL && in_buffer.stream_end == in_buffer.read_pos) + { + return 1; + } else + { + return 0; + } +} + +/* read for stream to input buffer and advance the read_pos to the start of the buffer */ +/* in_buffer.read_pos should point to last byte of previous block */ +int +find_block() +{ + unsigned char *safe_search,*scan_start; + register int i; + int found; + + found = 0; + + if(end_of_stream() && last_byte()) return 0; + in_buffer.block_offset = 0; + + do + { + if(in_buffer.read_pos >= in_buffer.low_pos || in_buffer.read_pos == NULL) read_input_stream(); + + if(last_byte()) in_buffer.read_pos++; + in_buffer.block_end = NULL; + + scan_start = in_buffer.read_pos; + + if(in_buffer.stream_end != NULL) + { + safe_search = in_buffer.stream_end; + } else + { + safe_search = in_buffer.low_pos; + } + + if (in_buffer.read_pos <= safe_search) + { + if(block.type & BLOCK_START_M) + { + if(block.start.N >= in_buffer.stream_offset + (off_t) (in_buffer.read_pos-in_buffer.buffer) && + block.start.N <= in_buffer.stream_offset + (off_t) (safe_search-in_buffer.buffer)) + { + in_buffer.read_pos = in_buffer.buffer + (block.start.N-in_buffer.stream_offset); + found = 1; + } else + { + in_buffer.read_pos = safe_search; + } + } + + if(block.type & BLOCK_START_S) + { + if(block.start.S.length > 0) + { + i = 0; + while(in_buffer.read_pos <= safe_search - block.start.S.length + 1 && i < block.start.S.length) + { + i = 0; + while(*in_buffer.read_pos == block.start.S.string[i] && i < block.start.S.length) + { + in_buffer.read_pos++; + i++; + } + if(i) + { + in_buffer.read_pos -= i - 1; + } else + { + in_buffer.read_pos++; + } + } + + if(i == block.start.S.length) + { + in_buffer.read_pos--; + found = 1; + } else if(scan_start == in_buffer.read_pos) + { + in_buffer.read_pos++; + } + + if(in_buffer.read_pos > in_buffer.stream_end && in_buffer.stream_end != NULL) in_buffer.read_pos--; + + } else + { + found = 1; + } + } + if(in_buffer.read_pos > scan_start) + write_output_stream(scan_start,in_buffer.read_pos - scan_start); + if(found) mark_block_end(); + } + } while (!found && !end_of_stream()); + if(end_of_stream() && !found) write_output_stream(in_buffer.read_pos,1); + if(found) in_buffer.block_num++; + return found; +} + +/* write_buffer at the current write position */ +void +write_buffer(unsigned char *buf,off_t length) +{ + unsigned char *save_pos; + + if(length > (off_t) (OUTPUT_BUFFER_SIZE - (out_buffer.write_pos - out_buffer.buffer))) + { + save_pos = out_buffer.cycle_start < out_buffer.low_pos ? out_buffer.cycle_start : out_buffer.low_pos; + if(save_pos == out_buffer.buffer) + panic("Write buffer too small",NULL,NULL); + write_output_stream(out_buffer.buffer,save_pos - out_buffer.buffer); + write_w_command(out_buffer.buffer,save_pos - out_buffer.buffer); + memmove(out_buffer.buffer,save_pos,out_buffer.write_pos - save_pos); + out_buffer.write_pos = out_buffer.buffer + (out_buffer.write_pos - save_pos); + out_buffer.cycle_start = out_buffer.buffer + (out_buffer.cycle_start - save_pos); + } + memcpy(out_buffer.write_pos,buf,length); + out_buffer.write_pos += length; + out_buffer.block_offset += length; +} + +/* put_byte, put one byte att current write position */ +inline void +put_byte(unsigned char byte) +{ + *out_buffer.write_pos = byte; +} + +/* next_byte, advance the write pointer by one */ +/* if buffer full write it to disk */ +inline void +write_next_byte() +{ + unsigned char *save_pos; + + out_buffer.write_pos++; + out_buffer.block_offset++; + if(out_buffer.write_pos > out_buffer.buffer + OUTPUT_BUFFER_SIZE) + { + save_pos = out_buffer.cycle_start < out_buffer.low_pos ? out_buffer.cycle_start : out_buffer.low_pos; + if(save_pos == out_buffer.buffer) + panic("Write buffer too small",NULL,NULL); + write_output_stream(out_buffer.buffer,save_pos - out_buffer.buffer); + write_w_command(out_buffer.buffer,save_pos - out_buffer.buffer); + memmove(out_buffer.buffer,save_pos,out_buffer.write_pos - save_pos); + out_buffer.write_pos = out_buffer.buffer + (out_buffer.write_pos - save_pos); + out_buffer.cycle_start = out_buffer.buffer + (out_buffer.cycle_start - save_pos); + } +} + +/* reverse_bytes, reverse the write position (for replace etc.) */ +inline void +reverse_bytes(size_t count) +{ + out_buffer.write_pos -= count; + out_buffer.block_offset -= count; + if(out_buffer.write_pos < out_buffer.buffer) panic("Too many bytes reversed, should not happen",NULL,NULL); +} + +/* set editing cycle start position */ +inline void +set_cycle_start() +{ + out_buffer.cycle_start = out_buffer.write_pos; +} + +/* write unwritten data from buffer to disk */ +void +flush_buffer() +{ + write_output_stream(out_buffer.buffer,out_buffer.write_pos - out_buffer.buffer); + write_w_command(out_buffer.buffer,out_buffer.write_pos - out_buffer.buffer); + out_buffer.write_pos = out_buffer.buffer; +} + +/* close_output_stream */ +void +close_output_stream() +{ + if(close(out_stream.fd) == -1) panic("Error closing output stream",out_stream.file,strerror(errno)); +} + diff --git a/src/execute.c b/src/execute.c new file mode 100644 index 0000000..5ad5cc0 --- /dev/null +++ b/src/execute.c @@ -0,0 +1,324 @@ +/* + * bbe - Binary block editor + * + * Copyright (C) 2005 Timo Savinen + * This file is part of bbe. + * + * bbe 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. + * + * bbe 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 bbe; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +/* $Id: execute.c,v 1.12 2005/09/14 17:34:44 timo Exp $ */ + +#include "bbe.h" +#include <stdlib.h> +#include <error.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> + +/* tells if current byte should be deleted */ +static int delete_this_byte; + +/* tells if current block should be deleted */ +static int delete_this_block; + +/* command list for write_w_command */ +static struct command *current_commands; + +/* commands to be executed at start of buffer */ +/* note J and L must be in every string becaus ethey affect the whole block */ +#define BLOCK_START_COMMANDS "DAJL" + +/* commands to be executed for each byte */ +#define BYTE_COMMANDS "acdirsywjlJL" + +/* commands to be executed at end of buffer */ +#define BLOCK_END_COMMANDS "IJL" + +/* execute given commands */ +void +execute_commands(struct command *c,char *command_letters) +{ + register int i; + unsigned char a,b; + + while(c != NULL) + { + if(strchr(command_letters,c->letter) != NULL) + { + switch(c->letter) + { + case 'A': + case 'I': + write_buffer(c->s1,c->s1_len); + break; + case 'd': + if(c->rpos || c->offset == in_buffer.block_offset) + { + if(c->rpos < c->count) + { + delete_this_byte = 1; + c->rpos++; + } else + { + c->rpos = 0; + } + } + break; + case 'D': + if(c->offset == in_buffer.block_num || c->offset == 0) delete_this_block = 1; + break; + case 'i': + if(c->offset == in_buffer.block_offset) + { + if (!delete_this_byte) write_next_byte(); + write_buffer(c->s1,c->s1_len); + reverse_bytes(1); + } + break; + case 'r': + if(c->offset == in_buffer.block_offset) + { + put_byte(c->s1[0]); + c->rpos=1; + delete_this_byte = 0; + } else if(c->rpos) + { + if(c->rpos < c->s1_len) + { + put_byte(c->s1[c->rpos]); + c->rpos++; + delete_this_byte = 0; + } else + { + c->rpos = 0; + } + } + break; + case 's': + if(delete_this_byte || out_buffer.block_offset + 1 < c->s1_len) break; + i = 0; + while(out_buffer.write_pos[i - c->s1_len + 1] == c->s1[i] && i < c->s1_len) i++; + if(i < c->s1_len) break; + reverse_bytes(c->s1_len - 1); + if(c->s2_len) + { + write_buffer(c->s2,c->s2_len); + reverse_bytes(1); + } else + { + delete_this_byte = 1; + } + break; + case 'y': + i = 0; + while(c->s1[i] != read_byte() && i < c->s1_len) i++; + if(c->s1[i] == read_byte() && i < c->s1_len) put_byte(c->s2[i]); + break; + case 'c': + switch(c->s1[0]) + { + case 'A': // from ascii + switch(c->s1[3]) + { + case 'B': // to bcd + if(c->rpos || (last_byte() && out_buffer.block_offset == 0)) // skip first nibble + { + c->rpos = 0; + if(last_byte()) // unless last byte of block + { + if(*out_buffer.write_pos >= '0' && *out_buffer.write_pos <= '9') + { + a = *out_buffer.write_pos - '0'; + a = (a << 4) & 0xf0; + b = 0x0f; + *out_buffer.write_pos = a | b; + } + } + break; + } + if(out_buffer.block_offset == 0 || delete_this_byte) break; + if((out_buffer.write_pos[-1] >= '0' && out_buffer.write_pos[-1] <= '9')) + { + a = out_buffer.write_pos[-1] - '0'; + a = (a << 4) & 0xf0; + if(*out_buffer.write_pos >= '0' && *out_buffer.write_pos <= '9') + { + b = *out_buffer.write_pos - '0'; + b &= 0x0f; + delete_this_byte = 1; + c->rpos = 1; + } else + { + b = 0x0f; + } + out_buffer.write_pos[-1] = a | b; + } + break; + } + break; + case 'B': // from bcd + switch(c->s1[3]) + { + case 'A': // to ascii + if(((*out_buffer.write_pos >> 4) & 0x0f) <= 9 && + ((*out_buffer.write_pos & 0x0f) <= 9 || (*out_buffer.write_pos & 0x0f) == 0x0f)) + { + a = (*out_buffer.write_pos >> 4) & 0x0f; + b = *out_buffer.write_pos & 0x0f; + *out_buffer.write_pos = '0' + a; + if(!delete_this_byte && b != 0x0f) + { + write_next_byte(); + *out_buffer.write_pos = '0' + b; + } + } + break; + } + break; + } + break; + case 'j': + if(in_buffer.block_offset < c->count) + { + while(c->next != NULL) c = c->next; // skip rest of commands + } + break; + case 'J': + if(in_buffer.block_num <= c->count) + { + while(c->next != NULL) c = c->next; // skip rest of commands + } + break; + case 'l': + if(in_buffer.block_offset >= c->count) + { + while(c->next != NULL) c = c->next; // skip rest of commands + } + break; + case 'L': + if(in_buffer.block_num > c->count) + { + while(c->next != NULL) c = c->next; // skip rest of commands + } + break; + case 'w': + break; + } + } + c = c->next; + } +} + +/* write w command, will be called when output_buffer is written, same will be written to w-command files */ +void +write_w_command(unsigned char *buf,size_t length) +{ + struct command *c; + + c = current_commands; + + while(c != NULL) + { + if(c->letter == 'w') + { + if(fwrite(buf,1,length,c->fd) != length) panic("Cannot write to file",c->s1,strerror(errno)); + } + c = c->next; + } +} + + + +/* init_commands, initialize those wich need it, currently w - open file and rpos=0 for all */ +void +init_commands(struct command *c) +{ + while(c != NULL) + { + switch(c->letter) + { + case 'w': + c->fd = fopen(c->s1,"w"); + if(c->fd == NULL) panic("Cannot open file for writing",c->s1,strerror(errno)); + break; + } + c = c->next; + } +} + + +/* close_commands, close those wich need it, currently w - close file */ +void +close_commands(struct command *c) +{ + while(c != NULL) + { + switch(c->letter) + { + case 'w': + if(fclose(c->fd) != 0) panic("Error in closing file",c->s1,strerror(errno)); + break; + } + c = c->next; + } +} + +/* reset the rpos counter for next block, in case block was shorter eg. delete count */ +inline void +reset_rpos(struct command *c) +{ + while(c != NULL) + { + c->rpos = 0; + c = c->next; + } +} + + + +/* main execution loop */ +void +execute_program(struct command *c) +{ + int block_end; + + current_commands = c; + + while(find_block()) + { + delete_this_block = 0; + reset_rpos(c); + execute_commands(c,BLOCK_START_COMMANDS); + out_buffer.block_offset = 0; + do + { + set_cycle_start(); + delete_this_byte = 0; + block_end = last_byte(); + put_byte(read_byte()); // as default write current byte from input + execute_commands(c,BYTE_COMMANDS); + if(!delete_this_byte && !delete_this_block) + { + write_next_byte(); // advance the write pointer if byte is not marked for del + } + if(!block_end) get_next_byte(); + } while (!block_end); + execute_commands(c,BLOCK_END_COMMANDS); + flush_buffer(); + } + close_output_stream(); +} diff --git a/src/xmalloc.c b/src/xmalloc.c new file mode 100644 index 0000000..01e1173 --- /dev/null +++ b/src/xmalloc.c @@ -0,0 +1,35 @@ +/* + * bbe - Binary block editor + * + * Copyright (C) 2005 Timo Savinen + * This file is part of bbe. + * + * bbe 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. + * + * bbe 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 bbe; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +/* $Id: xmalloc.c,v 1.2 2005/09/04 15:58:29 timo Exp $ */ + +#include "bbe.h" +#include <stdlib.h> + +void * +xmalloc (size_t size) +{ + register void *value = malloc(size); + if (value == 0) panic("Out of memory",NULL,NULL); + return value; +} + |

