diff --git a/.erlang.mk.packages.v2 b/.erlang.mk.packages.v2
deleted file mode 100644
index 8d7554c..0000000
--- a/.erlang.mk.packages.v2
+++ /dev/null
@@ -1,16 +0,0 @@
-bullet git https://github.com/extend/bullet master http://ninenines.eu Simple, reliable, efficient streaming for Cowboy.
-cowboy git https://github.com/ninenines/cowboy 1.0.0 http://ninenines.eu Small, fast and modular HTTP server.
-cowlib git https://github.com/ninenines/cowlib 1.0.0 http://ninenines.eu Support library for manipulating Web protocols.
-eper git https://github.com/massemanet/eper master https://github.com/massemanet/eper Erlang performance and debugging tools.
-epgsql git https://github.com/epgsql/epgsql master https://github.com/epgsql/epgsql Erlang PostgreSQL client library.
-erlydtl git https://github.com/erlydtl/erlydtl master https://github.com/erlydtl/erlydtl Django Template Language for Erlang.
-gun git https://github.com/extend/gun master http//ninenines.eu Asynchronous SPDY, HTTP and Websocket client written in Erlang.
-jiffy git https://github.com/davisp/jiffy master https://github.com/davisp/jiffy JSON NIFs for Erlang.
-jsx git https://github.com/talentdeficit/jsx master https://github.com/talentdeficit/jsx An Erlang application for consuming, producing and manipulating JSON.
-lager git https://github.com/basho/lager master https://github.com/basho/lager A logging framework for Erlang/OTP.
-neo4j git https://github.com/dmitriid/neo4j-erlang master https://github.com/dmitriid/neo4j-erlang Erlang client library for Neo4J.
-pegjs git https://github.com/dmitriid/pegjs 0.2.1 https://github.com/dmitriid/pegjs An implementation of PEG.js grammar for Erlang.
-proper git https://github.com/manopapad/proper master http://proper.softlab.ntua.gr PropEr: a QuickCheck-inspired property-based testing tool for Erlang.
-ranch git https://github.com/ninenines/ranch 1.0.0 http://ninenines.eu Socket acceptor pool for TCP protocols.
-resource_discovery git https://github.com/erlware/resource_discovery master http://erlware.org/ An application used to dynamically discover resources present in an Erlang node cluster.
-sheriff git https://github.com/extend/sheriff master http://ninenines.eu Parse transform for type based validation.
diff --git a/.gitignore b/.gitignore
index 0c20ff0..b969fee 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,8 @@ deps
*.beam
*.plt
erl_crash.dump
+*~
+*.html
+edoc-info
+*.png
+*.css
diff --git a/Makefile b/Makefile
index 3225f17..ba6f203 100644
--- a/Makefile
+++ b/Makefile
@@ -5,5 +5,8 @@ CT_SUITES = swab
include erlang.mk
-eunit:
+eunit: app
erl -noshell -pa `pwd`/ebin -pa `pwd`/priv -eval 'eunit:test(swab, [verbose])' -s init stop
+
+clean::
+ -@find . -type f -name \*~ -delete
diff --git a/README b/README
deleted file mode 100644
index e69de29..0000000
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..7d38708
--- /dev/null
+++ b/README.md
@@ -0,0 +1,169 @@
+# swab #
+
+General purpose buffer handling module.
+
+## Overview ##
+
+swab can :
+
+* cast data and sort lines.
+* decode, encode and convert data, including EBCDIC.
+* catch data that becomes the new current buffer.
+* match data and return the current buffer or otherwise continue next directives, if any.
+* store a buffer queue and maybe use it later to compose another buffer for instance, by merging or concatenating.
+* do diverse specialized (or custom) actions. (Pull requests welcome !).
+
+swab give the possibility to debug all or part of the directive chain, to do hexdump *à la* `od` and also ASN1 pretty printing *à la* `openssl asn1parse`.
+
+swab offer a very easy way to chain directives as you would do by chaining commands with pipes in a shell.
+
+Each step can modify the input buffer that becomes a new current buffer, and so on.
+
+## Documentation ##
+
+A complete documentation is available on all directives.
+
+Simply run `make docs` and open `doc/index.html` in your favorite browser, this will insure you having the documentation related to your version.
+
+## Some examples ##
+
+Bring the penultimate line :
+
+```
+[{jump, -2}, {nblines,1}]
+```
+
+AS400 data received in EBCDIC without linefeed, from 128 characters length records :
+
+```
+[{decode,ebcdic}, {fold, 128}]
+```
+
+Replace UID and GID to 0 in a gzip'ed tar :
+
+```
+[{convert, gunzip}, {tar, fakeroot}, {convert, gzip}]
+```
+
+Merge the two first lines and the last line of a string buffer (explained with debug) :
+
+```
+swab:sync([debug, queue}, {debug, on}, {buffer, in_r}, {nblines, 2}, {buffer, in},
+ {buffer, del}, {jump, -1}, {buffer, in}, {buffer, merge}, {buffer, del}],
+ "Erlang\n is \n not \ngreat !").
+<0.32.0> : {debug,on} => "Erlang\n is \n not \ngreat !"
+ []
+<0.32.0> : {buffer,in_r} => "Erlang\n is \n not \ngreat !"
+ ["Erlang\n is \n not \ngreat !"]
+<0.32.0> : {nblines,2} => "Erlang\n is "
+ ["Erlang\n is \n not \ngreat !"]
+<0.32.0> : {buffer,in} => "Erlang\n is "
+ ["Erlang\n is \n not \ngreat !","Erlang\n is "]
+<0.32.0> : {buffer,del} => "Erlang\n is \n not \ngreat !"
+ ["Erlang\n is "]
+<0.32.0> : {jump,-1} => "great !"
+ ["Erlang\n is "]
+<0.32.0> : {buffer,in} => "great !"
+ ["Erlang\n is ","great !"]
+<0.32.0> : {buffer,merge} => "great !"
+ ["Erlang\n is \ngreat !"]
+<0.32.0> : {buffer,del} => "Erlang\n is \ngreat !"
+ []
+{ok,"Erlang\n is \ngreat !"}
+```
+
+Hexdump debug :
+
+```
+ swab:sync([{debug,hexdump}], "Call me Ishmael. Some years ago--never mind how long precisely --having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world.").
+ <0.32.0> : {debug,hexdump} =>
+ 00000000 43 61 6c 6c 20 6d 65 20 49 73 68 6d 61 65 6c 2e |Call me Ishmael.|
+ 00000010 20 53 6f 6d 65 20 79 65 61 72 73 20 61 67 6f 2d | Some years ago-|
+ 00000020 2d 6e 65 76 65 72 20 6d 69 6e 64 20 68 6f 77 20 |-never mind how |
+ 00000030 6c 6f 6e 67 20 70 72 65 63 69 73 65 6c 79 20 2d |long precisely -|
+ 00000040 2d 68 61 76 69 6e 67 20 6c 69 74 74 6c 65 20 6f |-having little o|
+ 00000050 72 20 6e 6f 20 6d 6f 6e 65 79 20 69 6e 20 6d 79 |r no money in my|
+ 00000060 20 70 75 72 73 65 2c 20 61 6e 64 20 6e 6f 74 68 | purse, and noth|
+ 00000070 69 6e 67 20 70 61 72 74 69 63 75 6c 61 72 20 74 |ing particular t|
+ 00000080 6f 20 69 6e 74 65 72 65 73 74 20 6d 65 20 6f 6e |o interest me on|
+ 00000090 20 73 68 6f 72 65 2c 20 49 20 74 68 6f 75 67 68 | shore, I though|
+ 000000a0 74 20 49 20 77 6f 75 6c 64 20 73 61 69 6c 20 61 |t I would sail a|
+ 000000b0 62 6f 75 74 20 61 20 6c 69 74 74 6c 65 20 61 6e |bout a little an|
+ 000000c0 64 20 73 65 65 20 74 68 65 20 77 61 74 65 72 79 |d see the watery|
+ 000000d0 20 70 61 72 74 20 6f 66 20 74 68 65 20 77 6f 72 | part of the wor|
+ 000000e0 6c 64 2e |ld.|
+ {ok,"Call me Ishmael. Some years ago--never mind how long precisely --having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world."}
+```
+
+ASN1 pretty printing :
+
+```
+ {ok, Der} = file:read_file("/tmp/certificate.der").
+ {ok,<<48,130,3,193,48,130,2,169,160,3,2,1,2,2,9,0,174,28,
+ 240,36,102,146,9,116,48,13,6,...>>}
+
+ swab:sync([{debug, asn1_pp}],Der).
+ <0.36.0> : {debug,asn1_pp} =>
+ SEQUENCE
+ . SEQUENCE
+ . . CONSTRUCTOR
+ . . . INTEGER : 10#2 (16#2)
+ . . . END
+ . . INTEGER : 10#12546166701077694836 (16#AE1CF02466920974)
+ . . SEQUENCE
+ . . . OBJECT : {1,2,840,113549,1,1,5}
+ . . . NULL : <<>>
+ . . . END
+ . . SEQUENCE
+ . . . SET
+ . . . . SEQUENCE
+ . . . . . OBJECT : {2,5,4,6}
+ . . . . . PRINTABLESTRING : FR
+ . . . . . END
+ . . . . END
+ . . . SET
+ . . . . SEQUENCE
+ . . . . . OBJECT : {2,5,4,8}
+ . . . . . VALUE : Some-State
+ . . . . . END
+ . . . . END
+
+ ---- snip snip -----
+
+ . . SEQUENCE
+ . . . UTCTIME : 120708104913Z (2012-07-08 12:49:13 UTC+2)
+ . . . UTCTIME : 281211104913Z (2028-12-11 11:49:13 UTC+2)
+ . . . END
+
+ ---- snip snip -----
+
+ . . CONSTRUCTOR
+ . . . SEQUENCE
+ . . . . SEQUENCE
+ . . . . . OBJECT : {2,5,29,14}
+ . . . . . OCTET STRING :
+ 00000000 04 14 cd 81 ab 5c e1 59 b1 a4 f3 4d a1 9a 7e ab |.....\.Y...M..~.|
+ 00000010 ea fc 14 45 19 40 |...E.@|
+ . . . . . END
+
+ ---- snip snip -----
+
+ . END
+ END
+ {ok,<<48,130,3,193,48,130,2,169,160,3,2,1,2,2,9,0,174,28,
+ 240,36,102,146,9,116,48,13,6,...>>}
+```
+
+## Quick Start ##
+
+```
+git clone git://github.com/crownedgrouse/swab.git
+cd swab
+make
+erl -pa `pwd`/ebin
+```
+
+## Contributing ##
+
+Contributions are welcome. Please use pull-requests.
+
diff --git a/doc/edoc-info b/doc/edoc-info
deleted file mode 100644
index 6209eeb..0000000
--- a/doc/edoc-info
+++ /dev/null
@@ -1,4 +0,0 @@
-%% encoding: UTF-8
-{application,swab}.
-{packages,[]}.
-{modules,[swab,swab_tests]}.
diff --git a/doc/erlang.png b/doc/erlang.png
deleted file mode 100644
index 987a618..0000000
Binary files a/doc/erlang.png and /dev/null differ
diff --git a/doc/index.html b/doc/index.html
deleted file mode 100644
index c38816e..0000000
--- a/doc/index.html
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-The swab application
-
-
-
-
-
-
-This page uses frames
-Your browser does not accept frames.
- You should go to the non-frame version instead.
-
-
-
-
\ No newline at end of file
diff --git a/doc/modules-frame.html b/doc/modules-frame.html
deleted file mode 100644
index b5154f5..0000000
--- a/doc/modules-frame.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-The swab application
-
-
-
-Modules
-
-
-
\ No newline at end of file
diff --git a/doc/overview-summary.html b/doc/overview-summary.html
deleted file mode 100644
index b046308..0000000
--- a/doc/overview-summary.html
+++ /dev/null
@@ -1,578 +0,0 @@
-
-
-
-
-Welcome to the swab module documentation !
-
-
-
-
-Welcome to the swab module documentation !
-Copyright © 2014 crownedgrouse.com
-Version: 1.0.0
-Authors: Eric Pailleau (swab@crownedgrouse.com ).
-swab
is a general purpose buffer handling module
-
-
-The origin of this module was the need to solve a not so unusual concern : an external program was exiting always 0 even on error.
-The lone way to know the status of the commands was to analyse stdout and stderr.
-
-The program has disappeared, but the module remained. It was then augmented with several refactoring and converting features, that use Erlang BIF or not,
-and became a more generic tool.
-
-A kind of S wiss knife W orking A ll B uffers ...
-
-More seriously, module name comes from the relationship with the word buffer
and also from the act of reordering data to compensate for Endian incompatibilities.
-
-
-
-swab
can cast data and sort lines. See Refactoring
-
-swab
can decode, encode and convert data, including several EBCDIC flavours. See Encoding / Converting
-
-swab
can catch data that becomes the new current buffer. See Catching data
-
-swab
can match data and return the current buffer or otherwise continue next directives, if any. See Matching data
-
-swab
can store a buffer queue and maybe use it later to compose another buffer for instance, by merging or concatenating. See Buffers handling
-
-swab
can do diverse specialized actions. (Pull requests welcome !). See Misc
-
-swab
give the possibility to debug all or part of the directive chain, to do hexdump "à la" od
and also ASN1 pretty printing "à la" openssl asn1parse
. See Debugging / Pretty printing
-
-swab
offer a very easy way to chain directives as you would do by chaining commands with pipes in a shell.
-Each step can modify the input buffer that becomes a new current buffer, and so on. See Examples
-
-
-
-Dialyzer, Unit tests and Common tests are used to insure the maximum quality.
-If however you find a bug, please signal it on the GitHub page by opening an issue ticket, or better, fix it and propose a Pull Request.
-Features addition are welcome too.
-
-note : Unit tests are only done on directives that are not using BIFs.
-
-
-
-
-
-Only three tuple forms can be expected for sync/1 or sync/2 functions return:
-
-{ok, Buffer}
where Buffer is the last buffer.
-
-{match, MatchingDirective, Buffer}
where Buffer is the current buffer when the match is found.
-
-{error, OffendingDirective , Message}
where Message is a reason string.
-
-Note, if no matching directive is used, it is not necessary to expect match
tuple in your code.
-
-Be careful, some directive returned in match
or error
tuple, might have been modified, mainly to add default options (see regexp
directive, for example). In below documentation, those directives have a star * at end of argument that is possibly rewritten. However you have to take care of this only if more than one matching directive is used in the chain and different actions must be done depending the matching directive returned.
-
-
-
-
-
-Cast the current buffer content to uppercase.
-
- swab:sync({cast, upper },"I love Erlang !").
- {ok, "I LOVE ERLANG !"}
-
-
-Cast the current buffer content to lowercase.
-
- swab:sync({cast, lower },"I love Erlang !").
- {ok, "i love erlang !"}
-
-
- Mode = Sens | {Sens, Char}
- Sens = left | right | both
- Char = integer()
-
-* : Default to blank character ({Sens, $\040}
)
-
-Trim buffer left, right or both. Another character than blank can be used by setting it in second argument of tuple.
-
- swab:sync({trim, both }," I love Erlang ! ").
- {ok, "I love Erlang !"}
-
- swab:sync({trim, left }," I love Erlang ! ").
- {ok, "I love Erlang ! "}
-
- swab:sync({trim, right }," I love Erlang ! ").
- {ok, " I love Erlang !"}
-
- swab:sync({trim, {both, $.} },".................").
- {ok, []}
-
-
- Mode = integer() | {integer(), Char}
- Char = integer()
-
-* : Default is set to {integer(), $\040}
-
-Feed buffer lines up to integer()
length with blanks, by default, or with Char
character.
-If integer() < 0, feeding is done at beginning of lines.
-
-Warning : Any new lines will be normalized to local new lines !
-
- swab:sync({feed,10}, "abc\nadcdefghij\n12345678\n987654321").
- {ok,"abc \nadcdefghij\n12345678 \n987654321 "}
-
- swab:sync({feed, {10, $*}}, "abc\nadcdefghij\n12345678\n987654321").
- {ok,"abc*******\nadcdefghij\n12345678**\n987654321*"}
-
- swab:sync({feed, {-10, $*}}, "abc\nadcdefghij\n12345678\n987654321").
- {ok,"*******abc\nadcdefghij\n**12345678\n*987654321"}
-
-
-
-Fold buffer with local newlines, to fit in specified line width.
-
-Warning : DOS newlines \r\n should be normalized to a single character new lines (probably \n) before,
-or a local newline could be inserted between \r and \n.
-
- swab:sync({fold, 10}, "1234567890123456789abcdefghijkl") .
- {ok,"1234567890\n123456789a\nbcdefghijk\nl"}
-
- swab:sync({fold, 10}, "1234567\n890123456789abc\ndefghijkl") .
- {ok,"1234567\n89\n0123456789\nabc\ndefghi\njkl"}
-
-
-Mode = normal | reverse | inverse
-
-Sorting current buffer.
-
-
- normal
: normal alphabetic sort. Tip : ISO dates starting log lines are sorted nicely with this directive...
- reverse
: reverse normal alphabetic sort. Same as [{sort, normal}, {sort,inverse}]
- inverse
: inverse line order from last line to first line.
-
-
- swab:sync({sort, normal}, "aaa\nccc\nbbb\nddd\n").
- {ok,"aaa\nbbb\nccc\nddd"}
-
- swab:sync({sort, reverse}, "aaa\nccc\nbbb\nddd\n").
- {ok,"ddd\nccc\nbbb\naaa"}
-
- swab:sync({sort, inverse}, "aaa\nccc\nbbb\nddd\n").
- {ok,"ddd\nbbb\nccc\naaa"}
-
-
-
-
-
-Type = latin1 | unicode | utf8 | utf16 | utf32 | {utf16, big} | {utf16, little} | {utf32, big} | {utf32, little} | ebcdic
-
-Decode current buffer to Unicode.
-Converts the current buffer from the given format to pure Unicode. The purpose of the function is mainly to be able to convert combinations of unicode characters into a pure unicode string.
-
-Except ebcdic
, all other types use Erlang BIFs, from unicode module.
-
-
-Type = latin1 | unicode | utf8 | utf16 | utf32 | {utf16, big} | {utf16, little} | {utf32, big} | {utf32, little} | ebcdic
-
-Encode current buffer from Unicode to something.
-
-Except ebcdic
, all other types use Erlang BIFs, from unicode module.
-
-
-Type = der | pem | base64 | mime | uncompress | unzip | gunzip | compress | zip | gzip | nonl | local_nl
-
-Convertion of current buffer.
-
-
- der | pem
convert x509 certificate to der or pem, assuming the buffer contains the contrary (i.e pem or der).
- base64 | mime
Same as 'decode' but for base64 encoding and mime RFC4648.
- 'mime' strips away illegal characters, while 'base64' only strips
- away whitespace characters.
-
- uncompress | unzip | gunzip | compress | zip | gzip
- Same as a) but for main compression algorithms.
-
- uncompress
: Uncompress a binary (with zlib headers and checksum).
- unzip
: Uncompress a binary (without zlib headers and checksum).
- gunzip
: Uncompress a binary (with gz headers and checksum).
-
-
-
- nonl
Removes any new lines separators whatever the OS type
- (\r
, \r\n
, \n
but also \f
, \x85
and \x0b
).
-
- local_nl
Convert any new lines to local new lines.
-
-
-Except nonl
and local_nl
, all other types use Erlang BIFs, from several modules.
-
-
-
-
-
-Returns the word in position Integer of String in current buffer. Words are separated by blanks.
-
- swab:sync({sub_word, 3 },"I love Erlang !").
- {ok, "Erlang"}
-
-
-Mode = integer() | first | last
-
-Line jumping on current buffer.
-
- [integer()]
Jump to the given line number and bring only lines after.
-
- Be carefull, if line does not exist, it will empty the buffer !
- Negative value will bring the lines from the end.
- zero will bring all the lines.
-
-
- [last|first]
: Bring only the last/first line of current buffer.
-
-Warning : Any new lines will be normalized to local new lines !
-
- swab:sync({jump, last },"Definitely...\nI love Erlang !").
- {ok,"I love Erlang !"}
-
- swab:sync({jump, first },"Definitely...\nI love Erlang !").
- {ok,"Definitely..."}
-
- swab:sync({jump, 1 },"Definitely...\nI love Erlang !").
- {ok,"I love Erlang !"}
-
- swab:sync({jump, 2 },"Definitely...\nI love Erlang !").
- {ok,[]}
-
- swab:sync({jump, -1 },"Definitely...\nI love Erlang !").
- {ok,"I love Erlang !"}
-
-
-
-Get a number of lines from current buffer.
-
- forward in buffer if > 0
- from end in buffer if < 0
- 1 pick-up the first line only
- 0 clear the buffer !
-
-Can be used in conjunction with 'jump' before in order to discard unwanted lines. Lines found becomes the next current buffer.
-
- swab:sync({nblines, 1 },"Definitely...\nReally...\nI love Erlang !").
- {ok,"Definitely..."}
-
- swab:sync({nblines, 2 },"Definitely...\nReally...\nI love Erlang !").
- {ok,"Definitely...\nReally..."}
-
- swab:sync({nblines, -1 },"Definitely...\nReally...\nI love Erlang !").
- {ok,"I love Erlang !"}
-
-
-
- Mode = Regexp | mp() | {mp(), compile_option()} | {Regexp , compile_option()}
- Regexp = iodata()| unicode:charlist()
- mp() = {re_pattern, term(), term(), term(), term()}
- compile_option() = See re module compile options
-
-* : Default compile option is [{capture, all_but_first, list}]
.
-
-Warning : usage of some compile options may produce exceptions due to unexpected return value. Use at your own risk.
-
-Grab data from catching regular expression which becomes the next current buffer, or final return if last directive.
-
- swab:sync({grab, "^(...)"},"abcdefg").
- {ok,"abc"}
-
-If several catching expressions are used and matching, all the strings found are concatenated :
-
- swab:sync({grab, "^(...)..(.)"},"abcdefg").
- {ok,"abcf"}
-
-
-
-
-
-
-Comp = string() | binary()
-
-Simple string (or binary) comparison. If a match is found against the current buffer, a tuple {match, Directive, Buffer}
is returned and all next directives are ignored.
-
-In case of multiline buffer, String must include exact same newline separator : "abc\ndef" does not match neither "abc\r\ndef" nor "abcdef".
-
-Be carefull of buffer type : {equal, <<"abcdef">>}
will not match "abcdef"
.
-
-
-
-Try to read buffer in accordance with the formating control sequences of String. If a match is found against the current buffer, a tuple {match, Directive, Buffer}
is returned and all next directives are ignored. Incomplete matches are not considered valid.
-
-{fread, "~f~f~f"}
matches "1.9 35.5e3 15.0"
-
-{fread, "~10f~d"}
matches " 5.67899"
-
-{fread, ":~10s:~10c:"}
matches ": alan : joe :"
-
-
-
- Mode = Regexp | mp() | {mp(), compile_option()} | {Regexp , compile_option()}
- Regexp = iodata()| unicode:charlist()
- mp() = {re_pattern, term(), term(), term(), term()}
- compile_option() = See re module compile options
-
-* : Default compile option is []
, and if no compile options are set, the directive will be rewritten to {regexp, {Regexp | mp(), []}}
.
-If a match is found, this rewritten directive will be returned as second argument of match tuple.
-
-Warning : usage of some compile options may produce exceptions due to unexpected return value. Use at your own risk.
-
-Match data with regular expression. If directive is matching on the current buffer, a tuple {match, Directive, Buffer}
is returned and all next directives are ignored.
-
-
- swab:sync({regexp, ".*"},"abcdefg").
- {match, {regexp, {".*",[]}},"abcdefg"}
-
-The below (dummy) chain will not apply the last directive, but return at second directive :
-
- swab:sync([{cast, upper}, {regexp, "^[A-Z]"}, {cast, lower}], "abcdefg").
- {match, {regexp, {"^[A-Z]",[]}},"ABCDEFG"}
-
-while
-
- swab:sync([{regexp, "^[1-9]"}, {cast, lower}, {regexp, "^[a-z]"}], "ABCDEFG").
- {match, {regexp, {"^[a-z]",[]}},"abcdefg"}
-
-If more than one match directive is used, the second argument of the tuple returned might be used to know which directive has matched.
-
-
-
-
-Buffer handing allow complexes data manipulations, mainly to compose a buffer from part of a first big input buffer,
-but also by adding external data in the directive chain.
-
-Note : the current buffer is not part of a buffer queue, unless action.
-
-
-Copy current buffer at the rear (tail) of queue, and left current buffer unchanged.
-
-
-Copy current buffer at the front (head) of queue, and left current buffer unchanged.
-
-
-Get and removes the saved buffer at the front (head) of queue.
-The extracted buffer becomes then the current buffer, while current is saved in REAR of queue if non empty.
-
-
-Get and removes the saved buffer at the rear (tail) of the queue.
-The extracted buffer becomes then the current buffer, while current is saved in FRONT of queue if non empty.
-
-
-Delete the current buffer.
-Next buffer will be the first in queue (head), if any.
-
-
-Delete the current buffer.
-Next buffer will be the last in queue (tail), if any.
-
-
-Merge all buffers in only one buffer in queue, from head to tail.
-Current buffer is left unchanged !
-Local newlines are separating merged buffers.
-
-
-Merge all queued buffers in only one buffer in queue, but reverse order, i.e from tail to head.
-Current buffer is left unchanged !
-Local newlines are separating merged buffers.
-
-
-Concatenate all queued buffers in only one buffer in queue.
-Current buffer is left unchanged !
-
-
-Concatenate all buffers in only one buffer in queue, but reverse order.
-Current buffer is left unchanged !
-
-
-Data = string() | binary()
-Push data as new current buffer in your directive chain (current buffer is overwritten).
-The last buffer before this directive might have been saved in buffer queue, in order to compose another buffer with the data that is pushed.
-Considere also store
and store_r
in such case.
-
-
-Data = string() | binary()
-Push data directly in front (head) of buffer queue.
-Current buffer is left unchanged.
-Same as [..., {buffer, in_r}, {push, Data}, {buffer, in}, {buffer, del_r}, ...]
but more efficient.
-
-
-Push data directly in rear (tail) of buffer queue.
-Current buffer is left unchanged.
-Same as [..., {buffer, in}, {push, Data}, {buffer, in_r}, {buffer, del}, ...]
but more efficient.
-
-
-
-
-
-Mode = on | hexdump | asn1_pp | off | queue
-
-Debug can be set on and off at any place in the directive chain. Usefull when wanting to debug only a particular directive.
-
-The value queue
tells swab
to debug the buffer queue too, but needs on
to be active.
-Queue is displayed as a list, the head is the most left and tail is the most right.
-Use off
, then on
to reset to simple debugging.
-
-Basic debug :
-
- swab:sync([{debug,on}], "Call me Ishmael. Some years ago--never mind how long precisely --having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world.").
- <0.32.0> : {debug,on} => "Call me Ishmael. Some years ago--never mind how long precisely --having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world."
- {ok,"Call me Ishmael. Some years ago--never mind how long precisely --having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world."}
-
-Hexdump debug :
-
- swab:sync([{debug,hexdump}], "Call me Ishmael. Some years ago--never mind how long precisely --having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world.").
- <0.32.0> : {debug,hexdump} =>
- 00000000 43 61 6c 6c 20 6d 65 20 49 73 68 6d 61 65 6c 2e |Call me Ishmael.|
- 00000010 20 53 6f 6d 65 20 79 65 61 72 73 20 61 67 6f 2d | Some years ago-|
- 00000020 2d 6e 65 76 65 72 20 6d 69 6e 64 20 68 6f 77 20 |-never mind how |
- 00000030 6c 6f 6e 67 20 70 72 65 63 69 73 65 6c 79 20 2d |long precisely -|
- 00000040 2d 68 61 76 69 6e 67 20 6c 69 74 74 6c 65 20 6f |-having little o|
- 00000050 72 20 6e 6f 20 6d 6f 6e 65 79 20 69 6e 20 6d 79 |r no money in my|
- 00000060 20 70 75 72 73 65 2c 20 61 6e 64 20 6e 6f 74 68 | purse, and noth|
- 00000070 69 6e 67 20 70 61 72 74 69 63 75 6c 61 72 20 74 |ing particular t|
- 00000080 6f 20 69 6e 74 65 72 65 73 74 20 6d 65 20 6f 6e |o interest me on|
- 00000090 20 73 68 6f 72 65 2c 20 49 20 74 68 6f 75 67 68 | shore, I though|
- 000000a0 74 20 49 20 77 6f 75 6c 64 20 73 61 69 6c 20 61 |t I would sail a|
- 000000b0 62 6f 75 74 20 61 20 6c 69 74 74 6c 65 20 61 6e |bout a little an|
- 000000c0 64 20 73 65 65 20 74 68 65 20 77 61 74 65 72 79 |d see the watery|
- 000000d0 20 70 61 72 74 20 6f 66 20 74 68 65 20 77 6f 72 | part of the wor|
- 000000e0 6c 64 2e |ld.|
- {ok,"Call me Ishmael. Some years ago--never mind how long precisely --having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world."}
-
-ASN1 pretty printing :
-
- {ok, Der} = file:read_file("/tmp/certificate.der").
- {ok,<<48,130,3,193,48,130,2,169,160,3,2,1,2,2,9,0,174,28,
- 240,36,102,146,9,116,48,13,6,...>>}
-
- swab:sync([{debug, asn1_pp}],Der).
- <0.36.0> : {debug,asn1_pp} =>
- SEQUENCE
- . SEQUENCE
- . . CONSTRUCTOR
- . . . INTEGER : 10#2 (16#2)
- . . . END
- . . INTEGER : 10#12546166701077694836 (16#AE1CF02466920974)
- . . SEQUENCE
- . . . OBJECT : {1,2,840,113549,1,1,5}
- . . . NULL : <<>>
- . . . END
- . . SEQUENCE
- . . . SET
- . . . . SEQUENCE
- . . . . . OBJECT : {2,5,4,6}
- . . . . . PRINTABLESTRING : FR
- . . . . . END
- . . . . END
- . . . SET
- . . . . SEQUENCE
- . . . . . OBJECT : {2,5,4,8}
- . . . . . VALUE : Some-State
- . . . . . END
- . . . . END
-
- ---- snip snip -----
-
- . . SEQUENCE
- . . . UTCTIME : 120708104913Z (2012-07-08 12:49:13 UTC+2)
- . . . UTCTIME : 281211104913Z (2028-12-11 11:49:13 UTC+2)
- . . . END
-
- ---- snip snip -----
-
- . . CONSTRUCTOR
- . . . SEQUENCE
- . . . . SEQUENCE
- . . . . . OBJECT : {2,5,29,14}
- . . . . . OCTET STRING :
- 00000000 04 14 cd 81 ab 5c e1 59 b1 a4 f3 4d a1 9a 7e ab |.....\.Y...M..~.|
- 00000010 ea fc 14 45 19 40 |...E.@|
- . . . . . END
-
- ---- snip snip -----
-
- . END
- END
- {ok,<<48,130,3,193,48,130,2,169,160,3,2,1,2,2,9,0,174,28,
- 240,36,102,146,9,116,48,13,6,...>>}
-
-
-
-
-
-Use your own mfa() to treat or match the current buffer.
-The current buffer will be added as last argument of the function.
-The returned value becomes the new current buffer, but only if it is list() or binary().
-Any other term raise an error.
-If the mfa() is used to match a buffer, please throw an exception : throw(match) .
-swab
will then return the usual {match, {mfa, {M, F, A}}, Buffer}
.
-
-Note : If you think your custom treatment/match module would be usefull for other people, please integrate it in swab and propose a pull request !
-
-
-Replace all UID/GID to 0 in a (valid) gnu tar buffer.
-Same as [{tar, {0, "root"}}, {tar, {"root",0}}]
but more efficient (buffer treated only once).
-
-
-UserName = list()
-Uid = integer()
-Replace all Uid and user name in a (valid) gnu tar buffer.
-
-
-GroupName = list()
-Gid = integer()
-Replace all Gid and group name in a (valid) gnu tar buffer.
-
-
-
-
-Bring the penultimate line :
-
- [{jump, -2}, {nblines,1}]
-
-
-AS400 data received in EBCDIC without linefeed, from 128 characters length records :
-
- [{decode,ebcdic}, {fold, 128}]
-
-
-Replace UID and GID to 0 in a gzip'ed tar :
-
- [{convert, gunzip}, {fakeroot, tar}, {convert, gzip}]
-
-
-Merge the two first lines and the last line of a string buffer (explained with debug) :
-
-swab:sync([debug, queue}, {debug, on}, {buffer, in_r}, {nblines, 2}, {buffer, in},
- {buffer, del}, {jump, -1}, {buffer, in}, {buffer, merge}, {buffer, del}],
- "Erlang\n is \n not \ngreat !").
-<0.32.0> : {debug,on} => "Erlang\n is \n not \ngreat !"
- []
-<0.32.0> : {buffer,in_r} => "Erlang\n is \n not \ngreat !"
- ["Erlang\n is \n not \ngreat !"]
-<0.32.0> : {nblines,2} => "Erlang\n is "
- ["Erlang\n is \n not \ngreat !"]
-<0.32.0> : {buffer,in} => "Erlang\n is "
- ["Erlang\n is \n not \ngreat !","Erlang\n is "]
-<0.32.0> : {buffer,del} => "Erlang\n is \n not \ngreat !"
- ["Erlang\n is "]
-<0.32.0> : {jump,-1} => "great !"
- ["Erlang\n is "]
-<0.32.0> : {buffer,in} => "great !"
- ["Erlang\n is ","great !"]
-<0.32.0> : {buffer,merge} => "great !"
- ["Erlang\n is \ngreat !"]
-<0.32.0> : {buffer,del} => "Erlang\n is \ngreat !"
- []
-{ok,"Erlang\n is \ngreat !"}
-
-
-
-
-
-
-
-Generated by EDoc, Aug 12 2014, 23:14:32.
-
-
diff --git a/doc/overview.edoc b/doc/overview.edoc
index 8a7aad4..cf71f65 100644
--- a/doc/overview.edoc
+++ b/doc/overview.edoc
@@ -17,17 +17,20 @@ More seriously, module name comes from the relationship with the word `buffer' a
== Abstract ==
-`swab' can cast data and sort lines. See {@section Refactoring}
+`swab' can :
+
+ cast data and sort lines. See {@section Refactoring}
-`swab' can decode, encode and convert data, including several EBCDIC flavours. See {@section Encoding / Converting}
+ decode, encode and convert data, including EBCDIC. See {@section Encoding / Converting}
-`swab' can catch data that becomes the new current buffer. See {@section Catching data}
+ catch data that becomes the new current buffer. See {@section Catching data}
-`swab' can match data and return the current buffer or otherwise continue next directives, if any. See {@section Matching data}
+ match data and return the current buffer or otherwise continue next directives, if any. See {@section Matching data}
-`swab' can store a buffer queue and maybe use it later to compose another buffer for instance, by merging or concatenating. See {@section Buffers handling}
+ store a buffer queue and maybe use it later to compose another buffer for instance, by merging or concatenating. See {@section Buffers handling}
-`swab' can do diverse specialized actions. (Pull requests welcome !). See {@section Misc}
+ do diverse specialized (or custom) actions. (Pull requests welcome !). See {@section Misc}
+
`swab' give the possibility to debug all or part of the directive chain, to do hexdump "à la" ``od'' and also ASN1 pretty printing "à la" ``openssl asn1parse''. See {@section Debugging / Pretty printing}
@@ -36,7 +39,7 @@ Each step can modify the input buffer that becomes a new current buffer, and so
== Quality ==
-Dialyzer, Unit tests and Common tests are used to insure the maximum quality.
+Dialyzer and Unit tests are used to insure the maximum quality.
If however you find a bug, please signal it on the GitHub page by opening an issue ticket, or better, fix it and propose a Pull Request.
Features addition are welcome too.
@@ -167,7 +170,7 @@ Encode current buffer from Unicode to something.
Except ``ebcdic'', all other types use Erlang BIFs, from unicode module.
==== {convert, Type} ====
-``Type = der | pem | base64 | mime | uncompress | unzip | gunzip | compress | zip | gzip | nonl | local_nl''
+``Type = der | pem | base64 | mime | uncompress | unzip | gunzip | compress | zip | gzip | nonl | local_nl | swab''
Convertion of current buffer.
@@ -178,7 +181,7 @@ Convertion of current buffer.
away whitespace characters.
``uncompress | unzip | gunzip | compress | zip | gzip''
- Same as a) but for main compression algorithms.
+ Same as b) but for main compression algorithms.
``uncompress'' : Uncompress a binary (with zlib headers and checksum).
``unzip'' : Uncompress a binary (without zlib headers and checksum).
@@ -190,9 +193,10 @@ Convertion of current buffer.
(``\r'', ``\r\n'', ``\n'' but also ``\f'', ``\x85'' and ``\x0b'').
``local_nl'' Convert any new lines to local new lines.
+ ``swab'' Exchange adjacent even and odd bytes. Bytes number should be even, or last byte left unchanged.
-Except ``nonl'' and ``local_nl'' , all other types use Erlang BIFs, from several modules.
+Except ``nonl'', ``local_nl'' and ``swab'', all other types use Erlang BIFs, from several modules.
=== Catching data ===
@@ -204,27 +208,18 @@ Returns the word in position Integer of String in current buffer. Words are sepa
{ok, "Erlang"}'''
==== {jump, Mode} ====
-``Mode = integer() | first | last''
+``Mode = integer()''
Line jumping on current buffer.
-
- ``[integer()]'' Jump to the given line number and bring only lines after.
+Jump to the given line number and bring only lines after.
Be carefull, if line does not exist, it will empty the buffer !
Negative value will bring the lines from the end.
zero will bring all the lines.
-
- ``[last|first]'' : Bring only the last/first line of current buffer.
-
Warning : Any new lines will be normalized to local new lines !
-```swab:sync({jump, last },"Definitely...\nI love Erlang !").
- {ok,"I love Erlang !"}
-
- swab:sync({jump, first },"Definitely...\nI love Erlang !").
- {ok,"Definitely..."}
-
+```
swab:sync({jump, 1 },"Definitely...\nI love Erlang !").
{ok,"I love Erlang !"}
@@ -234,7 +229,8 @@ Warning : Any new lines will be normalized to local new lines !
swab:sync({jump, -1 },"Definitely...\nI love Erlang !").
{ok,"I love Erlang !"}'''
-==== {nblines, integer() } ====
+==== {nblines, Mode } ====
+``Mode = integer() | first | last ''
Get a number of lines from current buffer.
@@ -242,6 +238,7 @@ Get a number of lines from current buffer.
from end in buffer if < 0
1 pick-up the first line only
0 clear the buffer !
+ ``last|first'' : Bring only the last/first line of current buffer.
Can be used in conjunction with 'jump' before in order to discard unwanted lines. Lines found becomes the next current buffer.
@@ -536,7 +533,7 @@ AS400 data received in EBCDIC without linefeed, from 128 characters length recor
Replace UID and GID to 0 in a gzip'ed tar :
-```[{convert, gunzip}, {fakeroot, tar}, {convert, gzip}]'''
+```[{convert, gunzip}, {tar, fakeroot}, {convert, gzip}]'''
Merge the two first lines and the last line of a string buffer (explained with debug) :
diff --git a/doc/packages-frame.html b/doc/packages-frame.html
deleted file mode 100644
index 8cbb81f..0000000
--- a/doc/packages-frame.html
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-The swab application
-
-
-
-Packages
-
-
-
\ No newline at end of file
diff --git a/doc/stylesheet.css b/doc/stylesheet.css
deleted file mode 100644
index e426a90..0000000
--- a/doc/stylesheet.css
+++ /dev/null
@@ -1,55 +0,0 @@
-/* standard EDoc style sheet */
-body {
- font-family: Verdana, Arial, Helvetica, sans-serif;
- margin-left: .25in;
- margin-right: .2in;
- margin-top: 0.2in;
- margin-bottom: 0.2in;
- color: #000000;
- background-color: #ffffff;
-}
-h1,h2 {
- margin-left: -0.2in;
-}
-div.navbar {
- background-color: #add8e6;
- padding: 0.2em;
-}
-h2.indextitle {
- padding: 0.4em;
- background-color: #add8e6;
-}
-h3.function,h3.typedecl {
- background-color: #add8e6;
- padding-left: 1em;
-}
-div.spec {
- margin-left: 2em;
- background-color: #eeeeee;
-}
-a.module,a.package {
- text-decoration:none
-}
-a.module:hover,a.package:hover {
- background-color: #eeeeee;
-}
-ul.definitions {
- list-style-type: none;
-}
-ul.index {
- list-style-type: none;
- background-color: #eeeeee;
-}
-
-/*
- * Minor style tweaks
- */
-ul {
- list-style-type: square;
-}
-table {
- border-collapse: collapse;
-}
-td {
- padding: 3
-}
diff --git a/doc/swab.html b/doc/swab.html
deleted file mode 100644
index cd1f5e5..0000000
--- a/doc/swab.html
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-
-
-Module swab
-
-
-
-
-
-
-Module swab
-
- General purpose buffer handling.
-Copyright © 2014 crownedgrouse.com
-
-Authors: Eric Pailleau (swab@crownedgrouse.com ).
-
-
- General purpose buffer handling
-
-async/2 Apply rules asynchronously, and send result to caller Pid.
-async/3 Apply rules asynchronously, but send result to a Pid.
-sync/2 Apply rules and return synchronously.
-sync/3 Apply rules and return synchronously, but send result to a Pid.
-
-
-
-
-
-
-
async(Rules::list() | tuple(), Buffer::iolist()) -> tuple()
-
Apply rules asynchronously, and send result to caller Pid
-
-
-
-
async(Rules, Buffer, Pid) -> any()
-
Apply rules asynchronously, but send result to a Pid
-
-
-
-
sync(Rules::list() | tuple(), Buffer::iolist()) -> tuple()
-
Apply rules and return synchronously
-
-
-
-
sync(Rules, Buffer, Pid) -> any()
-
Apply rules and return synchronously, but send result to a Pid
-
-
-
-Generated by EDoc, Aug 12 2014, 23:14:32.
-
-
diff --git a/doc/swab_tests.html b/doc/swab_tests.html
deleted file mode 100644
index 3bac75a..0000000
--- a/doc/swab_tests.html
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-Module swab_tests
-
-
-
-
-
-
-Module swab_tests
-
- General purpose buffer handling - Unit tests.
-Copyright © 2014 crownedgrouse.com
-
-Authors: Eric Pailleau (swab@crownedgrouse.com ).
-
-
- General purpose buffer handling - Unit tests
-
-
-Generated by EDoc, Aug 12 2014, 23:14:32.
-
-
diff --git a/erlang.mk b/erlang.mk
index 8056706..fcd8eaf 100644
--- a/erlang.mk
+++ b/erlang.mk
@@ -61,15 +61,10 @@ help::
"Setting V=1 when calling make enables verbose mode."
# Core functions.
-ifeq ($(shell which wget | wc -l), 1)
+
define core_http_get
wget --no-check-certificate -O $(1) $(2)|| rm $(1)
endef
-else
-define core_http_get
- @erl -noshell -eval ' try case http_uri:parse("$(2)") of {ok, _} -> ok ; {error, R1} -> throw(R1), error; _ -> ok end, ssl:start(), inets:start(), case httpc:request(get, {"$(2)", []}, [], []) of {ok, {{_V, 200, _R}, _Headers, Body}} -> io:format(Body) ; {error, R2} -> throw(R2), error end, halt(0) catch throw:Term -> io:format(standard_error,"error: ~p~n", [Term]) end, halt(1). ' > $(1) || rm $(1)
-endef
-endif
# Copyright (c) 2013-2014, Loïc Hoguin
# This file is part of erlang.mk and subject to the terms of the ISC License.
@@ -119,7 +114,11 @@ define dep_fetch
if [ "$$$$VS" = "git" ]; then \
git clone -n -- $$$$REPO $(DEPS_DIR)/$(1); \
cd $(DEPS_DIR)/$(1) && git checkout -q $$$$COMMIT; \
+ elif [ "$$$$VS" = "hg" ]; then \
+ hg clone -U $$$$REPO $(DEPS_DIR)/$(1); \
+ cd $(DEPS_DIR)/$(1) && hg update -q $$$$COMMIT; \
else \
+ echo "Unknown or invalid dependency: $(1). Please consult the erlang.mk README for instructions." >&2; \
exit 78; \
fi
endef
@@ -129,13 +128,13 @@ $(DEPS_DIR)/$(1):
@mkdir -p $(DEPS_DIR)
@if [ ! -f $(PKG_FILE2) ]; then $(call core_http_get,$(PKG_FILE2),$(PKG_FILE_URL)); fi
ifeq (,$(dep_$(1)))
- DEPPKG=$$$$(awk 'BEGIN { FS = "\t" }; $$$$1 == "$(1)" { print $$$$2 " " $$$$3 " " $$$$4 }' $(PKG_FILE2);) \
+ @DEPPKG=$$$$(awk 'BEGIN { FS = "\t" }; $$$$1 == "$(1)" { print $$$$2 " " $$$$3 " " $$$$4 }' $(PKG_FILE2);); \
VS=$$$$(echo $$$$DEPPKG | cut -d " " -f1); \
REPO=$$$$(echo $$$$DEPPKG | cut -d " " -f2); \
COMMIT=$$$$(echo $$$$DEPPKG | cut -d " " -f3); \
$(call dep_fetch,$(1))
else
- VS=$(word 1,$(dep_$(1))); \
+ @VS=$(word 1,$(dep_$(1))); \
REPO=$(word 2,$(dep_$(1))); \
COMMIT=$(word 3,$(dep_$(1))); \
$(call dep_fetch,$(1))
@@ -205,9 +204,13 @@ xyrl_verbose = $(xyrl_verbose_$(V))
# Core targets.
-app:: ebin/$(PROJECT).app
+app:: erlc-include ebin/$(PROJECT).app
$(eval MODULES := $(shell find ebin -type f -name \*.beam \
| sed "s/ebin\//'/;s/\.beam/',/" | sed '$$s/.$$//'))
+ @if [ -z "$$(grep -E '^[^%]*{modules,' src/$(PROJECT).app.src)" ]; then \
+ echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk README for instructions." >&2; \
+ exit 1; \
+ fi
$(appsrc_verbose) cat src/$(PROJECT).app.src \
| sed "s/{modules,[[:space:]]*\[\]}/{modules, \[$(MODULES)\]}/" \
> ebin/$(PROJECT).app
@@ -240,6 +243,11 @@ clean:: clean-app
# Extra targets.
+erlc-include:
+ -@if [ -d ebin/ ]; then \
+ find include/ src/ -type f -name \*.hrl -newer ebin -exec touch $(shell find src/ -type f -name "*.erl") \; 2>/dev/null || printf ''; \
+ fi
+
clean-app:
$(gen_verbose) rm -rf ebin/
@@ -623,13 +631,19 @@ help::
# Plugin-specific targets.
-plt: deps app
+$(DIALYZER_PLT): deps app
@dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(ALL_DEPS_DIRS)
+plt: $(DIALYZER_PLT)
+
distclean-plt:
$(gen_verbose) rm -f $(DIALYZER_PLT)
+ifneq ($(wildcard $(DIALYZER_PLT)),)
dialyze:
+else
+dialyze: $(DIALYZER_PLT)
+endif
@dialyzer --no_native --src -r src $(DIALYZER_OPTS)
# Copyright (c) 2013-2014, Loïc Hoguin
@@ -683,14 +697,12 @@ distclean-edoc:
# Copyright (c) 2013-2014, Loïc Hoguin
# This file is part of erlang.mk and subject to the terms of the ISC License.
-.PHONY: distclean-rel
+.PHONY: relx-rel distclean-relx-rel distclean-relx
# Configuration.
RELX_CONFIG ?= $(CURDIR)/relx.config
-ifneq ($(wildcard $(RELX_CONFIG)),)
-
RELX ?= $(CURDIR)/relx
export RELX
@@ -700,14 +712,17 @@ RELX_OUTPUT_DIR ?= _rel
ifeq ($(firstword $(RELX_OPTS)),-o)
RELX_OUTPUT_DIR = $(word 2,$(RELX_OPTS))
+else
+ RELX_OPTS += -o $(RELX_OUTPUT_DIR)
endif
# Core targets.
-rel:: distclean-rel $(RELX)
- @$(RELX) -c $(RELX_CONFIG) $(RELX_OPTS)
+ifneq ($(wildcard $(RELX_CONFIG)),)
+rel:: distclean-relx-rel relx-rel
+endif
-distclean:: distclean-rel
+distclean:: distclean-relx-rel distclean-relx
# Plugin-specific targets.
@@ -719,7 +734,11 @@ endef
$(RELX):
@$(call relx_fetch)
-distclean-rel:
- $(gen_verbose) rm -rf $(RELX) $(RELX_OUTPUT_DIR)
+relx-rel: $(RELX)
+ @$(RELX) -c $(RELX_CONFIG) $(RELX_OPTS)
-endif
+distclean-relx-rel:
+ $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR)
+
+distclean-relx:
+ $(gen_verbose) rm -rf $(RELX)
diff --git a/include/swab_hexdump.hrl b/include/swab_hexdump.hrl
index b8bca86..4ad3741 100644
--- a/include/swab_hexdump.hrl
+++ b/include/swab_hexdump.hrl
@@ -1,9 +1,9 @@
%%%-------------------------------------------------------------------
-%%% File: swab_hexdump.hrl
+%%% File: swab_hexdump.erl
%%% @author Eric Pailleau
%%% @copyright 2014 crownedgrouse.com
%%% @doc
-%%% General purpose buffer handling - SWAB hexdump library
+%%% swab hexdump include
%%% @end
%%%
%%% Permission to use, copy, modify, and/or distribute this software
@@ -27,94 +27,7 @@
data = " ~2.16.0b" :: string(),
width = 8 :: integer(),
nb = 2 :: integer(),
- canonical = 'true' :: 'true' | 'false',
+ canonical = true :: 'true' | 'false',
sep = "|" :: string(),
line = 0 :: integer(),
io = standard_io :: pid() | atom()}).
-
-%%-------------------------------------------------------------------------
-%%@doc Main function call
-%%@end
-%%-------------------------------------------------------------------------
--spec hexdump(binary() | [any()]) -> 'ok'.
-
-hexdump(Data) when is_binary(Data) -> hexdump(binary_to_list(Data), #hexdump{});
-hexdump(Data) when is_list(Data) -> hexdump(Data, #hexdump{}).
-
-%%-------------------------------------------------------------------------
-%%@doc Treat data
-%%@end
-%%-------------------------------------------------------------------------
--spec hexdump(list(), #hexdump{}) -> 'ok'.
-
-hexdump(L, R) when is_list(L),
- is_tuple(R),
- (length(L)=< (R#hexdump.width * R#hexdump.nb)) -> hexdump_line(L, R);
-hexdump(L, R) when is_list(L),
- is_tuple(R),
- (length(L)> R#hexdump.width * R#hexdump.nb) -> % Take width*nb octets , and let's treat it, then the remaining
- {A, B} = lists:split(R#hexdump.width * R#hexdump.nb, L),
- hexdump_line(A, R),
- case B of
- [] -> io:fwrite(R#hexdump.io, "",[]);
- _ -> hexdump(B, R#hexdump{line= (R#hexdump.line + 1)})
- end.
-
-%%-------------------------------------------------------------------------
-%%@doc Treat line
-%%@end
-%%-------------------------------------------------------------------------
--spec hexdump_line(list(), #hexdump{}) -> 'ok'.
-
-hexdump_line(A, R) -> io:fwrite(R#hexdump.io, R#hexdump.prefix, [R#hexdump.line * R#hexdump.width * R#hexdump.nb] ),
- lists:foreach(fun(X) -> io:fwrite(R#hexdump.io, R#hexdump.data, [X]) end,A) ,
- % If the line is not complete, do it with blanks
- io:fwrite(R#hexdump.io, string:copies(" ",round(R#hexdump.width * R#hexdump.nb) - length(A)),[]),
- case R#hexdump.canonical of
- 'false' -> io:fwrite(R#hexdump.io, " ",[]) ;
- 'true' -> io:fwrite(R#hexdump.io, " ~s",[R#hexdump.sep]),
- lists:foreach(fun(X) -> io:fwrite(R#hexdump.io, "~s", [hexdump_printable(X)]) end,A),
- io:fwrite(R#hexdump.io, "~s",[R#hexdump.sep])
- end,
- io:fwrite(R#hexdump.io, "~n",[]).
-
-%%-------------------------------------------------------------------------
-%%@doc Is character printable or not ?
-%%@end
-%%-------------------------------------------------------------------------
--spec hexdump_printable(_) -> [any(),...].
-
-hexdump_printable(X) -> case ((X>31) and (X<128)) of
- true -> [X] ;
- false -> "."
- end.
-
-%%-------------------------------------------------------------------------
-%%@doc Zulu time to local time
-%%@end
-%%-------------------------------------------------------------------------
--spec zulu_to_localtime(iolist()) -> iolist().
-
-zulu_to_localtime(Z) -> {A1,A2,M1,M2,D1,D2,H1,H2,I1,I2,S1,S2,_} = list_to_tuple(Z),
- {{Year, Month, Day},{Hour, Min, Sec}} = calendar:universal_time_to_local_time({{
- list_to_integer("20"++[A1,A2]),
- list_to_integer([M1,M2]),
- list_to_integer([D1,D2])},
- {list_to_integer([H1,H2]),
- list_to_integer([I1,I2]),
- list_to_integer([S1,S2])} }),
- io_lib:fwrite("~4.10.0b-~2.10.0b-~2.10.0b ~2.10.0b:~2.10.0b:~2.10.0b",[Year,Month,Day,Hour,Min,Sec]).
-
-%%-------------------------------------------------------------------------
-%%@doc Timezone
-%%@end
-%%-------------------------------------------------------------------------
--spec timezone() -> list() .
-timezone() -> {{_, _, UD},{UH,_, _}} = calendar:universal_time(),
- {{_, _, LD},{LH,_, _}} = calendar:local_time(),
- Offset = (LD*24 + LH) - (UD*24 + UH),
- case (Offset >= 0) of
- true -> [Offset,"+"] ;
- false -> [abs(Offset),"-"]
- end.
-
diff --git a/include/swab_lib.hrl b/include/swab_lib.hrl
index c19fe06..e059ff4 100644
--- a/include/swab_lib.hrl
+++ b/include/swab_lib.hrl
@@ -67,7 +67,8 @@ nonl([], L) -> L.
%%@doc Fold
%%@end
%%-------------------------------------------------------------------------
-fold(Len, [], Acc) when is_integer(Len) -> Acc ;
+-spec fold(integer(), binary(), list()) -> iolist().
+fold(Len, <<>>, Acc) when is_integer(Len) -> Acc ;
fold(Len, In, []) when is_integer(Len),
is_binary(In),
byte_size(In) < Len -> binary_to_list(In) ;
@@ -85,6 +86,28 @@ fold(Len, In, Acc) when is_integer(Len),
is_list(Acc) -> {B1, B2} = split_binary(In, Len),
fold(Len, B2, Acc ++ io_lib:nl() ++ binary_to_list(B1)) .
+%%-------------------------------------------------------------------------
+%%@doc Swab
+%% Exchange adjacent even and odd bytes.
+%% This function is used to exchange data between machines that have different
+%% low/high byte ordering.
+%% When byte number is odd, it handles n-1 bytes as above, and leave unchanged
+%% the last byte. (In other words, bytes number should be even.)
+%% Original buffer type, list or binary, is kept.
+%%@end
+%%-------------------------------------------------------------------------
+-spec swab(list()| binary()) -> list() | binary().
+swab(Buff) when is_list(Buff) -> binary_to_list(swab(list_to_binary(Buff))) ;
+
+swab(Buff) when is_binary(Buff) -> swabify(Buff, []).
+
+-spec swabify(binary(), list()) -> binary().
+swabify(<>, Acc) -> swabify(Rest, Acc ++ [B, A]) ;
+
+swabify(< >, Acc) -> swabify(<<>>, Acc ++ [A]) ;
+
+swabify(<<>>, Acc) -> list_to_binary(Acc) .
+
%%-------------------------------------------------------------------------
%%@doc Queue init.
%%@end
diff --git a/src/swab.app.src b/src/swab.app.src
new file mode 100644
index 0000000..3e53f39
--- /dev/null
+++ b/src/swab.app.src
@@ -0,0 +1,12 @@
+{application, swab,
+ [
+ {description, "General purpose buffer handling module"},
+ {vsn, "1.0.0"},
+ {registered, []},
+ {applications, [
+ kernel,
+ stdlib
+ ]},
+ {env, []},
+ {modules, []}
+ ]}.
diff --git a/src/swab.erl b/src/swab.erl
index 53e9b71..0b66bbd 100644
--- a/src/swab.erl
+++ b/src/swab.erl
@@ -30,12 +30,16 @@
-include_lib("public_key/include/public_key.hrl").
--include("swab_lib.hrl").
--include("swab_ebcdic.hrl").
--include("swab_hexdump.hrl").
--include("swab_asn1.hrl").
--include("swab_tar.hrl").
+% Pre-compiled regexps for better performances.
+% (?>\r\n|\n|\x0b|\f|\r|\x85)
+-define(REG_LINES, {re_pattern,0,0,0,
+ <<69,82,67,80,98,0,0,0,0,0,0,0,1,8,0,0,255,255,255,255,255,255,
+ 255,255,0,0,0,0,0,0,0,0,0,0,56,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,125,0,38,124,0,7,29,13,29,10,113,0,5,29,10,113,0,5,29,
+ 11,113,0,5,29,12,113,0,5,29,13,113,0,5,29,133,114,0,32,114,0,38,
+ 0>>}).
+-include("swab_lib.hrl").
-define(SWAB_DBG(Tuple,Buf), case get(swab_dbg) of
'on' -> io:fwrite("~s : ~p => ~p~n",[pid_to_list(self()),Tuple, Buf]),
@@ -44,16 +48,21 @@
io:fwrite(" ~p~n",[queue:to_list(get(queue))]);
_ -> ok
end;
- 'hexdump' -> io:fwrite("~s : ~p => ~n" ,[pid_to_list(self()),Tuple]), hexdump(Buf) ;
- 'asn1_pp' -> io:fwrite("~s : ~p => ~n" ,[pid_to_list(self()),Tuple]), asn1_pp(Buf) ;
+ 'hexdump' -> io:fwrite("~s : ~p => ~n" ,[pid_to_list(self()),Tuple]), swab_hexdump:hexdump(Buf), ok ;
+ 'asn1_pp' -> io:fwrite("~s : ~p => ~n" ,[pid_to_list(self()),Tuple]), _ = swab_asn1:asn1_pp(Buf), ok ;
_ -> ok
end ).
%%-------------------------------------------------------------------------
-%% @doc Apply rules and return synchronously
+%% @doc Apply rules and return synchronously.
+%% Return values can be : {ok, LastBuffer}
+%% {error, OffendingDirective, Message}
+%% and if match directive is used and matching :
+%% {match, MatchingDirective, MatchingBuffer}
+%% MatchingDirective could have been rewritten with default values (See Overview).
%% @end
%%-------------------------------------------------------------------------
--spec sync(list()|tuple(), iolist()) -> tuple().
+-spec sync(list()|tuple(), iolist()|binary()) -> tuple().
sync(Rules, Buffer) when is_tuple(Rules);
is_list(Rules) -> try analyze(Buffer, Rules) of
@@ -62,24 +71,39 @@ sync(Rules, Buffer) when is_tuple(Rules);
end.
%%-------------------------------------------------------------------------
-%% @doc Apply rules and return synchronously, but send result to a Pid
+%% @doc Apply rules and return synchronously, but send result to a Pid.
+%% Caller Pid get atom ok .
+%% Target Pid receives message {swab, CallerPid, SwabSyncResult} .
%% @end
%%-------------------------------------------------------------------------
+-spec sync(list()|tuple(), iolist(), pid()) -> ok.
+
sync(Rules, Buffer, Pid) when is_pid(Pid) -> Return = analyze(Buffer, Rules),
Pid ! {swab, self(), Return},
ok.
%%-------------------------------------------------------------------------
-%% @doc Apply rules asynchronously, and send result to caller Pid
+%% @doc Apply rules asynchronously, and send result to caller Pid.
+%% Caller Pid get tuple {ok, SwabSpawnPid} .
+%% Caller Pid receives message {swab, SwabSpawnPid, SwabSyncResult} .
+%% The caller might store the returned value SwabSpawnPid as reference
+%% if several messages are expected to be received.
%% @end
%%-------------------------------------------------------------------------
--spec async(list()|tuple(), iolist()) -> tuple().
+-spec async(list()|tuple(), iolist()) -> {ok, pid()}.
+
async(Rules, Buffer) -> {ok, spawn(swab, sync, [Rules, Buffer, self()])}.
%%-------------------------------------------------------------------------
-%% @doc Apply rules asynchronously, but send result to a Pid
+%% @doc Apply rules asynchronously, but send result to a Pid.
+%% Caller Pid get tuple {ok, SwabSpawnPid} .
+%% Target Pid receives message {swab, SwabSpawnPid, SwabSyncResult} .
+%% The caller might store the returned value SwabSpawnPid as reference
+%% if a correlation must be done with the target.
%% @end
%%-------------------------------------------------------------------------
+-spec async(list()|tuple(), iolist(), pid()) -> {ok, pid()}.
+
async(Rules, Buffer, Pid) when is_pid(Pid) -> {ok, spawn(swab, sync, [Rules, Buffer, Pid])}.
%%*************************************************************************
@@ -263,7 +287,7 @@ analyze(_, {push, Data}) when is_binary(Data);
%%@end
%%-------------------------------------------------------------------------
analyze(Buff, {store, Data}) when is_binary(Data);
- is_list(Data) -> analyze(Data, {buffer, in_r}),
+ is_list(Data) -> _ = analyze(Data, {buffer, in_r}),
Buff ;
%%-------------------------------------------------------------------------
@@ -273,7 +297,7 @@ analyze(Buff, {store, Data}) when is_binary(Data);
%%-------------------------------------------------------------------------
analyze(Buff, {erots, Data}) -> analyze(Buff, {store_r, Data});
analyze(Buff, {store_r, Data}) when is_binary(Data);
- is_list(Data) -> analyze(Data, {buffer, in}),
+ is_list(Data) -> _ = analyze(Data, {buffer, in}),
Buff ;
%%**************************************************************************
@@ -336,7 +360,7 @@ analyze(Buff, {feed, Len}) when is_integer(Len) -> analyze(Buff, {feed, {Len, $\
%%@end
%%-------------------------------------------------------------------------
analyze(Buff, {feed, {Len, Char}}) when is_integer(Len),
- is_integer(Char) -> L = re:split(Buff,"(?>\r\n|\n|\x0b|\f|\r|\x85)",[{return,list}]),
+ is_integer(Char) -> L = re:split(Buff,?REG_LINES,[{return,list}]),
R = case (Len < 0) of
true -> lists:flatmap(fun(X) -> [string:right(X, (- Len), Char)] end, L) ;
false -> lists:flatmap(fun(X) -> [string:left(X, Len, Char)] end, L)
@@ -370,6 +394,7 @@ analyze(Buff, {fold, Len}) when is_integer(Len),
%% d) nonl - Removes any new lines separators whatever the OS type
%% (\r, \r\n, \n but also \f, \x85 and \x0b).
%% e) local_nl - Convert any new lines to local new lines.
+%% f) swab - exchange adjacent even and odd bytes.
%%@end
%%-------------------------------------------------------------------------
analyze(Buff, {convert, Type}) -> NewBuff = case Type of
@@ -385,6 +410,7 @@ analyze(Buff, {convert, Type}) -> NewBuff = case Type of
gzip -> (catch zlib:gzip(Buff)) ;
nonl -> nonl(Buff, []);
local_nl -> analyze(Buff, {jump, 0}) ;
+ swab -> swab(Buff);
_ -> throw(badarg), Buff
end,
case NewBuff of
@@ -412,7 +438,7 @@ analyze(Buff, {decode, Type}) -> NewBuff = case Type of
{utf32, big} -> (catch to_unicode(Buff,Type));
{utf32, little} -> (catch to_unicode(Buff,Type));
utf32 -> (catch to_unicode(Buff,Type));
- ebcdic -> e2a(Buff);
+ ebcdic -> swab_ebcdic:e2a(Buff);
_ -> throw(badarg), Buff
end,
case NewBuff of
@@ -436,7 +462,7 @@ analyze(Buff, {encode, Type}) -> NewBuff = case Type of
{utf32, big} -> (catch from_unicode(Buff,Type));
{utf32, little} -> (catch from_unicode(Buff,Type));
utf32 -> (catch from_unicode(Buff,Type));
- ebcdic -> a2e(Buff);
+ ebcdic -> swab_ebcdic:a2e(Buff);
_ -> throw(badarg), Buff
end,
case NewBuff of
@@ -448,21 +474,15 @@ analyze(Buff, {encode, Type}) -> NewBuff = case Type of
%%-------------------------------------------------------------------------
%%@doc Line extracting on current buffer (jump)
-%% a) Integer : Jump to the given line number and bring only
-%% lines after. Be carefull, if line does not exist,
-%% it will empty the buffer !
-%% Negative value will discard the given last lines.
-%% zero will bring all the lines.
-%% b) [last|first] : Bring only the last/first line of current buffer.
+%% Jump to the given line number and bring only lines after.
+%% Be carefull, if line does not exist, it will empty the buffer !
+%% Negative value will bring the lines from the end.
+%% zero will bring all the lines.
%% Warning : Any new lines will be normalized to local new lines !
%%@end
%%-------------------------------------------------------------------------
analyze(Buff, {jump, Mode}) -> L = re:split(Buff,"(?>\r\n|\n|\x0b|\f|\r|\x85)",[{return,list}]),
NewBuff = case Mode of
- first when (length(L) > 1 ) -> [NB | _ ] = L, NB ;
- first when (length(L) == 1 )-> L ;
- first when (length(L) == 0 )-> "" ;
- last -> lists:last(L) ;
Int when (Int == 0) -> {T,_} = lists:split(length(L), L),
string:join(T, io_lib:nl());
Int when (Int < 0) -> {_,T} = lists:split(length(L) + Int, L),
@@ -485,16 +505,18 @@ analyze(Buff, {jump, Mode}) -> L = re:split(Buff,"(?>\r\n|\n|\x0b|\f|\r|\x85)",[
%% Lines found becomes the next current buffer.
%%@end
%%-------------------------------------------------------------------------
+analyze(Buff, {nblines, first}) -> analyze(Buff, {nblines, 1}) ;
+analyze(Buff, {nblines, last}) -> analyze(Buff, {nblines, -1}) ;
analyze(Buff, {nblines, Int}) ->
NewBuff = case is_integer(Int) of
false -> throw(badarg), Buff ;
true when (Int == 0)-> "";
- true when (Int > 0) -> L = re:split(Buff,"(?>\r\n|\n|\x0b|\f|\r|\x85)",[{return,list}]),
- {L2, _} = lists:split(Int, L),
- string:join(L2,io_lib:nl());
- true when (Int < 0) -> L = re:split(Buff,"(?>\r\n|\n|\x0b|\f|\r|\x85)",[{return,list}]),
- {L2, _} = lists:split((- Int), lists:reverse(L)),
- string:join(lists:reverse(L2),io_lib:nl())
+ true when (Int > 0) -> L = re:split(Buff,?REG_LINES,[{return,list}]),
+ {L2, _} = lists:split(Int, L),
+ string:join(L2,io_lib:nl());
+ true when (Int < 0) -> L = re:split(Buff,?REG_LINES,[{return,list}]),
+ {L2, _} = lists:split((- Int), lists:reverse(L)),
+ string:join(lists:reverse(L2),io_lib:nl())
end,
?SWAB_DBG({nblines, Int}, NewBuff),
NewBuff;
@@ -516,7 +538,7 @@ analyze(Buff, {nblines, Int}) ->
%% Warning : slower than other sorting methods.
%%@end
%%-------------------------------------------------------------------------
-analyze(Buff, {sort, Mode}) -> L = re:split(Buff,"(?>\r\n|\n|\x0b|\f|\r|\x85)",[{return,list}, trim]),
+analyze(Buff, {sort, Mode}) -> L = re:split(Buff,?REG_LINES,[{return,list}, trim]),
NewBuff = case Mode of
normal -> string:join(lists:sort(L),io_lib:nl()) ;
reverse -> string:join(lists:reverse(lists:sort(L)),io_lib:nl()) ;
@@ -606,7 +628,7 @@ analyze(Buff, {mfa, {M, F, A}}) when is_atom(M),
end;
analyze(Buff, {tar, fakeroot}) -> try
- tar_fakeroot(Buff)
+ swab_tar:fakeroot(Buff)
catch
throw:invalid -> throw({error, {tar, fakeroot}, "Invalid Tar file"});
error:Reason -> throw({error, {tar, fakeroot}, Reason})
@@ -615,7 +637,7 @@ analyze(Buff, {tar, fakeroot}) -> try
analyze(Buff, {tar, {Uid, User}})
when is_integer(Uid),
is_list(User) -> try
- tar_change_user(Buff, {Uid, User})
+ swab_tar:change_user(Buff, {Uid, User})
catch
throw:invalid -> throw({error, {tar, {Uid, User}}, "Invalid Tar file"});
error:Reason -> throw({error, {tar, {Uid, User}}, Reason})
@@ -624,7 +646,7 @@ analyze(Buff, {tar, {Uid, User}})
analyze(Buff, {tar, {Group, Gid}})
when is_integer(Gid),
is_list(Group) -> try
- tar_change_group(Buff, {Gid, Group})
+ swab_tar:change_group(Buff, {Gid, Group})
catch
throw:invalid -> throw({error, {tar, {Gid, Group}}, "Invalid Tar file"});
error:Reason -> throw({error, {tar, {Gid, Group}}, Reason})
diff --git a/include/swab_asn1.hrl b/src/swab_asn1.erl
similarity index 74%
rename from include/swab_asn1.hrl
rename to src/swab_asn1.erl
index eec1869..e1b1f23 100644
--- a/include/swab_asn1.hrl
+++ b/src/swab_asn1.erl
@@ -1,9 +1,8 @@
%%%-----------------------------------------------------------------------
-%%% File: swab_asn1.hrl
+%%% File: swab_asn1.erl
%%% @author Eric Pailleau
%%% @copyright 2014 crownedgrouse.com
%%% @doc
-%%% General purpose buffer handling - SWAB hexdump library
%%% @end
%%%
%%% Permission to use, copy, modify, and/or distribute this software
@@ -22,7 +21,11 @@
%%%
%%% Created : 2014-07-14
%%%-----------------------------------------------------------------------
+-module(swab_asn1).
+-export([asn1_pp/1, asn1_pp/2]).
+
+-include("swab_hexdump.hrl").
-include("swab_asn1_otp.hrl"). % External code, thanks Ericsson AB.
%%*************************************************************************
@@ -31,41 +34,44 @@
%%asn1_struct(B) -> asn1rt:decode(B).
-record(asn1_pp, { module = undefined,
- indent :: 'true' | 'false',
- tab = ". ",
- hexdump :: 'true' | 'false',
- hexdump_conf= undefined,
+ indent = true :: 'true' | 'false',
+ tab = ". ",
+ hexdump = true :: 'true' | 'false',
+ hexdump_conf= #hexdump{},
depth = 0 ,
context = undefined,
io = standard_io}).
%%-------------------------------------------------------------------------
-%%@doc
+%%@doc ASN1 pretty printer
+%% Default.
%%@end
%%-------------------------------------------------------------------------
+-spec asn1_pp(list() | binary()) -> 'ok' | tuple().
-asn1_pp(P) -> _ = asn1_pp(P, #asn1_pp{}),
- ok.
+asn1_pp(P) -> _ = asn1_pp(P, #asn1_pp{}).
%%-------------------------------------------------------------------------
-%%@doc
+%%@doc ASN1 pretty printer
+%% Custom.
%%@end
%%-------------------------------------------------------------------------
--spec asn1_pp(_, _) -> 'ok' | tuple().
+-spec asn1_pp(list() | binary(), #asn1_pp{} | true | false) -> 'ok' | tuple().
-asn1_pp(P, true) -> asn1_pp(P, #asn1_pp{} ),ok;
-asn1_pp(P, false) -> asn1_pp(P, #asn1_pp{indent=false} ),ok;
+asn1_pp(P, true) -> asn1_pp(P, #asn1_pp{} );
+asn1_pp(P, false) -> asn1_pp(P, #asn1_pp{indent=false} );
asn1_pp(P, R) when is_list(P),is_tuple(R) -> % Assuming it is a path to a file
case file:read_file(P) of
- {ok, B} -> asn1_print(asn1_parse(B), R#asn1_pp{depth=0, context=undefined}),ok;
- {error, E} -> {error, E}
+ {ok, B} -> asn1_print(asn1_parse(B), R#asn1_pp{depth=0, context=undefined}),ok;
+ {error, E} -> {error, E}
end;
asn1_pp(B, R) when is_binary(B)-> asn1_print(asn1_parse(B), R#asn1_pp{depth=0, context=undefined}),ok.
%%-------------------------------------------------------------------------
-%%@doc
+%%@doc ASN1 formatter
%%@end
%%-------------------------------------------------------------------------
+-spec asn1_print(list() | binary() | tuple(), #asn1_pp{}) -> _.
asn1_print(L, R) when is_list(L) -> N= R#asn1_pp{depth= (R#asn1_pp.depth + 1)},
lists:foreach(fun(A) -> asn1_print(A, N) end, L),
@@ -117,48 +123,57 @@ asn1_print(T, R) when is_tuple(T)->
end.
%%-------------------------------------------------------------------------
-%%@doc
+%%@doc Indent
%%@end
%%-------------------------------------------------------------------------
+-spec asn1_indent(tuple()) -> _.
+
asn1_indent(R) when is_tuple(R) -> case R#asn1_pp.indent of
'false' -> "" ;
- 'true' -> string:copies(R#asn1_pp.tab, max(0,R#asn1_pp.depth - 1));
- _ -> "" % Dialyzer and default record type ! Grrrrr...
+ 'true' -> string:copies(R#asn1_pp.tab, max(0,R#asn1_pp.depth - 1))
end.
%%-------------------------------------------------------------------------
-%%@doc
+%%@doc BER to OID
%%@end
%%-------------------------------------------------------------------------
+-spec ber_to_oid(binary()) -> tuple().
+
ber_to_oid(<>) -> X=(A div 40),
list_to_tuple(lists:flatten([X, (A - (X*40))] ++ b128_decode(binary_to_list(R)))) .
%%-------------------------------------------------------------------------
-%%@doc
+%%@doc Decoding
%%@end
%%-------------------------------------------------------------------------
+-spec b128_decode(list()) -> _.
+
b128_decode(B) when is_list(B) -> P = lists:takewhile(fun(X)-> X >= 128 end, B),
- Z = lists:subtract(B, P),
- A = case Z of
+ Z = lists:subtract(B, P),
+ A = case Z of
[] -> P;
_ -> P ++ [hd(Z)]
end,
- R = case Z of
+ R = case Z of
[] -> [];
_ -> tl(Z)
end,
- case A of
- [] -> [];
- B -> [b128_to_b10(B)];
- _ -> [b128_to_b10(lists:flatten([A]))] ++ [b128_decode(lists:flatten([R]))]
- end.
+ case A of
+ [] -> [];
+ B -> [b128_to_b10(B)];
+ _ -> [b128_to_b10(lists:flatten([A]))] ++ [b128_decode(lists:flatten([R]))]
+ end.
%%-------------------------------------------------------------------------
-%%@doc
+%%@doc Decoding
%%@end
%%-------------------------------------------------------------------------
+-spec b128_to_b10(list()) -> _ .
b128_to_b10(B) when is_list(B) -> b128_to_b10(lists:reverse(B), 0).
+
+-spec b128_to_b10(list(), integer()) -> _ .
+
b128_to_b10([], _) -> 0;
b128_to_b10(B, Pow) when is_list(B),(length(B)==1) -> H = hd(B),
case H of
@@ -173,9 +188,10 @@ b128_to_b10(B, Pow) when is_list(B),(length(B)>1) -> H = hd(B),
end.
%%-------------------------------------------------------------------------
-%%@doc
+%%@doc OID to Name
%%@end
%%-------------------------------------------------------------------------
+-spec oid_to_name(atom(),tuple()) -> _ .
oid_to_name(M, Oid) when is_atom(M),is_tuple(Oid) ->
case M of
@@ -188,13 +204,41 @@ oid_to_name(M, Oid) when is_atom(M),is_tuple(Oid) ->
end.
%%-------------------------------------------------------------------------
-%%@doc
+%%@doc Hexdump non printable data
%%@end
%%-------------------------------------------------------------------------
+-spec asn1_hexdump(binary(),#asn1_pp{indent::'false' | 'true',hexdump::'false' | 'true',depth::non_neg_integer(),context::atom()}) -> 'ok'.
+
asn1_hexdump(B, R) -> case R#asn1_pp.hexdump of
- true -> case is_tuple(R#asn1_pp.hexdump_conf) of
- false -> hexdump(B) ;
- true -> hexdump(B, R#asn1_pp.hexdump_conf)
- end ;
+ true -> swab_hexdump:hexdump(binary_to_list(B), R#asn1_pp.hexdump_conf) ;
_ -> io:fwrite(R#asn1_pp.io, "~w~n",[B])
end.
+
+%%-------------------------------------------------------------------------
+%%@doc Zulu time to local time
+%%@end
+%%-------------------------------------------------------------------------
+-spec zulu_to_localtime(iolist()) -> iolist().
+
+zulu_to_localtime(Z) -> {A1,A2,M1,M2,D1,D2,H1,H2,I1,I2,S1,S2,_} = list_to_tuple(Z),
+ {{Year, Month, Day},{Hour, Min, Sec}} = calendar:universal_time_to_local_time({{
+ list_to_integer("20"++[A1,A2]),
+ list_to_integer([M1,M2]),
+ list_to_integer([D1,D2])},
+ {list_to_integer([H1,H2]),
+ list_to_integer([I1,I2]),
+ list_to_integer([S1,S2])} }),
+ io_lib:fwrite("~4.10.0b-~2.10.0b-~2.10.0b ~2.10.0b:~2.10.0b:~2.10.0b",[Year,Month,Day,Hour,Min,Sec]).
+
+%%-------------------------------------------------------------------------
+%%@doc Timezone
+%%@end
+%%-------------------------------------------------------------------------
+-spec timezone() -> list() .
+timezone() -> {{_, _, UD},{UH,_, _}} = calendar:universal_time(),
+ {{_, _, LD},{LH,_, _}} = calendar:local_time(),
+ Offset = (LD*24 + LH) - (UD*24 + UH),
+ case (Offset >= 0) of
+ true -> [Offset,"+"] ;
+ false -> [abs(Offset),"-"]
+ end.
diff --git a/include/swab_ebcdic.hrl b/src/swab_ebcdic.erl
similarity index 60%
rename from include/swab_ebcdic.hrl
rename to src/swab_ebcdic.erl
index e077028..62527fd 100644
--- a/include/swab_ebcdic.hrl
+++ b/src/swab_ebcdic.erl
@@ -1,9 +1,9 @@
%%%-------------------------------------------------------------------
-%%% File: ebcdic.hrl
+%%% File: swab_ebcdic.erl
%%% @author Eric Pailleau
%%% @copyright 2014 crownedgrouse.com
%%% @doc
-%%% EBCDIC library
+%%% EBCDIC module for swab
%%% @end
%%%
%%% Permission to use, copy, modify, and/or distribute this software
@@ -22,11 +22,16 @@
%%%
%%% Created : 2014-07-14
%%%-------------------------------------------------------------------
+-module(swab_ebcdic).
+
+-export([e2a/1,a2e/1]).
%%-------------------------------------------------------------------------
%%@doc EBCDIC to ASCII
%%@end
%%-------------------------------------------------------------------------
+-spec e2a(list() | binary()) -> list() | binary().
+
e2a(L) when is_list(L) ->
lists:foldl(fun(X, Res) -> Res ++ [e2a_char(X)] end, [], L);
e2a(L) when is_binary(L) ->
@@ -36,6 +41,8 @@ e2a(L) when is_binary(L) ->
%%@doc ASCII to EBCDIC
%%@end
%%-------------------------------------------------------------------------
+-spec a2e(list() | binary()) -> list() | binary().
+
a2e(L) when is_list(L) ->
lists:foldl(fun(X, Res) -> Res ++ [a2e_char(X)] end, [], L);
a2e(L) when is_binary(L) ->
@@ -45,6 +52,8 @@ a2e(L) when is_binary(L) ->
%%@doc ASCII to EBCDIC characters map
%%@end
%%-------------------------------------------------------------------------
+-spec a2e_char(integer()) -> integer().
+
a2e_char(_Char) ->
case _Char of
$\000 -> $\000;
@@ -308,264 +317,266 @@ a2e_char(_Char) ->
%%-------------------------------------------------------------------------
%%@doc EBCDIC to ASCII characters map
%%@end
-%%-------------------------------------------------------------------------
+%%-------------------------------------------------------------------------
+-spec e2a_char(integer()) -> integer().
+
e2a_char(_Char) ->
case _Char of
- $\000 -> $\000 ;
- $\001 -> $\001 ;
- $\002 -> $\002 ;
- $\003 -> $\003 ;
- $\067 -> $\004 ;
- $\055 -> $\005 ;
- $\056 -> $\006 ;
- $\057 -> $\007 ;
- $\026 -> $\010 ;
- $\005 -> $\011 ;
- $\045 -> $\012 ;
- $\013 -> $\013 ;
- $\014 -> $\014 ;
- $\015 -> $\015 ;
- $\016 -> $\016 ;
- $\017 -> $\017 ;
- $\020 -> $\020 ;
- $\021 -> $\021 ;
- $\022 -> $\022 ;
- $\023 -> $\023 ;
- $\074 -> $\024 ;
- $\075 -> $\025 ;
- $\062 -> $\026 ;
- $\046 -> $\027 ;
- $\030 -> $\030 ;
- $\031 -> $\031 ;
- $\077 -> $\032 ;
- $\047 -> $\033 ;
- $\034 -> $\034 ;
- $\035 -> $\035 ;
- $\036 -> $\036 ;
- $\037 -> $\037 ;
- $\100 -> $\040 ;
- $\117 -> $\041 ;
- $\177 -> $\042 ;
- $\173 -> $\043 ;
- $\133 -> $\044 ;
- $\154 -> $\045 ;
- $\120 -> $\046 ;
- $\175 -> $\047 ;
- $\115 -> $\050 ;
- $\135 -> $\051 ;
- $\134 -> $\052 ;
- $\116 -> $\053 ;
- $\153 -> $\054 ;
- $\140 -> $\055 ;
- $\113 -> $\056 ;
- $\141 -> $\057 ;
- $\360 -> $\060 ;
- $\361 -> $\061 ;
- $\362 -> $\062 ;
- $\363 -> $\063 ;
- $\364 -> $\064 ;
- $\365 -> $\065 ;
- $\366 -> $\066 ;
- $\367 -> $\067 ;
- $\370 -> $\070 ;
- $\371 -> $\071 ;
- $\172 -> $\072 ;
- $\136 -> $\073 ;
- $\114 -> $\074 ;
- $\176 -> $\075 ;
- $\156 -> $\076 ;
- $\157 -> $\077 ;
- $\174 -> $\100 ;
- $\301 -> $\101 ;
- $\302 -> $\102 ;
- $\303 -> $\103 ;
- $\304 -> $\104 ;
- $\305 -> $\105 ;
- $\306 -> $\106 ;
- $\307 -> $\107 ;
- $\310 -> $\110 ;
- $\311 -> $\111 ;
- $\321 -> $\112 ;
- $\322 -> $\113 ;
- $\323 -> $\114 ;
- $\324 -> $\115 ;
- $\325 -> $\116 ;
- $\326 -> $\117 ;
- $\327 -> $\120 ;
- $\330 -> $\121 ;
- $\331 -> $\122 ;
- $\342 -> $\123 ;
- $\343 -> $\124 ;
- $\344 -> $\125 ;
- $\345 -> $\126 ;
- $\346 -> $\127 ;
- $\347 -> $\130 ;
- $\350 -> $\131 ;
- $\351 -> $\132 ;
- $\112 -> $\133 ;
- $\340 -> $\134 ;
- $\132 -> $\135 ;
- $\137 -> $\136 ;
- $\155 -> $\137 ;
- $\171 -> $\140 ;
- $\201 -> $\141 ;
- $\202 -> $\142 ;
- $\203 -> $\143 ;
- $\204 -> $\144 ;
- $\205 -> $\145 ;
- $\206 -> $\146 ;
- $\207 -> $\147 ;
- $\210 -> $\150 ;
- $\211 -> $\151 ;
- $\221 -> $\152 ;
- $\222 -> $\153 ;
- $\223 -> $\154 ;
- $\224 -> $\155 ;
- $\225 -> $\156 ;
- $\226 -> $\157 ;
- $\227 -> $\160 ;
- $\230 -> $\161 ;
- $\231 -> $\162 ;
- $\242 -> $\163 ;
- $\243 -> $\164 ;
- $\244 -> $\165 ;
- $\245 -> $\166 ;
- $\246 -> $\167 ;
- $\247 -> $\170 ;
- $\250 -> $\171 ;
- $\251 -> $\172 ;
- $\300 -> $\173 ;
- $\152 -> $\174 ;
- $\320 -> $\175 ;
- $\241 -> $\176 ;
- $\007 -> $\177 ;
- $\040 -> $\200 ;
- $\041 -> $\201 ;
- $\042 -> $\202 ;
- $\043 -> $\203 ;
- $\044 -> $\204 ;
- $\025 -> $\205 ;
- $\006 -> $\206 ;
- $\027 -> $\207 ;
- $\050 -> $\210 ;
- $\051 -> $\211 ;
- $\052 -> $\212 ;
- $\053 -> $\213 ;
- $\054 -> $\214 ;
- $\011 -> $\215 ;
- $\012 -> $\216 ;
- $\033 -> $\217 ;
- $\060 -> $\220 ;
- $\061 -> $\221 ;
- $\032 -> $\222 ;
- $\063 -> $\223 ;
- $\064 -> $\224 ;
- $\065 -> $\225 ;
- $\066 -> $\226 ;
- $\010 -> $\227 ;
- $\070 -> $\230 ;
- $\071 -> $\231 ;
- $\072 -> $\232 ;
- $\073 -> $\233 ;
- $\004 -> $\234 ;
- $\024 -> $\235 ;
- $\076 -> $\236 ;
- $\341 -> $\237 ;
- $\101 -> $\240 ;
- $\102 -> $\241 ;
- $\103 -> $\242 ;
- $\104 -> $\243 ;
- $\105 -> $\244 ;
- $\106 -> $\245 ;
- $\107 -> $\246 ;
- $\110 -> $\247 ;
- $\111 -> $\250 ;
- $\121 -> $\251 ;
- $\122 -> $\252 ;
- $\123 -> $\253 ;
- $\124 -> $\254 ;
- $\125 -> $\255 ;
- $\126 -> $\256 ;
- $\127 -> $\257 ;
- $\130 -> $\260 ;
- $\131 -> $\261 ;
- $\142 -> $\262 ;
- $\143 -> $\263 ;
- $\144 -> $\264 ;
- $\145 -> $\265 ;
- $\146 -> $\266 ;
- $\147 -> $\267 ;
- $\150 -> $\270 ;
- $\151 -> $\271 ;
- $\160 -> $\272 ;
- $\161 -> $\273 ;
- $\162 -> $\274 ;
- $\163 -> $\275 ;
- $\164 -> $\276 ;
- $\165 -> $\277 ;
- $\166 -> $\300 ;
- $\167 -> $\301 ;
- $\170 -> $\302 ;
- $\200 -> $\303 ;
- $\212 -> $\304 ;
- $\213 -> $\305 ;
- $\214 -> $\306 ;
- $\215 -> $\307 ;
- $\216 -> $\310 ;
- $\217 -> $\311 ;
- $\220 -> $\312 ;
- $\232 -> $\313 ;
- $\233 -> $\314 ;
- $\234 -> $\315 ;
- $\235 -> $\316 ;
- $\236 -> $\317 ;
- $\237 -> $\320 ;
- $\240 -> $\321 ;
- $\252 -> $\322 ;
- $\253 -> $\323 ;
- $\254 -> $\324 ;
- $\255 -> $\325 ;
- $\256 -> $\326 ;
- $\257 -> $\327 ;
- $\260 -> $\330 ;
- $\261 -> $\331 ;
- $\262 -> $\332 ;
- $\263 -> $\333 ;
- $\264 -> $\334 ;
- $\265 -> $\335 ;
- $\266 -> $\336 ;
- $\267 -> $\337 ;
- $\270 -> $\340 ;
- $\271 -> $\341 ;
- $\272 -> $\342 ;
- $\273 -> $\343 ;
- $\274 -> $\344 ;
- $\275 -> $\345 ;
- $\276 -> $\346 ;
- $\277 -> $\347 ;
- $\312 -> $\350 ;
- $\313 -> $\351 ;
- $\314 -> $\352 ;
- $\315 -> $\353 ;
- $\316 -> $\354 ;
- $\317 -> $\355 ;
- $\332 -> $\356 ;
- $\333 -> $\357 ;
- $\334 -> $\360 ;
- $\335 -> $\361 ;
- $\336 -> $\362 ;
- $\337 -> $\363 ;
- $\352 -> $\364 ;
- $\353 -> $\365 ;
- $\354 -> $\366 ;
- $\355 -> $\367 ;
- $\356 -> $\370 ;
- $\357 -> $\371 ;
- $\372 -> $\372 ;
- $\373 -> $\373 ;
- $\374 -> $\374 ;
- $\375 -> $\375 ;
- $\376 -> $\376 ;
- $\377 -> $\377
+ $\000 -> $\000 ;
+ $\001 -> $\001 ;
+ $\002 -> $\002 ;
+ $\003 -> $\003 ;
+ $\067 -> $\004 ;
+ $\055 -> $\005 ;
+ $\056 -> $\006 ;
+ $\057 -> $\007 ;
+ $\026 -> $\010 ;
+ $\005 -> $\011 ;
+ $\045 -> $\012 ;
+ $\013 -> $\013 ;
+ $\014 -> $\014 ;
+ $\015 -> $\015 ;
+ $\016 -> $\016 ;
+ $\017 -> $\017 ;
+ $\020 -> $\020 ;
+ $\021 -> $\021 ;
+ $\022 -> $\022 ;
+ $\023 -> $\023 ;
+ $\074 -> $\024 ;
+ $\075 -> $\025 ;
+ $\062 -> $\026 ;
+ $\046 -> $\027 ;
+ $\030 -> $\030 ;
+ $\031 -> $\031 ;
+ $\077 -> $\032 ;
+ $\047 -> $\033 ;
+ $\034 -> $\034 ;
+ $\035 -> $\035 ;
+ $\036 -> $\036 ;
+ $\037 -> $\037 ;
+ $\100 -> $\040 ;
+ $\117 -> $\041 ;
+ $\177 -> $\042 ;
+ $\173 -> $\043 ;
+ $\133 -> $\044 ;
+ $\154 -> $\045 ;
+ $\120 -> $\046 ;
+ $\175 -> $\047 ;
+ $\115 -> $\050 ;
+ $\135 -> $\051 ;
+ $\134 -> $\052 ;
+ $\116 -> $\053 ;
+ $\153 -> $\054 ;
+ $\140 -> $\055 ;
+ $\113 -> $\056 ;
+ $\141 -> $\057 ;
+ $\360 -> $\060 ;
+ $\361 -> $\061 ;
+ $\362 -> $\062 ;
+ $\363 -> $\063 ;
+ $\364 -> $\064 ;
+ $\365 -> $\065 ;
+ $\366 -> $\066 ;
+ $\367 -> $\067 ;
+ $\370 -> $\070 ;
+ $\371 -> $\071 ;
+ $\172 -> $\072 ;
+ $\136 -> $\073 ;
+ $\114 -> $\074 ;
+ $\176 -> $\075 ;
+ $\156 -> $\076 ;
+ $\157 -> $\077 ;
+ $\174 -> $\100 ;
+ $\301 -> $\101 ;
+ $\302 -> $\102 ;
+ $\303 -> $\103 ;
+ $\304 -> $\104 ;
+ $\305 -> $\105 ;
+ $\306 -> $\106 ;
+ $\307 -> $\107 ;
+ $\310 -> $\110 ;
+ $\311 -> $\111 ;
+ $\321 -> $\112 ;
+ $\322 -> $\113 ;
+ $\323 -> $\114 ;
+ $\324 -> $\115 ;
+ $\325 -> $\116 ;
+ $\326 -> $\117 ;
+ $\327 -> $\120 ;
+ $\330 -> $\121 ;
+ $\331 -> $\122 ;
+ $\342 -> $\123 ;
+ $\343 -> $\124 ;
+ $\344 -> $\125 ;
+ $\345 -> $\126 ;
+ $\346 -> $\127 ;
+ $\347 -> $\130 ;
+ $\350 -> $\131 ;
+ $\351 -> $\132 ;
+ $\112 -> $\133 ;
+ $\340 -> $\134 ;
+ $\132 -> $\135 ;
+ $\137 -> $\136 ;
+ $\155 -> $\137 ;
+ $\171 -> $\140 ;
+ $\201 -> $\141 ;
+ $\202 -> $\142 ;
+ $\203 -> $\143 ;
+ $\204 -> $\144 ;
+ $\205 -> $\145 ;
+ $\206 -> $\146 ;
+ $\207 -> $\147 ;
+ $\210 -> $\150 ;
+ $\211 -> $\151 ;
+ $\221 -> $\152 ;
+ $\222 -> $\153 ;
+ $\223 -> $\154 ;
+ $\224 -> $\155 ;
+ $\225 -> $\156 ;
+ $\226 -> $\157 ;
+ $\227 -> $\160 ;
+ $\230 -> $\161 ;
+ $\231 -> $\162 ;
+ $\242 -> $\163 ;
+ $\243 -> $\164 ;
+ $\244 -> $\165 ;
+ $\245 -> $\166 ;
+ $\246 -> $\167 ;
+ $\247 -> $\170 ;
+ $\250 -> $\171 ;
+ $\251 -> $\172 ;
+ $\300 -> $\173 ;
+ $\152 -> $\174 ;
+ $\320 -> $\175 ;
+ $\241 -> $\176 ;
+ $\007 -> $\177 ;
+ $\040 -> $\200 ;
+ $\041 -> $\201 ;
+ $\042 -> $\202 ;
+ $\043 -> $\203 ;
+ $\044 -> $\204 ;
+ $\025 -> $\205 ;
+ $\006 -> $\206 ;
+ $\027 -> $\207 ;
+ $\050 -> $\210 ;
+ $\051 -> $\211 ;
+ $\052 -> $\212 ;
+ $\053 -> $\213 ;
+ $\054 -> $\214 ;
+ $\011 -> $\215 ;
+ $\012 -> $\216 ;
+ $\033 -> $\217 ;
+ $\060 -> $\220 ;
+ $\061 -> $\221 ;
+ $\032 -> $\222 ;
+ $\063 -> $\223 ;
+ $\064 -> $\224 ;
+ $\065 -> $\225 ;
+ $\066 -> $\226 ;
+ $\010 -> $\227 ;
+ $\070 -> $\230 ;
+ $\071 -> $\231 ;
+ $\072 -> $\232 ;
+ $\073 -> $\233 ;
+ $\004 -> $\234 ;
+ $\024 -> $\235 ;
+ $\076 -> $\236 ;
+ $\341 -> $\237 ;
+ $\101 -> $\240 ;
+ $\102 -> $\241 ;
+ $\103 -> $\242 ;
+ $\104 -> $\243 ;
+ $\105 -> $\244 ;
+ $\106 -> $\245 ;
+ $\107 -> $\246 ;
+ $\110 -> $\247 ;
+ $\111 -> $\250 ;
+ $\121 -> $\251 ;
+ $\122 -> $\252 ;
+ $\123 -> $\253 ;
+ $\124 -> $\254 ;
+ $\125 -> $\255 ;
+ $\126 -> $\256 ;
+ $\127 -> $\257 ;
+ $\130 -> $\260 ;
+ $\131 -> $\261 ;
+ $\142 -> $\262 ;
+ $\143 -> $\263 ;
+ $\144 -> $\264 ;
+ $\145 -> $\265 ;
+ $\146 -> $\266 ;
+ $\147 -> $\267 ;
+ $\150 -> $\270 ;
+ $\151 -> $\271 ;
+ $\160 -> $\272 ;
+ $\161 -> $\273 ;
+ $\162 -> $\274 ;
+ $\163 -> $\275 ;
+ $\164 -> $\276 ;
+ $\165 -> $\277 ;
+ $\166 -> $\300 ;
+ $\167 -> $\301 ;
+ $\170 -> $\302 ;
+ $\200 -> $\303 ;
+ $\212 -> $\304 ;
+ $\213 -> $\305 ;
+ $\214 -> $\306 ;
+ $\215 -> $\307 ;
+ $\216 -> $\310 ;
+ $\217 -> $\311 ;
+ $\220 -> $\312 ;
+ $\232 -> $\313 ;
+ $\233 -> $\314 ;
+ $\234 -> $\315 ;
+ $\235 -> $\316 ;
+ $\236 -> $\317 ;
+ $\237 -> $\320 ;
+ $\240 -> $\321 ;
+ $\252 -> $\322 ;
+ $\253 -> $\323 ;
+ $\254 -> $\324 ;
+ $\255 -> $\325 ;
+ $\256 -> $\326 ;
+ $\257 -> $\327 ;
+ $\260 -> $\330 ;
+ $\261 -> $\331 ;
+ $\262 -> $\332 ;
+ $\263 -> $\333 ;
+ $\264 -> $\334 ;
+ $\265 -> $\335 ;
+ $\266 -> $\336 ;
+ $\267 -> $\337 ;
+ $\270 -> $\340 ;
+ $\271 -> $\341 ;
+ $\272 -> $\342 ;
+ $\273 -> $\343 ;
+ $\274 -> $\344 ;
+ $\275 -> $\345 ;
+ $\276 -> $\346 ;
+ $\277 -> $\347 ;
+ $\312 -> $\350 ;
+ $\313 -> $\351 ;
+ $\314 -> $\352 ;
+ $\315 -> $\353 ;
+ $\316 -> $\354 ;
+ $\317 -> $\355 ;
+ $\332 -> $\356 ;
+ $\333 -> $\357 ;
+ $\334 -> $\360 ;
+ $\335 -> $\361 ;
+ $\336 -> $\362 ;
+ $\337 -> $\363 ;
+ $\352 -> $\364 ;
+ $\353 -> $\365 ;
+ $\354 -> $\366 ;
+ $\355 -> $\367 ;
+ $\356 -> $\370 ;
+ $\357 -> $\371 ;
+ $\372 -> $\372 ;
+ $\373 -> $\373 ;
+ $\374 -> $\374 ;
+ $\375 -> $\375 ;
+ $\376 -> $\376 ;
+ $\377 -> $\377
end.
diff --git a/src/swab_hexdump.erl b/src/swab_hexdump.erl
new file mode 100644
index 0000000..b104c08
--- /dev/null
+++ b/src/swab_hexdump.erl
@@ -0,0 +1,94 @@
+%%%-------------------------------------------------------------------
+%%% File: swab_hexdump.erl
+%%% @author Eric Pailleau
+%%% @copyright 2014 crownedgrouse.com
+%%% @doc
+%%% hexdump module for swab
+%%% @end
+%%%
+%%% Permission to use, copy, modify, and/or distribute this software
+%%% for any purpose with or without fee is hereby granted, provided
+%%% that the above copyright notice and this permission notice appear
+%%% in all copies.
+%%%
+%%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+%%% WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+%%% WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+%%% AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+%%% CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+%%% LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+%%% NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+%%% CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+%%%
+%%% Created : 2014-07-14
+%%%-------------------------------------------------------------------
+-module(swab_hexdump).
+
+-export([hexdump/1, hexdump/2]).
+
+-include("swab_hexdump.hrl").
+
+%%-------------------------------------------------------------------------
+%%@doc Main function call
+%%@end
+%%-------------------------------------------------------------------------
+-spec hexdump(binary() | [any()]) -> 'ok'.
+
+hexdump(Data) when is_binary(Data) -> hexdump(binary_to_list(Data), #hexdump{});
+hexdump(Data) when is_list(Data) -> hexdump(Data, #hexdump{}).
+
+%%-------------------------------------------------------------------------
+%%@doc Treat data
+%%@end
+%%-------------------------------------------------------------------------
+-spec hexdump(list(), #hexdump{prefix::string(),data::string(),width::integer(),nb::integer(),canonical::boolean(),sep::string(),line::integer(),io::atom() | pid()}) -> 'ok'.
+
+hexdump(L, R) when is_list(L),
+ is_tuple(R),
+ (length(L)=< (R#hexdump.width * R#hexdump.nb)) -> hexdump_line(L, R);
+hexdump(L, R) when is_list(L),
+ is_tuple(R),
+ (length(L)> R#hexdump.width * R#hexdump.nb) -> % Take width*nb octets , and let's treat it, then the remaining
+ {A, B} = lists:split(R#hexdump.width * R#hexdump.nb, L),
+ hexdump_line(A, R),
+ case B of
+ [] -> io:fwrite(R#hexdump.io, "",[]);
+ _ -> hexdump(B, R#hexdump{line= (R#hexdump.line + 1)})
+ end.
+
+%%-------------------------------------------------------------------------
+%%@doc Treat line
+%%@end
+%%-------------------------------------------------------------------------
+-spec hexdump_line(list(), #hexdump{}) -> 'ok'.
+
+hexdump_line(A, R)
+ when R#hexdump.canonical =:= true -> io:fwrite(R#hexdump.io, R#hexdump.prefix, [R#hexdump.line * R#hexdump.width * R#hexdump.nb] ),
+ lists:foreach(fun(X) -> io:fwrite(R#hexdump.io, R#hexdump.data, [X]) end,A) ,
+ % If the line is not complete, do it with blanks
+ io:fwrite(R#hexdump.io, string:copies(" ",round(R#hexdump.width * R#hexdump.nb) - length(A)),[]),
+ io:fwrite(R#hexdump.io, " ~s",[R#hexdump.sep]),
+ lists:foreach(fun(X) -> io:fwrite(R#hexdump.io, "~s", [hexdump_printable(X)]) end,A),
+ io:fwrite(R#hexdump.io, "~s",[R#hexdump.sep]),
+ io:fwrite(R#hexdump.io, "~n",[]);
+
+hexdump_line(A, R)
+ when R#hexdump.canonical =:= false -> io:fwrite(R#hexdump.io, R#hexdump.prefix, [R#hexdump.line * R#hexdump.width * R#hexdump.nb] ),
+ lists:foreach(fun(X) -> io:fwrite(R#hexdump.io, R#hexdump.data, [X]) end,A) ,
+ % If the line is not complete, do it with blanks
+ io:fwrite(R#hexdump.io, string:copies(" ",round(R#hexdump.width * R#hexdump.nb) - length(A)),[]),
+ io:fwrite(R#hexdump.io, " ",[]),
+ io:fwrite(R#hexdump.io, "~n",[]).
+
+%%-------------------------------------------------------------------------
+%%@doc Is character printable or not ?
+%%@end
+%%-------------------------------------------------------------------------
+-spec hexdump_printable(_) -> [any(),...].
+
+hexdump_printable(X) -> case ((X>31) and (X<128)) of
+ true -> [X] ;
+ false -> "."
+ end.
+
+
diff --git a/include/swab_tar.hrl b/src/swab_tar.erl
similarity index 76%
rename from include/swab_tar.hrl
rename to src/swab_tar.erl
index 6839136..f968eff 100644
--- a/include/swab_tar.hrl
+++ b/src/swab_tar.erl
@@ -1,9 +1,9 @@
%%%-------------------------------------------------------------------
-%%% File: swab_tar.hrl
+%%% File: swab_tar.erl
%%% @author Eric Pailleau
%%% @copyright 2014 crownedgrouse.com
%%% @doc
-%%% Tar library
+%%% Tar module for swab
%%% @end
%%%
%%% Permission to use, copy, modify, and/or distribute this software
@@ -22,61 +22,72 @@
%%%
%%% Created : 2014-08-11
%%%-------------------------------------------------------------------
+-module(swab_tar).
+
+-export([fakeroot/1, change_user/2, change_group/2]).
%%-------------------------------------------------------------------------
%%@doc Replace Uid and User
%%@end
%%-------------------------------------------------------------------------
-tar_change_user(Data, {Uid, User}) when is_integer(Uid),
- is_list(User) -> tar_change_user(Data, {Uid, User}, []).
+-spec change_user(binary(), tuple()) -> binary().
+
+change_user(Data, {Uid, User}) when is_integer(Uid),
+ is_list(User) -> change_user(Data, {Uid, User}, []).
-tar_change_user([], {_, _}, Iolist) -> list_to_binary(lists:flatten(Iolist));
-tar_change_user(<>, {_, _}, Iolist) when size(Rest)=< 512 -> list_to_binary(lists:flatten(Iolist ++ [Rest]));
+change_user(<<>>, {_, _}, Iolist) -> list_to_binary(lists:flatten(Iolist));
+change_user(<>, {_, _}, Iolist) when size(Rest)=< 512 -> list_to_binary(lists:flatten(Iolist ++ [Rest]));
-tar_change_user(<>,
+change_user(<>,
{Uid, User},
Iolist) -> {Skip, NewHeader} = tar_change_header_user(Header, {Uid, User}),
case Skip of
- 0 -> tar_change_user(Rest, {Uid, User}, Iolist ++ [NewHeader]) ;
+ 0 -> change_user(Rest, {Uid, User}, Iolist ++ [NewHeader]) ;
_ -> <> = Rest,
- tar_change_user(Next, {Uid, User}, Iolist ++ [NewHeader, File])
+ change_user(Next, {Uid, User}, Iolist ++ [NewHeader, File])
end.
%%-------------------------------------------------------------------------
%%@doc Replace Gid and Group
%%@end
%%-------------------------------------------------------------------------
-tar_change_group(Data, {Gid, Group}) when is_integer(Gid),
- is_list(Group) -> tar_change_group(Data, {Gid, Group}, []).
+-spec change_group(binary(), tuple()) -> binary().
+
+change_group(Data, {Gid, Group}) when is_integer(Gid),
+ is_list(Group) -> change_group(Data, {Gid, Group}, []).
-tar_change_group([], {_, _}, Iolist) -> list_to_binary(lists:flatten(Iolist));
-tar_change_group(<>, {_, _}, Iolist) when size(Rest)=< 512 -> list_to_binary(lists:flatten(Iolist ++ [Rest]));
+change_group([], {_, _}, Iolist) -> list_to_binary(lists:flatten(Iolist));
+change_group(<>, {_, _}, Iolist) when size(Rest)=< 512 -> list_to_binary(lists:flatten(Iolist ++ [Rest]));
-tar_change_group(<>,
+change_group(<>,
{Gid, Group},
Iolist) -> {Skip, NewHeader} = tar_change_header_group(Header, {Gid, Group}),
case Skip of
- 0 -> tar_change_group(Rest, {Gid, Group}, Iolist ++ [NewHeader]) ;
+ 0 -> change_group(Rest, {Gid, Group}, Iolist ++ [NewHeader]) ;
_ -> <> = Rest,
- tar_change_group(Next, {Gid, Group}, Iolist ++ [NewHeader, File])
+ change_group(Next, {Gid, Group}, Iolist ++ [NewHeader, File])
end.
%%-------------------------------------------------------------------------
%%@doc Replace Uid/Gid and User/Group to 0/root
%%@end
%%-------------------------------------------------------------------------
-tar_fakeroot(Data) -> tar_fakeroot(Data, []).
+-spec fakeroot(binary()) -> binary().
+
+fakeroot(Data) -> fakeroot(Data, []).
+
+-spec fakeroot(binary(), iolist()) -> binary().
-tar_fakeroot([], Iolist) -> list_to_binary(lists:flatten(Iolist));
-tar_fakeroot(<>, Iolist) when size(Rest)=< 512 -> list_to_binary(lists:flatten(Iolist ++ [Rest]));
+fakeroot(<<>>, Iolist) -> list_to_binary(lists:flatten(Iolist));
+fakeroot(<>, Iolist) when size(Rest)=< 512 -> list_to_binary(lists:flatten(Iolist ++ [Rest]));
-tar_fakeroot(<>, Iolist) ->
+fakeroot(<>, Iolist) ->
{Skip, NewHeader1} = tar_change_header_user(Header, {0,"root"}),
{Skip, NewHeader} = tar_change_header_group(NewHeader1, {0,"root"}),
case Skip of
- 0 -> tar_fakeroot(Rest, Iolist ++ [NewHeader]) ;
+ 0 -> fakeroot(Rest, Iolist ++ [NewHeader]) ;
_ -> <> = Rest,
- tar_fakeroot(Next, Iolist ++ [NewHeader, File])
+ fakeroot(Next, Iolist ++ [NewHeader, File])
end.
%%-------------------------------------------------------------------------
@@ -86,6 +97,7 @@ tar_fakeroot(<>, Iolist) ->
%% or otherwise remaining padding zeroes at end of file.
%%@end
%%-------------------------------------------------------------------------
+-spec tar_change_header_user(binary(), tuple()) -> tuple().
tar_change_header_user(< tar_change_header(X).
%% or otherwise remaining padding zeroes at end of file.
%%@end
%%-------------------------------------------------------------------------
+-spec tar_change_header_group(binary(), tuple()) -> tuple().
+
tar_change_header_group(< tar_change_header(X).
%%@doc Remaining padding zeroes at end of file.
%%@end
%%-------------------------------------------------------------------------
+-spec tar_change_header(binary()) -> tuple().
+
tar_change_header(X) -> case binary:copy(<<0>>, size(X)) of
X -> {0, X} ;
- _ -> throw(invalid) % Neither valid header, nor zeroes padding.
+ _ -> throw(invalid), {0, X} % Neither valid header, nor zeroes padding.
end.
%%-------------------------------------------------------------------------
%%@doc Checksum of Tar Header
%%@end
%%-------------------------------------------------------------------------
+-spec checksum(binary()) -> integer().
+
checksum(H) -> checksum(H, 0).
checksum(<>, Sum) ->
@@ -165,9 +183,13 @@ checksum(<<>>, Sum) -> Sum.
%%@doc Cast to Octal
%%@end
%%-------------------------------------------------------------------------
+-spec to_octal(integer(), integer()) -> list().
+
to_octal(Int, Count) when Count > 1 ->
to_octal(Int, Count-1, [0]).
+-spec to_octal(integer(), integer(), list()) -> list().
+
to_octal(_, 0, Result) -> Result;
to_octal(Int, Count, Result) ->
to_octal(Int div 8, Count-1, [Int rem 8 + $0|Result]).
diff --git a/src/swab_tests.erl b/src/swab_tests.erl
index d43d38c..2ed2dd8 100644
--- a/src/swab_tests.erl
+++ b/src/swab_tests.erl
@@ -74,10 +74,6 @@ analyze_test() ->
,?assertEqual({ok, "love"}, swab:sync([{sub_word, 2}], " I\n love Erlang "))
,?assertEqual({ok, "love"}, swab:sync({sub_word, 2}, " I\n love Erlang "))
% jump
- ,?assertEqual({ok, "a"}, swab:sync([{jump, first}], "a\r\nb\nc\rd\fe\x85f\x0bg"))
- ,?assertEqual({ok, "a"}, swab:sync({jump, first}, "a\r\nb\nc\rd\fe\x85f\x0bg"))
- ,?assertEqual({ok, "g"}, swab:sync([{jump, last}], "a\r\nb\nc\rd\fe\x85f\x0bg"))
- ,?assertEqual({ok, "g"}, swab:sync({jump, last}, "a\r\nb\nc\rd\fe\x85f\x0bg"))
,?assertEqual({ok, "d"++?NL++"e"++?NL++"f"++?NL++"g"}, swab:sync([{jump, 3}], "a\r\nb\nc\rd\fe\x85f\x0bg"))
,?assertEqual({ok, "d"++?NL++"e"++?NL++"f"++?NL++"g"}, swab:sync({jump, 3}, "a\r\nb\nc\rd\fe\x85f\x0bg"))
,?assertEqual({ok, "a"++?NL++"b"++?NL++"c"++?NL++"d"++?NL++"e"++?NL++"f"++?NL++"g"},
@@ -87,6 +83,10 @@ analyze_test() ->
,?assertEqual({ok, "f"++?NL++"g"}, swab:sync([{jump, -2}], "a\r\nb\nc\rd\fe\x85f\x0bg"))
,?assertEqual({ok, "f"++?NL++"g"}, swab:sync({jump, -2}, "a\r\nb\nc\rd\fe\x85f\x0bg"))
% nblines
+ ,?assertEqual({ok, "a"}, swab:sync([{nblines, first}], "a\r\nb\nc\rd\fe\x85f\x0bg"))
+ ,?assertEqual({ok, "a"}, swab:sync({nblines, first}, "a\r\nb\nc\rd\fe\x85f\x0bg"))
+ ,?assertEqual({ok, "g"}, swab:sync([{nblines, last}], "a\r\nb\nc\rd\fe\x85f\x0bg"))
+ ,?assertEqual({ok, "g"}, swab:sync({nblines, last}, "a\r\nb\nc\rd\fe\x85f\x0bg"))
,?assertEqual({ok, "123" }, swab:sync([{nblines, 1}], "123" ++ ?NL ++ "456" ++ ?NL ++ "789"))
,?assertEqual({ok, "123" }, swab:sync({nblines, 1}, "123" ++ ?NL ++ "456" ++ ?NL ++ "789"))
,?assertEqual({ok, "123" ++ ?NL ++ "456"}, swab:sync([{nblines, 2}], "123" ++ ?NL ++ "456" ++ ?NL ++ "789"))
@@ -107,12 +107,7 @@ analyze_test() ->
,?assertEqual({match, {fread, "~10f~d"}," 5.67899"},swab:sync({fread, "~10f~d"}," 5.67899"))
,?assertEqual({match, {fread, ":~10s:~10c:"},": alan : joe :"},swab:sync({fread, ":~10s:~10c:"},": alan : joe :"))
% regexp
-
- %*** BUFFER ***
-
- %*** MISC ***
- % tar
-
- .
+ ,?assertEqual({match, {regexp, {"^[A-Z]",[]}},"ABCDEFG"},swab:sync([{cast, upper}, {regexp, "^[A-Z]"}, {cast, lower}], "abcdefg"))
+ ,ok.
-endif.
diff --git a/src/test.hrl b/src/test.hrl
deleted file mode 100644
index e69de29..0000000