diff options
| author | Timo Savinen <tjsa@iki.fi> | 2005-09-25 12:05:00 +0000 |
|---|---|---|
| committer | Hadrien Dorio <hadrien.dorio@gmail.com> | 2017-12-16 00:24:05 +0100 |
| commit | b9eb6e4429575318d3c510b99961093c42321529 (patch) | |
| tree | 997ceb30973318a5cb7da0a78a5a9784d8137e61 | |
| parent | 35d0e8a808dd1382d5236d1f6f8bfe62b2ebefee (diff) | |
| download | binary-block-editor-b9eb6e4429575318d3c510b99961093c42321529.tar.gz binary-block-editor-b9eb6e4429575318d3c510b99961093c42321529.zip | |
0.1.1
| -rw-r--r-- | ChangeLog | 11 | ||||
| -rw-r--r-- | config.h.in | 9 | ||||
| -rwxr-xr-x[-rw-r--r--] | config/texinfo.tex | 0 | ||||
| -rwxr-xr-x | configure | 125 | ||||
| -rw-r--r-- | configure.ac | 5 | ||||
| -rw-r--r-- | doc/bbe.1 | 22 | ||||
| -rw-r--r-- | doc/bbe.info | 116 | ||||
| -rw-r--r-- | doc/bbe.texi | 105 | ||||
| -rw-r--r-- | src/bbe.c | 169 | ||||
| -rw-r--r-- | src/bbe.h | 15 | ||||
| -rw-r--r-- | src/buffer.c | 50 | ||||
| -rw-r--r-- | src/execute.c | 104 |
12 files changed, 650 insertions, 81 deletions
@@ -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 @@ -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. @@ -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 @@ -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(); @@ -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(); |

