Skip to content

Commit

Permalink
Added align method
Browse files Browse the repository at this point in the history
Signed-off-by: Andrea Zoppi <[email protected]>
  • Loading branch information
TexZK committed Mar 7, 2024
1 parent 68fb93c commit 698174a
Show file tree
Hide file tree
Showing 18 changed files with 182 additions and 23 deletions.
1 change: 1 addition & 0 deletions docs/_autosummary/hexrec.base.BaseFile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ BaseFile
:nosignatures:

~BaseFile.__init__
~BaseFile.align
~BaseFile.append
~BaseFile.apply_records
~BaseFile.clear
Expand Down
1 change: 1 addition & 0 deletions docs/_autosummary/hexrec.formats.asciihex.AsciiHexFile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ AsciiHexFile
:nosignatures:

~AsciiHexFile.__init__
~AsciiHexFile.align
~AsciiHexFile.append
~AsciiHexFile.apply_records
~AsciiHexFile.clear
Expand Down
1 change: 1 addition & 0 deletions docs/_autosummary/hexrec.formats.avr.AvrFile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ AvrFile
:nosignatures:

~AvrFile.__init__
~AvrFile.align
~AvrFile.append
~AvrFile.apply_records
~AvrFile.clear
Expand Down
1 change: 1 addition & 0 deletions docs/_autosummary/hexrec.formats.ihex.IhexFile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ IhexFile
:nosignatures:

~IhexFile.__init__
~IhexFile.align
~IhexFile.append
~IhexFile.apply_records
~IhexFile.clear
Expand Down
1 change: 1 addition & 0 deletions docs/_autosummary/hexrec.formats.mos.MosFile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ MosFile
:nosignatures:

~MosFile.__init__
~MosFile.align
~MosFile.append
~MosFile.apply_records
~MosFile.clear
Expand Down
1 change: 1 addition & 0 deletions docs/_autosummary/hexrec.formats.raw.RawFile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ RawFile
:nosignatures:

~RawFile.__init__
~RawFile.align
~RawFile.append
~RawFile.apply_records
~RawFile.clear
Expand Down
1 change: 1 addition & 0 deletions docs/_autosummary/hexrec.formats.srec.SrecFile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ SrecFile
:nosignatures:

~SrecFile.__init__
~SrecFile.align
~SrecFile.append
~SrecFile.apply_records
~SrecFile.clear
Expand Down
1 change: 1 addition & 0 deletions docs/_autosummary/hexrec.formats.titxt.TiTxtFile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ TiTxtFile
:nosignatures:

~TiTxtFile.__init__
~TiTxtFile.align
~TiTxtFile.append
~TiTxtFile.apply_records
~TiTxtFile.clear
Expand Down
1 change: 1 addition & 0 deletions docs/_autosummary/hexrec.formats.xtek.XtekFile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ XtekFile
:nosignatures:

~XtekFile.__init__
~XtekFile.align
~XtekFile.append
~XtekFile.apply_records
~XtekFile.clear
Expand Down
2 changes: 1 addition & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ sphinx >= 7
sphinx-click
sphinx-autodoc-typehints

