summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTimo Savinen <tjsa@iki.fi>2005-09-22 15:39:00 +0000
committerHadrien Dorio <hadrien.dorio@gmail.com>2017-12-16 00:23:56 +0100
commit35d0e8a808dd1382d5236d1f6f8bfe62b2ebefee (patch)
treee84242391375fab6b6e15963b4b1e0be5296b0bd /src
downloadbinary-block-editor-35d0e8a808dd1382d5236d1f6f8bfe62b2ebefee.tar.gz
binary-block-editor-35d0e8a808dd1382d5236d1f6f8bfe62b2ebefee.zip
0.1.0
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am6
-rw-r--r--src/Makefile.in408
-rw-r--r--src/bbe.c597
-rw-r--r--src/bbe.h211
-rw-r--r--src/buffer.c490
-rw-r--r--src/execute.c324
-rw-r--r--src/xmalloc.c35
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;
+}
+
OpenPOWER on IntegriCloud