summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimo Savinen <tjsa@iki.fi>2005-09-25 12:05:00 +0000
committerHadrien Dorio <hadrien.dorio@gmail.com>2017-12-16 00:24:05 +0100
commitb9eb6e4429575318d3c510b99961093c42321529 (patch)
tree997ceb30973318a5cb7da0a78a5a9784d8137e61
parent35d0e8a808dd1382d5236d1f6f8bfe62b2ebefee (diff)
downloadbinary-block-editor-b9eb6e4429575318d3c510b99961093c42321529.tar.gz
binary-block-editor-b9eb6e4429575318d3c510b99961093c42321529.zip
0.1.1
-rw-r--r--ChangeLog11
-rw-r--r--config.h.in9
-rwxr-xr-x[-rw-r--r--]config/texinfo.tex0
-rwxr-xr-xconfigure125
-rw-r--r--configure.ac5
-rw-r--r--doc/bbe.122
-rw-r--r--doc/bbe.info116
-rw-r--r--doc/bbe.texi105
-rw-r--r--src/bbe.c169
-rw-r--r--src/bbe.h15
-rw-r--r--src/buffer.c50
-rw-r--r--src/execute.c104
12 files changed, 650 insertions, 81 deletions
diff --git a/ChangeLog b/ChangeLog
index dbb4c62..180add7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,11 @@
-2005-09-15 Timo Savinen <tjsa@iki.fi>
+2005-09-25 Timo Savinen <tjsa.iki.fi>
+ * Version 0.1.1
+ * Bug fixes (\\ escape in strings)
+ * -s option added
+ * Added F, B, N and p commands
+ * Several commands can be given in one -e switch, commands must be separated by semicolon
- * bbe: initial version 0.1.0.
+2005-09-15 Timo Savinen <tjsa@iki.fi>
+
+ * bbe: initial version 0.1.0.
diff --git a/config.h.in b/config.h.in
index dc7fa33..a389c82 100644
--- a/config.h.in
+++ b/config.h.in
@@ -3,12 +3,21 @@
/* Define to 1 if you have the <errno.h> header file. */
#undef HAVE_ERRNO_H
+/* Define to 1 if you have the <error.h> header file. */
+#undef HAVE_ERROR_H
+
/* Define to 1 if you have the <features.h> header file. */
#undef HAVE_FEATURES_H
+/* Define to 1 if you have the `getline' function. */
+#undef HAVE_GETLINE
+
/* Define to 1 if you have the <getopt.h> header file. */
#undef HAVE_GETOPT_H
+/* Define to 1 if you have the `getopt_long' function. */
+#undef HAVE_GETOPT_LONG
+
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
diff --git a/config/texinfo.tex b/config/texinfo.tex
index ff2c406..ff2c406 100644..100755
--- a/config/texinfo.tex
+++ b/config/texinfo.tex
diff --git a/configure b/configure
index ab53901..2f14f06 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.59 for bbe 0.1.0.
+# Generated by GNU Autoconf 2.59 for bbe 0.1.1.
#
# Report bugs to <tjsa@iki.fi>.
#
@@ -269,8 +269,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package.
PACKAGE_NAME='bbe'
PACKAGE_TARNAME='bbe'
-PACKAGE_VERSION='0.1.0'
-PACKAGE_STRING='bbe 0.1.0'
+PACKAGE_VERSION='0.1.1'
+PACKAGE_STRING='bbe 0.1.1'
PACKAGE_BUGREPORT='tjsa@iki.fi'
ac_unique_file="src/bbe.c"
@@ -780,7 +780,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures bbe 0.1.0 to adapt to many kinds of systems.
+\`configure' configures bbe 0.1.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -846,7 +846,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of bbe 0.1.0:";;
+ short | recursive ) echo "Configuration of bbe 0.1.1:";;
esac
cat <<\_ACEOF
@@ -965,7 +965,7 @@ fi
test -n "$ac_init_help" && exit 0
if $ac_init_version; then
cat <<\_ACEOF
-bbe configure 0.1.0
+bbe configure 0.1.1
generated by GNU Autoconf 2.59
Copyright (C) 2003 Free Software Foundation, Inc.
@@ -979,7 +979,7 @@ cat >&5 <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by bbe $as_me 0.1.0, which was
+It was created by bbe $as_me 0.1.1, which was
generated by GNU Autoconf 2.59. Invocation command line was
$ $0 $@
@@ -1623,7 +1623,7 @@ fi
# Define the identity of the package.
PACKAGE='bbe'
- VERSION='0.1.0'
+ VERSION='0.1.1'
cat >>confdefs.h <<_ACEOF
@@ -3492,7 +3492,8 @@ done
-for ac_header in features.h errno.h getopt.h
+
+for ac_header in features.h error.h errno.h getopt.h
do
as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
if eval "test \"\${$as_ac_Header+set}\" = set"; then
@@ -3642,6 +3643,108 @@ done
+for ac_func in getline getopt_long
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
# Check whether --enable-largefile or --disable-largefile was given.
if test "${enable_largefile+set}" = set; then
enableval="$enable_largefile"
@@ -4557,7 +4660,7 @@ _ASBOX
} >&5
cat >&5 <<_CSEOF
-This file was extended by bbe $as_me 0.1.0, which was
+This file was extended by bbe $as_me 0.1.1, which was
generated by GNU Autoconf 2.59. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -4620,7 +4723,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\
-bbe config.status 0.1.0
+bbe config.status 0.1.1
configured by $0, generated by GNU Autoconf 2.59,
with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
diff --git a/configure.ac b/configure.ac
index 826c679..3c95d66 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
dnl Process this file with autoconf to produce a configure script.
-AC_INIT(bbe, 0.1.0, tjsa@iki.fi)
+AC_INIT(bbe, 0.1.1, tjsa@iki.fi)
AC_CONFIG_SRCDIR(src/bbe.c)
AC_CONFIG_AUX_DIR(config)
AM_INIT_AUTOMAKE
@@ -24,7 +24,8 @@ dnl Checks for libraries.
dnl Checks for header files.
AC_HEADER_STDC
-AC_CHECK_HEADERS(features.h errno.h getopt.h)
+AC_CHECK_HEADERS(features.h error.h errno.h getopt.h)
+AC_CHECK_FUNCS(getline getopt_long)
dnl Checks for typedefs, structures, and compiler characteristics.
diff --git a/doc/bbe.1 b/doc/bbe.1
index fef176d..6426ed1 100644
--- a/doc/bbe.1
+++ b/doc/bbe.1
@@ -49,6 +49,9 @@ Add the contest of script\-file to commands.
.BR \-o ", " \-\-output=\fIname\fP
Write output to \fIname\fP instead of standard output.
.TP
+.BR \-s ", " \-\-suppress
+Suppress normal output, print only block contents.
+.TP
.BR \-? ", " \-\-help
List all available options and their meanings.
.TP
@@ -68,7 +71,7 @@ Block length in input stream is M.
String \fIstart\fP starts M bytes long block.
.TP
/start/:/stop/
-String \fIstart\fP starts the block and block ends to string \fIstop\fR
+String \fIstart\fP starts the block and block ends to string \fIstop\fR.
.TP
/start/:
String \fIstart\fR starts the block and block will end at next occurence of \fIstart\fR. Only the first \fIstart\fR is included to the block.
@@ -113,6 +116,17 @@ Skip \fIn\fR blocks before executing commands after this command.
.TP
L \fIn\fR
Leave all blocks unmodified starting from block number \fIn\fR. Affects only commands after this command.
+.TP
+N
+Before printing a block, the file name in which the block starts is printed.
+.TP
+F \fIf\fR
+Before printing a block, the input stream offset at the begining of the block is printed.
+\fIf\fR can be H, D or O for Hexadecimal, Decimal or Octal format of offset.
+.TP
+B \fIf\fR
+Before printing a block, the block number is printed (first block == 1)
+\fIf\fR can be H, D or O for Hexadecimal, Decimal or Octal format of block number.
.LP
\fBByte commands\fR
.br
@@ -124,6 +138,10 @@ Replace bytes starting at position \fIn\fR with string \fIstring\fR.
i \fIn\fR \fIstring\fR
Insert \fIstring\fR starting at position \fIn\fR.
.TP
+p \fIformat\fR
+The contents of block is printed in format defined by \fIformat\fR. \fIformat\fR
+can have any of the formats H, D, O and A for Hexadecimal, Decimal, Octal or Ascii.
+.TP
s/\fIsearch\fR/\fIreplace\fR/
Replace all occurrences of \fIsearch\fR with \fIreplace\fR.
.TP
@@ -153,7 +171,7 @@ Write bytes from the current block to file \fIfile\fR. Commands before w\-comman
.LP
Nonvisible characters in strings can be escaped same way as in block definition strings. Character '/' in s and y commands can be any visible character.
.LP
-Note that the D, A, I, c, s, i, y and d commands cause the length of input and output streams to be different.
+Note that the D, A, I, F, B, c, s, i, y, p and d commands cause the length of input and output streams to be different.
.SH "EXAMPLES"
.TP
diff --git a/doc/bbe.info b/doc/bbe.info
index a8c5a3f..75a3d07 100644
--- a/doc/bbe.info
+++ b/doc/bbe.info
@@ -59,6 +59,9 @@ basic byte related transformations on blocks of input stream. `bbe' is
non-interactive command line tool and can be used as a part of a
pipeline. `bbe' makes only one pass over input stream.
+ `bbe' also contains grep-like features, like printing the filename,
+offset and block number.
+