bytesparse >= 0.0.8
bytesparse >= 1.0.0
colorama
furo
twine
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ classifiers = [
"Topic :: Utilities",
]
dependencies = [
"bytesparse >= 0.0.8", # comment out and use the one below for development instead
"bytesparse >= 1.0.0", # comment out and use the one below for development instead
# "bytesparse @ git+https://github.com/TexZK/bytesparse.git", # only for development
"click",
"colorama",
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
bytesparse >= 0.0.8
bytesparse >= 1.0.0
click
colorama
53 changes: 53 additions & 0 deletions src/hexrec/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1974,6 +1974,59 @@ def _is_line_empty(cls, line: AnyBytes) -> bool:

return not line or line.isspace()

def align(
self,
modulo: int,
start: Optional[int] = None,
endex: Optional[int] = None,
pattern: Union[int, AnyBytes] = 0,
) -> Self:
r"""Pads blocks to align their boundaries.
It fills memory holes of the underlying :attr:`memory` within the
specified range with a `pattern`, so that memory blocks are aligned to
the required `modulo`.
Any stored :attr:`records` are discarded upon return.
Args:
modulo (int):
Alignment modulo.
start (int):
Inclusive start address of the specified range.
If ``None``, start from the beginning of the :attr:`memory`.
endex (int):
Exclusive end address of the specified range.
If ``None``, extend after the end of the :attr:`memory`.
pattern (bytes or int):
Byte pattern for flooding.
Returns:
:class:`BaseFile`: *self*.
See Also:
:attr:`memory`
:meth:`discard_records`
:meth:`bytesparse.base.MutableMemory.align`
Examples:
**NOTE:** These examples are provided by :class:`BaseFile`.
Inherited classes for specific *formats* may require an adaptation.
>>> from hexrec import SrecFile
>>> file = SrecFile.from_blocks([[123, b'abc'], [134, b'xyz']])
>>> _ = file.align(4, pattern=b'.')
>>> file.memory.to_blocks()
[[120, b'...abc..'], [132, b'..xyz...']]
"""

self.memory.align(modulo, start=start, endex=endex, pattern=pattern)
self.discard_records()
return self

def append(self, item: Union[AnyBytes, int]) -> Self:
r"""Appends a byte.
Expand Down
96 changes: 76 additions & 20 deletions src/hexrec/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,9 @@ def main() -> None:
Forces the output file format.
By default it is that of the input file.
""")
@click.option('-m', '--modulo', type=BYTE_INT, default=4, help="""
Alignment modulo.
""")
@click.option('-s', '--start', type=BASED_INT, help="""
Inclusive start address. Negative values are referred to the end of the data.
By default it applies from the start of the data contents.
Expand All @@ -329,12 +332,65 @@ def main() -> None:
Exclusive end address. Negative values are referred to the end of the data.
By default it applies till the end of the data contents.
""")
@click.option('-v', '--value', type=BYTE_INT, default=0, help="""
Byte value used to flood alignment padding.
""")
@click.option('-w', '--width', type=BASED_INT, help="""
Sets the length of the record data field, in bytes.
By default it is that of the input file.
""")
@click.argument('infile', type=FILE_PATH_IN)
@click.argument('outfile', type=FILE_PATH_OUT)
@click.argument('infile', type=FILE_PATH_IN, required=False)
@click.argument('outfile', type=FILE_PATH_OUT, required=False)
def align(
input_format: Optional[str],
output_format: Optional[str],
modulo: int,
start: Optional[int],
endex: Optional[int],
value: Optional[int],
width: Optional[int],
infile: str,
outfile: str,
) -> None:
r"""Pads blocks to align their boundaries.
``INFILE`` is the path of the input file.
Set to ``-`` to read from standard input; input format required.
``OUTFILE`` is the path of the output file.
Set to ``-`` to write to standard output.
Leave empty to overwrite ``INFILE``.
"""

with SingleFileInOutCtxMgr(infile, input_format, outfile, output_format, width) as ctx:
ctx.output_file.align(modulo, start=start, endex=endex, pattern=value)


# ----------------------------------------------------------------------------

@main.command()
@click.option('-i', '--input-format', type=FORMAT_CHOICE, help="""
Forces the input file format.
Required for the standard input.
""")
@click.option('-o', '--output-format', type=FORMAT_CHOICE, help="""
Forces the output file format.
By default it is that of the input file.
""")
@click.option('-s', '--start', type=BASED_INT, help="""
Inclusive start address. Negative values are referred to the end of the data.
By default it applies from the start of the data contents.
""")
@click.option('-e', '--endex', type=BASED_INT, help="""
Exclusive end address. Negative values are referred to the end of the data.
By default it applies till the end of the data contents.
""")
@click.option('-w', '--width', type=BASED_INT, help="""
Sets the length of the record data field, in bytes.
By default it is that of the input file.
""")
@click.argument('infile', type=FILE_PATH_IN, required=False)
@click.argument('outfile', type=FILE_PATH_OUT, required=False)
def clear(
input_format: Optional[str],
output_format: Optional[str],
Expand Down Expand Up @@ -373,8 +429,8 @@ def clear(
Sets the length of the record data field, in bytes.
By default it is that of the input file.
""")
@click.argument('infile', type=FILE_PATH_IN)
@click.argument('outfile', type=FILE_PATH_OUT)
@click.argument('infile', type=FILE_PATH_IN, required=False)
@click.argument('outfile', type=FILE_PATH_OUT, required=False)
def convert(
input_format: Optional[str],
output_format: Optional[str],
Expand Down Expand Up @@ -424,8 +480,8 @@ def convert(
Sets the length of the record data field, in bytes.
By default it is that of the input file.
""")
@click.argument('infile', type=FILE_PATH_IN)
@click.argument('outfile', type=FILE_PATH_OUT)
@click.argument('infile', type=FILE_PATH_IN, required=False)
@click.argument('outfile', type=FILE_PATH_OUT, required=False)
def crop(
input_format: Optional[str],
output_format: Optional[str],
Expand Down Expand Up @@ -476,8 +532,8 @@ def crop(
Sets the length of the record data field, in bytes.
By default it is that of the input file.
""")
@click.argument('infile', type=FILE_PATH_IN)
@click.argument('outfile', type=FILE_PATH_OUT)
@click.argument('infile', type=FILE_PATH_IN, required=False)
@click.argument('outfile', type=FILE_PATH_OUT, required=False)
def delete(
input_format: Optional[str],
output_format: Optional[str],
Expand Down Expand Up @@ -527,8 +583,8 @@ def delete(
Sets the length of the record data field, in bytes.
By default it is that of the input file.
""")
@click.argument('infile', type=FILE_PATH_IN)
@click.argument('outfile', type=FILE_PATH_OUT)
@click.argument('infile', type=FILE_PATH_IN, required=False)
@click.argument('outfile', type=FILE_PATH_OUT, required=False)
def fill(
input_format: Optional[str],
output_format: Optional[str],
Expand Down Expand Up @@ -579,8 +635,8 @@ def fill(
Sets the length of the record data field, in bytes.
By default it is that of the input file.
""")
@click.argument('infile', type=FILE_PATH_IN)
@click.argument('outfile', type=FILE_PATH_OUT)
@click.argument('infile', type=FILE_PATH_IN, required=False)
@click.argument('outfile', type=FILE_PATH_OUT, required=False)
def flood(
input_format: Optional[str],
output_format: Optional[str],
Expand Down Expand Up @@ -941,8 +997,8 @@ def merge(
Sets the length of the record data field, in bytes.
By default it is that of the input file.
""")
@click.argument('infile', type=FILE_PATH_IN)
@click.argument('outfile', type=FILE_PATH_OUT)
@click.argument('infile', type=FILE_PATH_IN, required=False)
@click.argument('outfile', type=FILE_PATH_OUT, required=False)
def shift(
input_format: Optional[str],
output_format: Optional[str],
Expand Down Expand Up @@ -972,7 +1028,7 @@ def shift(
Forces the input file format.
Required for the standard input.
""")
@click.argument('infile', type=FILE_PATH_IN)
@click.argument('infile', type=FILE_PATH_IN, required=False)
def validate(
input_format: Optional[str],
infile: str,
Expand Down Expand Up @@ -1001,7 +1057,7 @@ def srec() -> None:
@srec.command()
@click.option('-f', '--format', 'format', type=DATA_FMT_CHOICE,
default='ascii', help='Header data format.')
@click.argument('infile', type=FILE_PATH_IN)
@click.argument('infile', type=FILE_PATH_IN, required=False)
def get_header(
format: str,
infile: str,
Expand All @@ -1028,8 +1084,8 @@ def get_header(
@click.option('-f', '--format', 'format', type=DATA_FMT_CHOICE,
default='ascii', help='Header data format.')
@click.argument('header', type=str)
@click.argument('infile', type=FILE_PATH_IN)
@click.argument('outfile', type=FILE_PATH_OUT)
@click.argument('infile', type=FILE_PATH_IN, required=False)
@click.argument('outfile', type=FILE_PATH_OUT, required=False)
def set_header(
format: str,
header: str,
Expand Down Expand Up @@ -1071,8 +1127,8 @@ def set_header(

# noinspection PyShadowingBuiltins
@srec.command()
@click.argument('infile', type=FILE_PATH_IN)
@click.argument('outfile', type=FILE_PATH_OUT)
@click.argument('infile', type=FILE_PATH_IN, required=False)
@click.argument('outfile', type=FILE_PATH_OUT, required=False)
def del_header(
infile: str,
outfile: str,
Expand Down
8 changes: 8 additions & 0 deletions tests/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -983,6 +983,14 @@ def test__is_line_empty(self):
assert File._is_line_empty(b'') is True
assert File._is_line_empty(b' \t\v\r\n') is True

def test_align(self):
File = self.File
file = File.from_blocks([[123, b'abc'], [134, b'xyz']])
returned = file.align(4, pattern=b'.')
assert returned is file
assert file._memory.to_blocks() == [[120, b'...abc..'], [132, b'..xyz...']]
assert file._records is None

def test_append(self):
File = self.File
file = File.from_bytes(b'abc', offset=5)
Expand Down
11 changes: 11 additions & 0 deletions tests/test_cli/test_hexrec_align_-m_3_triangle.mot
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
S0030000FC
S1130000000102030405060708090A0B0C0D0E0F74
S1130010000102030405060708090A0B0C0D0E0073
S1130020000002030405060708090A0B0C0D000072
S10F0033030405060708090A0B0C000072
S10F004200000405060708090A0B000072
S10C00540005060708090A000072
S109006606070809000072
S109007500000708000072
S5030008F4
S9030000FC
11 changes: 11 additions & 0 deletions tests/test_cli/test_hexrec_align_triangle.mot
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
S0030000FC
S1130000000102030405060708090A0B0C0D0E0F74
S1130010000102030405060708090A0B0C0D0E0073
S1130020000002030405060708090A0B0C0D000072
S1130030000000030405060708090A0B0C00000071
S10B00440405060708090A0B74
S10B00540005060708090A0073
S10B0064000006070809000072
S10B0074000000070800000071
S5030008F4
S9030000FC
11 changes: 11 additions & 0 deletions tests/test_cli/triangle.mot
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
S0030000FC
S1130000000102030405060708090A0B0C0D0E0F74
S11100110102030405060708090A0B0C0D0E74
S10F002202030405060708090A0B0C0D74
S10D0033030405060708090A0B0C74
S10B00440405060708090A0B74
S109005505060708090A74
S10700660607080974
S1050077070874
S5030008F4
S9030000FC

0 comments on commit 698174a

Please sign in to comment.