File: bbe.info, Node: Samples, Next: Invoking bbe, Prev: Overview, Up: Top
@@ -124,7 +127,8 @@ The format for running the `bbe' program is:
`-e COMMAND'
`--expression=COMMAND'
- Add command to the commands to be executed.
+ Add command(s) to the commands to be executed. Commands must
+ separated by semicolon.
`-f SCRIPT-FILE'
`--file=SCRIPT-FILE'
@@ -134,6 +138,10 @@ The format for running the `bbe' program is:
`--output=FILE'
Write output to FILE instead of standard output.
+`-s'
+`--suppress'
+ Suppress printing of normal output, print only block contents.
+
`-?'
`--help'
Print an informative help message describing the options and then
@@ -144,7 +152,8 @@ The format for running the `bbe' program is:
Print the version number of `bbe' and then exit successfully.
All remaining options are names of input files, if no input files
-are specified, then the standard input is read.
+are specified, then the standard input is read. `-' means standard
+input.

File: bbe.info, Node: Block, Next: Commands, Prev: Invocation, Up: Invoking bbe
@@ -247,6 +256,28 @@ Block commands are:
Commands that are defined before this command have effect on every
block.
+`N'
+ Before block contents the file name where the block starts is
+ printed with colon.
+
+`F F'
+ Before block contents the current stream offset and colon is
+ printed in format specified by F. Stream offset starts at zero. F
+ can have one of following values:
+ H
+ Hexadecimal.
+
+ D
+ Decimal.
+
+ O
+ Octal.
+
+`B F'
+ Before block contents the current block number and colon is
+ printed in format specified by F. Block numbering starts at zero.
+ F can have one of the sames codes as `F'-command
+
Byte commands are:
------------------
@@ -260,7 +291,7 @@ block, first byte is number zero.
`BCD'
Binary Coded Decimal
- *Note:* Bytes, that cannot be converted are passed through as they
+ *Note*: Bytes, that cannot be converted are passed through as they
are. e.g. in ASC -> BCD conversion, ASCII characters not in range
`'0'' - `'9'' are not converted.
@@ -278,6 +309,24 @@ block, first byte is number zero.
Commands appearing after `l'-command have no effect concerning
bytes starting from the byte number N of the block.
+`p FORMAT'
+ Contents of block is printed in formats specified by FORMAT.
+ FORMAT can contain following format codes:
+ H
+ Hexadecimal.
+
+ D
+ Decimal.
+
+ O
+ Octal.
+
+ A
+ Ascii, nonprintable characters are printed as space.
+
+ FORMAT can contain several codes, values are then separated by
+ hyphen.
+
`r N STRING'
Replace bytes with STRING starting at the byte number N of the
block.
@@ -303,8 +352,8 @@ File: bbe.info, Node: Limits, Prev: Commands, Up: Invoking bbe
3.4 Limitations
===============
-At least in GNU/Linux `bbe' should be able to handle big files (>4GB),
-other systems are not tested.
+At least in GNU/Linux `bbe' should be able to handle big files (> 4
+GB), other systems are not tested.
There are however, some limitations in block and command definitions:
@@ -332,10 +381,11 @@ Basic execution cycle:
----------------------
1. Start of the block is searched. If found, data before block is
- written to output stream and step 2 is executed.
+ written to output stream (unless `-s' is defined) and step 2 is
+ executed.
- 2. Block commands affecting the start of the block (`A', `D' and `J')
- are executed.
+ 2. Block commands affecting the start of the block (`A', `D', `J',
+ `N', `F' and `B') are executed.
3. The block is scanned byte by byte and all byte commands (lower
case letters) are executed. *Note*: Commands are executed on
@@ -345,8 +395,8 @@ Basic execution cycle:
4. When end of the block is reached the end of the block commands
(`I') are executed.
- 5. Next block is searched, data between the blocks is written to
- output stream.
+ 5. Next block is searched, data between the blocks, if not suppressed
+ with `-s', is written to output stream.
Few examples:
-------------
@@ -358,7 +408,6 @@ Few examples:
The quick brown fox j
All spaces in the block are converted to X's, before conversion
first 4 bytes are skipped.
-
`echo "The quick brown fox jumps over a lazy dog" | bbe -b ":/ /" -e "J 1" -e "I \x0a"'
Output is:
The quick
@@ -371,17 +420,42 @@ Few examples:
dog
All blocks end at space, a newline character is inserted after
every block except the first block.
-
`echo "The quick brown fox jumps over a lazy dog" | bbe -e "r 4 fast\x20" -e "s/f/c/"'
Output is:
The cast brown cox jumps over a lazy dog
Also the `f' in `fast' is converted to `c'.
-
`echo "1234567890" | bbe -b ":1" -e "L 9" -e "I -"'
Output is
1-2-3-4-5-6-7-8-9-0
Minus is inserted after every 1 byte long block,but not after 9'th
block.
+`bbe -s -b "/First line/:/Last line/" /tmp/text'
+ Print lines between sentences `First line' and `Last line'.
+`bbe -s -b "%<a %:%</a>%" -e "s/\x0a/ /" -e "I \x0a" ./index.html'
+ Extract all links from `./index.html'. To get one link per line,
+ all newlines are converted to spaces and newline is added after
+ every link.
+`bbe -b "/\x5f\x28\x02/:10" -s -e "F d" -e "p h" -e "I \x0a" ./bindata'
+ 10 bytes long sequences starting with values `x5f' `x28' and `x02'
+ are printed as hex values. Also the file offset is printed before
+ each sequence and new line is added after every sequence. Example
+ output:
+ 52688:x5f x28 x02 x32 x36 x5f x81 x64 x01 x93
+ 68898:x5f x28 x02 x39 x46 x5f x81 x64 x41 x05
+ 69194:x5f x28 x02 x42 x36 x5f x81 x64 x41 x05
+
+`bbe -b "/Linux/:5" -s -e "N;D;I \x0a" /bin/* | uniq'
+ Print the files names of those programs in /bin directory which
+ contains word `Linux'. Example output:
+ /bin/loadkeys:
+ /bin/mkbimage:
+ /bin/ps:
+ /bin/uname:
+
+`bbe -b "/\x5f\x81\x18\x06/:10" -s -e "B d;d 0 4;c BCD ASC;I \x0a" ./bindata'
+ Print BCD numbers and their block numbers in ascii format. Numbers
+ start with sequence `x5f' `x81' `x18' `x06'. The start sequence
+ is not printed.

File: bbe.info, Node: Problems, Prev: bbe programs, Up: Top
@@ -404,13 +478,13 @@ problems.
Tag Table:
Node: Top766
Node: Overview1811
-Node: Samples2201
-Node: Invoking bbe3599
-Node: Invocation4117
-Node: Block4980
-Node: Commands6784
-Node: Limits9572
-Node: bbe programs10123
-Node: Problems12406
+Node: Samples2298
+Node: Invoking bbe3696
+Node: Invocation4214
+Node: Block5237
+Node: Commands7041
+Node: Limits10744
+Node: bbe programs11297
+Node: Problems14962

End Tag Table
diff --git a/doc/bbe.texi b/doc/bbe.texi
index b5d830e..f0c6188 100644
--- a/doc/bbe.texi
+++ b/doc/bbe.texi
@@ -6,7 +6,7 @@
@finalout
@c %**end of header
-@set VERSION 0.1.0
+@set VERSION 0.1.1
@copying
This file documents the @command{bbe} - binary block editor
@@ -68,6 +68,9 @@ The @command{bbe} program is a sed-like editor for binary files. @command{bbe}
performs basic byte related transformations on blocks of input stream. @command{bbe} is non-interactive command line tool and
can be used as a part of a pipeline. @command{bbe} makes only one pass over input stream.
+@command{bbe} also contains grep-like features, like printing the filename, offset and block number.
+
+
@node Samples, Invoking bbe, Overview, Top
@chapter Samples using @command{bbe}
@cindex sample
@@ -136,7 +139,7 @@ Block definition.
@item -e @var{COMMAND}
@itemx --expression=@var{COMMAND}
-Add command to the commands to be executed.
+Add command(s) to the commands to be executed. Commands must separated by semicolon.
@item -f @var{script-file}
@@ -149,6 +152,11 @@ Add commands from @var{script-file} to the commands to be executed.
Write output to @var{file} instead of standard output.
+@item -s
+@itemx --suppress
+Suppress printing of normal output, print only block contents.
+
+
@item -?
@itemx --help
Print an informative help message describing the options and then exit
@@ -161,6 +169,7 @@ Print the version number of @command{bbe} and then exit successfully.
@end table
All remaining options are names of input files, if no input files are specified, then the standard input is read.
+@code{-} means standard input.
@node Block, Commands, Invocation, Invoking bbe
@section Block definition
@@ -251,6 +260,27 @@ Commands appearing after this command have no effect until @var{N} blocks are fo
@item L @var{N}
Commands appearing after this command have no effect after @var{N} blocks are found. Means "Leave blocks after @var{N}'th block".
@strong{Note}: Commands that are defined before this command have effect on every block.
+
+@item N
+Before block contents the file name where the block starts is printed with colon.
+
+@item F @var{f}
+Before block contents the current stream offset and colon is printed in format specified by @var{f}.
+Stream offset starts at zero. @var{f} can have one of following values:
+@table @var
+@item H
+Hexadecimal.
+
+@item D
+Decimal.
+
+@item O
+Octal.
+@end table
+
+@item B @var{f}
+Before block contents the current block number and colon is printed in format specified by @var{f}.
+Block numbering starts at zero. @var{f} can have one of the sames codes as @code{F}-command
@end table
@subheading Byte commands are:
@@ -267,7 +297,7 @@ Ascii
@item BCD
Binary Coded Decimal
@end table
-@strong{Note:} Bytes, that cannot be converted are passed through as they are. e.g. in ASC -> BCD conversion, ASCII characters not
+@strong{Note}: Bytes, that cannot be converted are passed through as they are. e.g. in ASC -> BCD conversion, ASCII characters not
in range @code{'0'} -- @code{'9'} are not converted.
@item d @var{n} @var{m}
@@ -282,6 +312,24 @@ Commands appearing after @code{j}-command have no effect concerning bytes 0-@var
@item l @var{n}
Commands appearing after @code{l}-command have no effect concerning bytes starting from the byte number @var{n} of the block.
+@item p @var{format}
+Contents of block is printed in formats specified by @var{format}. @var{format} can contain following format codes:
+@table @var
+@item H
+Hexadecimal.
+
+@item D
+Decimal.
+
+@item O
+Octal.
+
+@item A
+Ascii, nonprintable characters are printed as space.
+@end table
+
+@var{format} can contain several codes, values are then separated by hyphen.
+
@item r @var{n} @var{string}
Replace bytes with @var{string} starting at the byte number @var{n} of the block.
@@ -303,7 +351,7 @@ Separator @code{/} can be replaced by any character not present in @var{source}
@cindex big files
@cindex limits
-At least in GNU/Linux @command{bbe} should be able to handle big files (>4GB), other
+At least in GNU/Linux @command{bbe} should be able to handle big files (> 4 GB), other
systems are not tested.
There are however, some limitations in block and command definitions:
@@ -331,22 +379,22 @@ and if the end of input stream is found before 128'th byte of the last block is
@enumerate
@item
-Start of the block is searched. If found, data before block is written to output stream and
+Start of the block is searched. If found, data before block is written to output stream (unless @option{-s} is defined) and
step 2 is executed.
@item
-Block commands affecting the start of the block (@code{A}, @code{D} and @code{J}) are executed.
+Block commands affecting the start of the block (@code{A}, @code{D}, @code{J}, @code{N}, @code{F} and @code{B}) are executed.
@item
The block is scanned byte by byte and all byte commands (lower case letters) are executed.
@strong{Note}: Commands are executed on results of previous commands, if e.g. the first byte of the block is deleted,
-the following commands don't 'see' the removed byte.
+the following commands don't 'see' the removed byte.
@item
When end of the block is reached the end of the block commands (@code{I}) are executed.
@item
-Next block is searched, data between the blocks is written to output stream.
+Next block is searched, data between the blocks, if not suppressed with @option{-s}, is written to output stream.
@end enumerate
@subheading Few examples:
@@ -361,7 +409,7 @@ The only block in this is
@example
The quick brown fox j
@end example
-All spaces in the block are converted to X's, before conversion first 4 bytes are skipped.
+All spaces in the block are converted to X's, before conversion first 4 bytes are skipped.@*
@item echo "The quick brown fox jumps over a lazy dog" | bbe -b ":/ /" -e "J 1" -e "I \x0a"
Output is:
@@ -376,21 +424,54 @@ lazy
dog
@end example
-All blocks end at space, a newline character is inserted after every block except the first block.
+All blocks end at space, a newline character is inserted after every block except the first block.@*
@item echo "The quick brown fox jumps over a lazy dog" | bbe -e "r 4 fast\x20" -e "s/f/c/"
Output is:
@example
The cast brown cox jumps over a lazy dog
@end example
-Also the @code{f} in @code{fast} is converted to @code{c}.
+Also the @code{f} in @code{fast} is converted to @code{c}.@*
@item echo "1234567890" | bbe -b ":1" -e "L 9" -e "I -"
Output is
@example
1-2-3-4-5-6-7-8-9-0
@end example
-Minus is inserted after every 1 byte long block,but not after 9'th block.
+Minus is inserted after every 1 byte long block,but not after 9'th block.@*
+
+@item bbe -s -b "/First line/:/Last line/" /tmp/text
+Print lines between sentences @samp{First line} and @samp{Last line}.@*
+
+@item bbe -s -b "%<a %:%</a>%" -e "s/\x0a/ /" -e "I \x0a" ./index.html
+Extract all links from @file{./index.html}. To get one link per line,
+all newlines are converted to spaces and newline is added after every link.@*
+
+@item bbe -b "/\x5f\x28\x02/:10" -s -e "F d" -e "p h" -e "I \x0a" ./bindata
+10 bytes long sequences starting with values @code{x5f} @code{x28} and @code{x02} are printed as hex values.
+Also the file offset is printed before each sequence and new line is added after every sequence.
+Example output:
+@example
+52688:x5f x28 x02 x32 x36 x5f x81 x64 x01 x93
+68898:x5f x28 x02 x39 x46 x5f x81 x64 x41 x05
+69194:x5f x28 x02 x42 x36 x5f x81 x64 x41 x05
+@end example
+@*
+
+@item bbe -b "/Linux/:5" -s -e "N;D;I \x0a" /bin/* | uniq
+Print the files names of those programs in /bin directory which contains word @samp{Linux}.
+Example output:
+@example
+/bin/loadkeys:
+/bin/mkbimage:
+/bin/ps:
+/bin/uname:
+@end example
+@*
+
+@item bbe -b "/\x5f\x81\x18\x06/:10" -s -e "B d;d 0 4;c BCD ASC;I \x0a" ./bindata
+Print BCD numbers and their block numbers in ascii format. Numbers start with sequence @code{x5f} @code{x81} @code{x18} @code{x06}.
+The start sequence is not printed.
@end table
diff --git a/src/bbe.c b/src/bbe.c
index 7c1ed00..9743ac2 100644
--- a/src/bbe.c
+++ b/src/bbe.c
@@ -20,7 +20,7 @@
*
*/
-/* $Id: bbe.c,v 1.23 2005/09/14 15:48:52 timo Exp $ */
+/* $Id: bbe.c,v 1.30 2005/09/25 10:03:47 timo Exp $ */
#include "bbe.h"
#ifdef HAVE_GETOPT_H
@@ -28,7 +28,6 @@
#endif
#include <ctype.h>
-#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_STRING_H
@@ -44,7 +43,7 @@ static char *program = "bbe";
#ifdef VERSION
static char *version = VERSION;
#else
-static char *version = "0.1.0";
+static char *version = "0.1.1";
#endif
#ifdef PACKAGE_BUGREPORT
@@ -54,19 +53,34 @@ static char *email_address = "tjsa@iki.fi";
#endif
-
+/* global block */
struct block block;
+
+/* commands to be executed */
struct command *commands = NULL;
+
+/* extra info for panic */
char *panic_info = NULL;
+/* -s switch state */
+int output_only_block = 0;
+
+/* c command conversions */
char *convert_strings[] = {
"BCDASC",
"ASCBCD",
"",
};
-static char short_opts[] = "b:e:f:o:?V";
+/* format types for p command */
+char *p_formats="DOHA";
+/* formats for F and B commands */
+char *FB_formats="DOH";
+
+static char short_opts[] = "b:e:f:o:s?V";
+
+#ifdef HAVE_GETOPT_LONG
static struct option long_opts[] = {
{"block",1,NULL,'b'},
{"expression",1,NULL,'e'},
@@ -74,8 +88,10 @@ static struct option long_opts[] = {
{"output",1,NULL,'o'},
{"help",0,NULL,'?'},
{"version",0,NULL,'V'},
+ {"suppress",0,NULL,'s'},
{NULL,0,NULL,0}
};
+#endif
void
panic(char *msg,char *info,char *syserror)
@@ -160,9 +176,9 @@ parse_string(char *string,off_t *length)
if(*p == '\\')
{
p++;
- if(*p == '\\')
+ if(*p == '\\' || *p == ';')
{
- num[i] = *p++;
+ buf[i] = *p++;
} else
{
j = 0;
@@ -345,6 +361,7 @@ parse_command(char *command_string)
{
struct command *curr,*new;
char *c,*p,*buf;
+ char *f;
char *token[10];
char slash_char;
int i,j;
@@ -352,6 +369,9 @@ parse_command(char *command_string)
p = command_string;
while(isspace(*p)) p++; // remove leading spaces
+ if (p[0] == 0) return; // empty line
+ if (p[0] == '#') return; // comment
+
c = strdup(p);
if(c == NULL) panic("Out of memory",NULL,NULL);
@@ -361,9 +381,6 @@ parse_command(char *command_string)
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)
{
@@ -468,6 +485,30 @@ parse_command(char *command_string)
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;
+ case 'F':
+ case 'B':
+ if(i > 1 && (strlen(token[1]) != 1)) panic("Error in command",command_string,NULL);
+ case 'p':
+ if(i != 2 || strlen(token[0]) > 1) panic("Error in command",command_string,NULL);
+ new->s1 = parse_string(token[1],&new->s1_len);
+ j = 0;
+ while(new->s1[j] != 0) {
+ new->s1[j] = toupper(new->s1[j]);
+ j++;
+ }
+ if (new->letter == 'p')
+ {
+ f = p_formats;
+ } else
+ {
+ f = FB_formats;
+ }
+ while(*f != 0 && strchr(new->s1,*f) == NULL) f++;
+ if (*f == 0) panic("Error in command",command_string,NULL);
+ break;
+ case 'N':
+ if(i != 1 || strlen(token[0]) > 1) panic("Error in command",command_string,NULL);
+ break;
default:
panic("Unknown command",command_string,NULL);
break;
@@ -475,30 +516,95 @@ parse_command(char *command_string)
free(c);
}
-/* read commands from file */
+/* parse commands, commands are separated by ;. ; can be escaped as \;
+ and ;s inside " or ' are not separators
+ */
+void
+parse_commands(char *command_string)
+{
+ char *c;
+ char *start;
+ int inside_d = 0; // double
+ int inside_s = 0; // single
+
+ c = command_string;
+ start = c;
+
+ while(*start != 0)
+ {
+ switch(*c)
+ {
+ case '\\':
+ c++;
+ break;
+ case '"':
+ if(inside_d)
+ {
+ inside_d--;
+ } else
+ {
+ inside_d++;
+ }
+ break;
+ case '\'':
+ if(inside_s)
+ {
+ inside_s--;
+ } else
+ {
+ inside_s++;
+ }
+ break;
+ case ';':
+ if(!inside_d && !inside_s)
+ {
+ *c = 0;
+ parse_command(start);
+ start = c + 1;
+ }
+ break;
+ case 0:
+ parse_command(start);
+ start = c;
+ break;
+ }
+ c++;
+ }
+}
+
+
+
+/* parse one command, commands are in list
+ read commands from file */
void
parse_command_file(char *file)
{
FILE *fp;
char *line;
- char info[1024];
- size_t line_len = 1024;
+ char *info;
+ size_t line_len = (8*1024);
int line_no = 0;
line = xmalloc(line_len);
+ info = xmalloc(strlen(file) + 100);
fp = fopen(file,"r");
if (fp == NULL) panic("Error in opening file",file,strerror(errno));
+#ifdef HAVE_GETLINE
while(getline(&line,&line_len,fp) != -1)
+#else
+ while(fgets(line,line_len,fp) != NULL)
+#endif
{
line_no++;
sprintf(info,"Error in file '%s' in line %d\n",file,line_no);
panic_info=info;
- parse_command(line);
+ parse_commands(line);
}
free(line);
+ free(info);
fclose(fp);
panic_info=NULL;
}
@@ -507,6 +613,7 @@ void
help(FILE *stream)
{
fprintf(stream,"Usage: %s [OPTION]...\n\n",program);
+#ifdef HAVE_GETOPT_LONG
fprintf(stream,"-b, --block=BLOCK\n");
fprintf(stream,"\t\tBlock definition.\n");
fprintf(stream,"-e, --expression=COMMAND\n");
@@ -515,13 +622,30 @@ help(FILE *stream)
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,"-s, --suppress\n");
+ fprintf(stream,"\t\tSuppress normal output, print only block contents.\n");
fprintf(stream,"-?, --help\n");
- fprintf(stream,"\t\tDisplay this help and exit\n");
+ fprintf(stream,"\t\tDisplay this help and exit.\n");
fprintf(stream,"-V, --Version\n");
- fprintf(stream,"\t\tShow version and exit\n");
+#else
+ fprintf(stream,"-b BLOCK\n");
+ fprintf(stream,"\t\tBlock definition.\n");
+ fprintf(stream,"-e COMMAND\n");
+ fprintf(stream,"\t\tAdd command to the commands to be executed.\n");
+ fprintf(stream,"-f script-file\n");
+ fprintf(stream,"\t\tAdd commands from script-file to the commands to be executed.\n");
+ fprintf(stream,"-o name\n");
+ fprintf(stream,"\t\tWrite output to name instead of standard output.\n");
+ fprintf(stream,"-s\n");
+ fprintf(stream,"\t\tSuppress normal output, print only block contents.\n");
+ fprintf(stream,"-?\n");
+ fprintf(stream,"\t\tDisplay this help and exit.\n");
+ fprintf(stream,"-V\n");
+#endif
+ 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);
+ fprintf(stream,"\nSend bug reports to %s.\n",email_address);
}
void
@@ -547,7 +671,11 @@ main (int argc, char **argv)
int opt;
block.type = 0;
+#ifdef HAVE_GETOPT_LONG
while ((opt = getopt_long(argc,argv,short_opts,long_opts,NULL)) != -1)
+#else
+ while ((opt = getopt(argc,argv,short_opts)) != -1)
+#endif
{
switch(opt)
{
@@ -556,7 +684,7 @@ main (int argc, char **argv)
parse_block(optarg);
break;
case 'e':
- parse_command(optarg);
+ parse_commands(optarg);
break;
case 'f':
parse_command_file(optarg);
@@ -564,6 +692,9 @@ main (int argc, char **argv)
case 'o':
set_output_file(optarg);
break;
+ case 's':
+ output_only_block = 1;
+ break;
case '?':
help(stdout);
exit(EXIT_SUCCESS);
@@ -586,7 +717,7 @@ main (int argc, char **argv)
while(optind < argc) set_input_file(argv[optind++]);
} else
{
- set_input_file(NULL);
+ set_input_file("-");
}
init_buffer();
diff --git a/src/bbe.h b/src/bbe.h
index 93b3e0c..721ad66 100644
--- a/src/bbe.h
+++ b/src/bbe.h
@@ -20,7 +20,7 @@
*
*/
-/* $Id: bbe.h,v 1.15 2005/09/14 15:48:52 timo Exp $ */
+/* $Id: bbe.h,v 1.20 2005/09/25 10:03:47 timo Exp $ */
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -34,6 +34,10 @@
#include <errno.h>
#endif
+#ifdef HAVE_ERROR_H
+#include <error.h>
+#endif
+
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
@@ -113,6 +117,7 @@ struct command {
struct io_file {
char *file;
int fd;
+ off_t start_offset;
struct io_file *next;
};
@@ -203,9 +208,17 @@ execute_program(struct command *c);
extern void
reverse_bytes(size_t count);
+
+extern void
+write_string(char *string);
+
+extern char *
+get_current_file(void);
+
/* 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;
+extern int output_only_block;
diff --git a/src/buffer.c b/src/buffer.c
index f9b45eb..b5798d3 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -20,11 +20,10 @@
*
*/
-/* $Id: buffer.c,v 1.19 2005/09/14 15:48:52 timo Exp $ */
+/* $Id: buffer.c,v 1.25 2005/09/25 10:03:47 timo Exp $ */
#include "bbe.h"
#include <stdlib.h>
-#include <error.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
@@ -34,6 +33,7 @@ struct io_file out_stream;
/* list of input files, points to current file */
struct io_file *in_stream = NULL;
+struct io_file *in_stream_start = NULL;
/* input buffer */
struct input_buffer in_buffer;
@@ -80,6 +80,7 @@ set_input_file(char *file)
if(in_stream == NULL)
{
in_stream = new;
+ in_stream_start = in_stream;
} else
{
curr = in_stream;
@@ -90,7 +91,8 @@ set_input_file(char *file)
curr->next = new;
}
- if(file == NULL)
+ new->start_offset = (off_t) 0;
+ if(file[0] == '-' && file[1] == 0)
{
new->fd = STDIN_FILENO;
new->file = "stdin";
@@ -103,6 +105,28 @@ set_input_file(char *file)
}
}
+/* return the name of current input file */
+char *
+get_current_file(void)
+{
+ struct io_file *f = in_stream_start;
+ struct io_file *prev;
+ off_t current_offset = in_buffer.stream_offset + (off_t) (in_buffer.read_pos-in_buffer.buffer);
+
+ while(f != NULL)
+ {
+ prev = f;
+ f = f->next;
+ if(f != NULL && (f->start_offset == (off_t) 0 || f->start_offset > current_offset))
+ {
+ f = NULL;
+ }
+ }
+ return prev->file;
+}
+
+
+
/* initialize in and out buffers */
void
init_buffer()
@@ -129,6 +153,7 @@ read_input_stream()
if(in_buffer.read_pos == NULL) // first read, so just fill buffer
{
to_be_read = INPUT_BUFFER_SIZE;
+ to_be_saved = 0;
buffer_write_pos = in_buffer.buffer;
in_buffer.stream_offset = (off_t) 0;
} else //we have allready read something
@@ -153,6 +178,8 @@ read_input_stream()
{
if (close(in_stream->fd) == -1) panic("Error in closing file",in_stream->file,strerror(errno));
in_stream = in_stream->next;
+ if (in_stream != NULL)
+ in_stream->start_offset = in_buffer.stream_offset + (off_t) read_count + (off_t) to_be_saved;
}
read_count += last_read;
} while (in_stream != NULL && read_count < to_be_read);
@@ -395,16 +422,29 @@ find_block()
found = 1;
}
}
- if(in_buffer.read_pos > scan_start)
+ if(in_buffer.read_pos > scan_start && !output_only_block)
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(end_of_stream() && !found && !output_only_block) write_output_stream(in_buffer.read_pos,1);
if(found) in_buffer.block_num++;
return found;
}
+/* write null terminated string */
+void
+write_string(char *string)
+{
+ register char *f;
+
+ f = string;
+
+ while(*f != 0) f++;
+
+ write_buffer(string,(off_t) (f - string));
+}
+
/* write_buffer at the current write position */
void
write_buffer(unsigned char *buf,off_t length)
diff --git a/src/execute.c b/src/execute.c
index 5ad5cc0..9d43bc5 100644
--- a/src/execute.c
+++ b/src/execute.c
@@ -20,14 +20,14 @@
*
*/
-/* $Id: execute.c,v 1.12 2005/09/14 17:34:44 timo Exp $ */
+/* $Id: execute.c,v 1.17 2005/09/25 10:03:47 timo Exp $ */
#include "bbe.h"
#include <stdlib.h>
-#include <error.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
+#include <ctype.h>
/* tells if current byte should be deleted */
static int delete_this_byte;
@@ -40,20 +40,79 @@ 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"
+#define BLOCK_START_COMMANDS "DAJLFBN"
/* commands to be executed for each byte */
-#define BYTE_COMMANDS "acdirsywjlJL"
+#define BYTE_COMMANDS "acdirsywjplJL"
/* commands to be executed at end of buffer */
#define BLOCK_END_COMMANDS "IJL"
+
+/* byte_to_string, convert byte value to visible string,
+ either hex (H), decimal (D), octal (O) or ascii (A)
+ */
+char *
+byte_to_string(unsigned char byte,char format)
+{
+ static char string[10];
+
+ switch(format)
+ {
+ case 'H':
+ sprintf(string,"x%02x",(int) byte);
+ break;
+ case 'D':
+ sprintf(string,"% 3d",(int) byte);
+ break;
+ case 'O':
+ sprintf(string,"%03o",(int) byte);
+ break;
+ case 'A':
+ sprintf(string,"%c",isprint(byte) ? byte : ' ');
+ break;
+ default:
+ string[0] = 0;
+ break;
+ }
+ return string;
+}
+
+/* convert off_t to string */
+char *
+off_t_to_string(off_t number,char format)
+{
+ static char string[16];
+
+ switch(format)
+ {
+ case 'H':
+ sprintf(string,"x%llx",(long long) number);
+ break;
+ case 'D':
+ sprintf(string,"%lld",(long long) number);
+ break;
+ case 'O':
+ sprintf(string,"0%llo",(long long) number);
+ break;
+ default:
+ string[0] = 0;
+ break;
+ }
+ return string;
+}
+
+
+
+
/* execute given commands */
void
execute_commands(struct command *c,char *command_letters)
{
register int i;
unsigned char a,b;
+ char *f;
+ char *str;
while(c != NULL)
{
@@ -215,6 +274,39 @@ execute_commands(struct command *c,char *command_letters)
while(c->next != NULL) c = c->next; // skip rest of commands
}
break;
+ case 'p':
+ if (delete_this_byte) break;
+ f = c->s1;
+ while(*f != 0)
+ {
+ str = byte_to_string(read_byte(),*f);
+ write_string(str);
+ f++;
+ if (*f != 0)
+ {
+ put_byte('-');
+ write_next_byte();
+ }
+ }
+ put_byte(' ');
+ break;
+ case 'F':
+ str = off_t_to_string(in_buffer.stream_offset + (off_t) (in_buffer.read_pos-in_buffer.buffer),c->s1[0]);
+ write_string(str);
+ put_byte(':');
+ write_next_byte();
+ break;
+ case 'B':
+ str = off_t_to_string(in_buffer.block_num,c->s1[0]);
+ write_string(str);
+ put_byte(':');
+ write_next_byte();
+ break;
+ case 'N':
+ write_string(get_current_file());
+ put_byte(':');
+ write_next_byte();
+ break;
case 'w':
break;
}
@@ -300,10 +392,10 @@ execute_program(struct command *c)
while(find_block())
{
- delete_this_block = 0;
reset_rpos(c);
- execute_commands(c,BLOCK_START_COMMANDS);
+ delete_this_block = 0;
out_buffer.block_offset = 0;
+ execute_commands(c,BLOCK_START_COMMANDS);
do
{
set_cycle_start();
OpenPOWER on IntegriCloud