Compare commits
70 commits
Author | SHA1 | Date | |
---|---|---|---|
2252b7d732 | |||
88d228644e | |||
3408183b39 | |||
425fa77900 | |||
4cd660ffd5 | |||
dd1a8abdd4 | |||
aeb8eff350 | |||
2e46790ece | |||
4f0fdfa602 | |||
c30f2f3fd2 | |||
4e6b2b8f5a | |||
49bd4b5c76 | |||
4479fdce62 | |||
bdbbf7dc16 | |||
40567d5a3a | |||
c095c40644 | |||
d1609849a1 | |||
b96d26de81 | |||
0b63dd12ee | |||
c55864a51b | |||
a133b3a49d | |||
ffa5885ed6 | |||
c1dde797b5 | |||
ae4bcff24a | |||
852c931d8b | |||
55cd3b2659 | |||
d8068a6f5f | |||
b28e384149 | |||
c6d2d50c0f | |||
2f4c0d3679 | |||
9d105bc3a5 | |||
b90b7ae64f | |||
e9c327a62f | |||
d939939723 | |||
4b730b4824 | |||
3dc9e88e24 | |||
dcff34e06b | |||
613354034d | |||
c1c4f048cb | |||
e7db978a3c | |||
d30c30995f | |||
5f8d6b0c0b | |||
72d2db378f | |||
7046dfb1e5 | |||
1d85ddd0e9 | |||
ecb0c751d8 | |||
99e1a2d850 | |||
c4ff2347ff | |||
c18e772928 | |||
735d2b4f7a | |||
4985672ea2 | |||
0a6afe6148 | |||
5b3a7e3994 | |||
4cb4184338 | |||
17f89e5a68 | |||
da2a0f7b1c | |||
0449ab389e | |||
af235ff878 | |||
fe04dc7018 | |||
be67425d21 | |||
bbdcd660a5 | |||
ea845f2552 | |||
0299129ea6 | |||
2364f53649 | |||
58daa1130d | |||
875e4bb2a4 | |||
41fde43eed | |||
4670f0f3c1 | |||
cb79e4e45c | |||
efffb8c147 |
24 changed files with 3185 additions and 735 deletions
|
@ -7,6 +7,7 @@ set(SimpleArchiver_SOURCES
|
||||||
src/main.c
|
src/main.c
|
||||||
src/parser.c
|
src/parser.c
|
||||||
src/helpers.c
|
src/helpers.c
|
||||||
|
src/archiver.c
|
||||||
src/data_structures/linked_list.c
|
src/data_structures/linked_list.c
|
||||||
src/data_structures/hash_map.c
|
src/data_structures/hash_map.c
|
||||||
src/data_structures/priority_heap.c
|
src/data_structures/priority_heap.c
|
||||||
|
|
210
LICENSE
210
LICENSE
|
@ -1,201 +1,15 @@
|
||||||
Apache License
|
ISC License
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
Copyright (c) 2024 Stephen Seo
|
||||||
|
|
||||||
1. Definitions.
|
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.
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
the copyright owner that is granting the License.
|
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
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
PERFORMANCE OF THIS SOFTWARE.
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
29
README.md
29
README.md
|
@ -1,6 +1,7 @@
|
||||||
# Simple Archiver
|
# Simple Archiver
|
||||||
|
|
||||||
This program is not yet finished! You can track progress
|
This program ~~is not yet~~ almost finished! Basic functionality is implemented
|
||||||
|
and only some advanced features are missing. You can track progress
|
||||||
[here](https://git.seodisparate.com/stephenseo/SimpleArchiver/projects/3).
|
[here](https://git.seodisparate.com/stephenseo/SimpleArchiver/projects/3).
|
||||||
|
|
||||||
This program exists because I could not get `tar` or `ar` to compile with
|
This program exists because I could not get `tar` or `ar` to compile with
|
||||||
|
@ -9,6 +10,30 @@ archiver will be written with support for Cosmopolitan in mind. This means
|
||||||
sticking to the C programming language and possibly using Cosmopolitan-specfic
|
sticking to the C programming language and possibly using Cosmopolitan-specfic
|
||||||
API calls.
|
API calls.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Usage flags:
|
||||||
|
-c : create archive file
|
||||||
|
-x : extract archive file
|
||||||
|
-t : examine archive file
|
||||||
|
-f <filename> : filename to work on
|
||||||
|
Use "-f -" to work on stdout when creating archive or stdin when reading archive
|
||||||
|
NOTICE: "-f" is not affected by "-C"!
|
||||||
|
-C <dir> : Change current working directory before archiving/extracting
|
||||||
|
--compressor <full_compress_cmd> : requires --decompressor
|
||||||
|
--decompressor <full_decompress_cmd> : requires --compressor
|
||||||
|
Specifying "--decompressor" when extracting overrides archive file's stored decompressor cmd
|
||||||
|
--overwrite-create : allows overwriting an archive file
|
||||||
|
--overwrite-extract : allows overwriting when extracting
|
||||||
|
--no-abs-symlink : do not store absolute paths for symlinks
|
||||||
|
--temp-files-dir <dir> : where to store temporary files created when compressing (defaults to current working directory)
|
||||||
|
-- : specifies remaining arguments are files to archive/extract
|
||||||
|
If creating archive file, remaining args specify files to archive.
|
||||||
|
If extracting archive file, remaining args specify files to extract.
|
||||||
|
|
||||||
|
Note that `--compressor` and `--decompressor` cmds must accept data from stdin
|
||||||
|
and return processed data to stdout.
|
||||||
|
|
||||||
## LICENSE Information
|
## LICENSE Information
|
||||||
|
|
||||||
Uses the [Apache License 2.0](https://choosealicense.com/licenses/apache-2.0).
|
Uses the [ISC License](https://choosealicense.com/licenses/isc/).
|
||||||
|
|
|
@ -7,6 +7,7 @@ SOURCES = \
|
||||||
../src/main.c \
|
../src/main.c \
|
||||||
../src/parser.c \
|
../src/parser.c \
|
||||||
../src/helpers.c \
|
../src/helpers.c \
|
||||||
|
../src/archiver.c \
|
||||||
../src/algorithms/linear_congruential_gen.c \
|
../src/algorithms/linear_congruential_gen.c \
|
||||||
../src/data_structures/linked_list.c \
|
../src/data_structures/linked_list.c \
|
||||||
../src/data_structures/hash_map.c \
|
../src/data_structures/hash_map.c \
|
||||||
|
@ -16,6 +17,7 @@ HEADERS = \
|
||||||
../src/parser.h \
|
../src/parser.h \
|
||||||
../src/parser_internal.h \
|
../src/parser_internal.h \
|
||||||
../src/helpers.h \
|
../src/helpers.h \
|
||||||
|
../src/archiver.h \
|
||||||
../src/algorithms/linear_congruential_gen.h \
|
../src/algorithms/linear_congruential_gen.h \
|
||||||
../src/data_structures/linked_list.h \
|
../src/data_structures/linked_list.h \
|
||||||
../src/data_structures/hash_map.h \
|
../src/data_structures/hash_map.h \
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
# File Format
|
# File Format
|
||||||
|
|
||||||
|
Note that any unused bytes/bits should be zeroed-out before being written.
|
||||||
|
|
||||||
## Format Version 0
|
## Format Version 0
|
||||||
|
|
||||||
File extension is "*.simplearchive"
|
File extension is "*.simplearchive"
|
||||||
|
@ -43,8 +45,18 @@ Following the file-count bytes, the following bytes are added for each file:
|
||||||
3. 4 bytes bit-flags
|
3. 4 bytes bit-flags
|
||||||
1. The first byte
|
1. The first byte
|
||||||
1. The first bit is set if the file is a symbolic link.
|
1. The first bit is set if the file is a symbolic link.
|
||||||
|
2. The second bit is "user read permission".
|
||||||
|
3. The third bit is "user write permission".
|
||||||
|
4. The fourth bit is "user execute permission".
|
||||||
|
5. The fifth bit is "group read permission".
|
||||||
|
6. The sixth bit is "group write permission".
|
||||||
|
7. The seventh bit is "group execute permission".
|
||||||
|
8. The eighth bit is "other read permission".
|
||||||
2. The second byte.
|
2. The second byte.
|
||||||
1. Currently unused.
|
1. The first bit is "other write permission".
|
||||||
|
2. The second bit is "other execute permission".
|
||||||
|
3. The third bit is UNSET if relative links are preferred, and is SET
|
||||||
|
if absolute links are preferred.
|
||||||
3. The third byte.
|
3. The third byte.
|
||||||
1. Currently unused.
|
1. Currently unused.
|
||||||
4. The fourth byte.
|
4. The fourth byte.
|
||||||
|
@ -61,5 +73,6 @@ Following the file-count bytes, the following bytes are added for each file:
|
||||||
Is a NULL-terminated string. If the previous "size" value is 0, then
|
Is a NULL-terminated string. If the previous "size" value is 0, then
|
||||||
this entry does not exist and should be skipped.
|
this entry does not exist and should be skipped.
|
||||||
5. If this file is NOT a symbolic link:
|
5. If this file is NOT a symbolic link:
|
||||||
1. 8 bytes 64-bit unsigned integer "size of filename in this archive file".
|
1. 8 bytes 64-bit unsigned integer "size of filename in this archive file"
|
||||||
|
in big-endian.
|
||||||
2. X bytes file data (length defined by previous value).
|
2. X bytes file data (length defined by previous value).
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
/*
|
// ISC License
|
||||||
* Copyright 2024 Stephen Seo
|
//
|
||||||
*
|
// Copyright (c) 2024 Stephen Seo
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
//
|
||||||
* you may not use this file except in compliance with the License.
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* You may obtain a copy of the License at
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
*
|
// copyright notice and this permission notice appear in all copies.
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
*
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
* See the License for the specific language governing permissions and
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
* limitations under the License.
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
*
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
* `linear_congruential_gen.c` is the source for the linear congruential
|
//
|
||||||
* generator algorithm.
|
// `linear_congruential_gen.c` is the source for the linear congruential
|
||||||
*/
|
// generator algorithm.
|
||||||
|
|
||||||
#include "linear_congruential_gen.h"
|
#include "linear_congruential_gen.h"
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
/*
|
// ISC License
|
||||||
* Copyright 2024 Stephen Seo
|
//
|
||||||
*
|
// Copyright (c) 2024 Stephen Seo
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
//
|
||||||
* you may not use this file except in compliance with the License.
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* You may obtain a copy of the License at
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
*
|
// copyright notice and this permission notice appear in all copies.
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
*
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
* See the License for the specific language governing permissions and
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
* limitations under the License.
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
*
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
* `linear_congruential_gen.h` is the header for the linear congruential
|
//
|
||||||
* generator algorithm.
|
// `linear_congruential_gen.h` is the header for the linear congruential
|
||||||
*/
|
// generator algorithm.
|
||||||
|
|
||||||
#ifndef SEODISPARATE_COM_ALGORITHMS_LINEAR_CONGRUENTIAL_GEN_H_
|
#ifndef SEODISPARATE_COM_ALGORITHMS_LINEAR_CONGRUENTIAL_GEN_H_
|
||||||
#define SEODISPARATE_COM_ALGORITHMS_LINEAR_CONGRUENTIAL_GEN_H_
|
#define SEODISPARATE_COM_ALGORITHMS_LINEAR_CONGRUENTIAL_GEN_H_
|
||||||
|
|
1913
src/archiver.c
Normal file
1913
src/archiver.c
Normal file
File diff suppressed because it is too large
Load diff
73
src/archiver.h
Normal file
73
src/archiver.h
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
// ISC License
|
||||||
|
//
|
||||||
|
// Copyright (c) 2024 Stephen Seo
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// `archiver.h` is the header for an interface to creating an archive file.
|
||||||
|
|
||||||
|
#ifndef SEODISPARATE_COM_SIMPLE_ARCHIVER_ARCHIVER_H_
|
||||||
|
#define SEODISPARATE_COM_SIMPLE_ARCHIVER_ARCHIVER_H_
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "data_structures/hash_map.h"
|
||||||
|
#include "data_structures/linked_list.h"
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
typedef struct SDArchiverState {
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
unsigned int flags;
|
||||||
|
const SDArchiverParsed *parsed;
|
||||||
|
FILE *out_f;
|
||||||
|
SDArchiverHashMap *map;
|
||||||
|
size_t count;
|
||||||
|
size_t max;
|
||||||
|
size_t digits;
|
||||||
|
} SDArchiverState;
|
||||||
|
|
||||||
|
enum SDArchiverStateReturns {
|
||||||
|
SDAS_SUCCESS = 0,
|
||||||
|
SDAS_HEADER_ALREADY_WRITTEN = 1,
|
||||||
|
SDAS_FAILED_TO_WRITE,
|
||||||
|
SDAS_NO_COMPRESSOR,
|
||||||
|
SDAS_NO_DECOMPRESSOR,
|
||||||
|
SDAS_INVALID_PARSED_STATE,
|
||||||
|
SDAS_INVALID_FILE,
|
||||||
|
SDAS_INTERNAL_ERROR,
|
||||||
|
SDAS_FAILED_TO_CREATE_MAP,
|
||||||
|
SDAS_FAILED_TO_EXTRACT_SYMLINK,
|
||||||
|
SDAS_FAILED_TO_CHANGE_CWD
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Returned pointer must not be freed.
|
||||||
|
char *simple_archiver_error_to_string(enum SDArchiverStateReturns error);
|
||||||
|
|
||||||
|
SDArchiverState *simple_archiver_init_state(const SDArchiverParsed *parsed);
|
||||||
|
void simple_archiver_free_state(SDArchiverState **state);
|
||||||
|
|
||||||
|
/// Returns zero on success. Otherwise one value from SDArchiverStateReturns
|
||||||
|
/// enum.
|
||||||
|
int simple_archiver_write_all(FILE *out_f, SDArchiverState *state,
|
||||||
|
const SDArchiverLinkedList *filenames);
|
||||||
|
|
||||||
|
/// Returns zero on success.
|
||||||
|
int simple_archiver_parse_archive_info(FILE *in_f, int do_extract,
|
||||||
|
const SDArchiverState *state);
|
||||||
|
|
||||||
|
/// Returns zero on success.
|
||||||
|
int simple_archiver_de_compress(int pipe_fd_in[2], int pipe_fd_out[2],
|
||||||
|
const char *cmd, void *pid_out);
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,20 +1,20 @@
|
||||||
/*
|
// ISC License
|
||||||
* Copyright 2024 Stephen Seo
|
//
|
||||||
*
|
// Copyright (c) 2024 Stephen Seo
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
//
|
||||||
* you may not use this file except in compliance with the License.
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* You may obtain a copy of the License at
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
*
|
// copyright notice and this permission notice appear in all copies.
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
*
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
* See the License for the specific language governing permissions and
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
* limitations under the License.
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
*
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
* `hash_map.c` is the source for a hash map implementation.
|
//
|
||||||
*/
|
// `hash_map.c` is the source for a hash map implementation.
|
||||||
|
|
||||||
#include "hash_map.h"
|
#include "hash_map.h"
|
||||||
|
|
||||||
|
@ -26,16 +26,22 @@
|
||||||
typedef struct SDArchiverHashMapData {
|
typedef struct SDArchiverHashMapData {
|
||||||
void *value;
|
void *value;
|
||||||
void *key;
|
void *key;
|
||||||
unsigned int key_size;
|
size_t key_size;
|
||||||
void (*value_cleanup_fn)(void *);
|
void (*value_cleanup_fn)(void *);
|
||||||
void (*key_cleanup_fn)(void *);
|
void (*key_cleanup_fn)(void *);
|
||||||
} SDArchiverHashMapData;
|
} SDArchiverHashMapData;
|
||||||
|
|
||||||
typedef struct SDArchiverHashMapKeyData {
|
typedef struct SDArchiverHashMapKeyData {
|
||||||
void *key;
|
void *key;
|
||||||
unsigned int key_size;
|
size_t key_size;
|
||||||
} SDArchiverHashMapKeyData;
|
} SDArchiverHashMapKeyData;
|
||||||
|
|
||||||
|
typedef struct SDArchiverInternalIterContext {
|
||||||
|
int (*iter_check_fn)(const void *, size_t, const void *, void *);
|
||||||
|
int ret;
|
||||||
|
void *user_data;
|
||||||
|
} SDArchiverInternalIterContext;
|
||||||
|
|
||||||
void simple_archiver_hash_map_internal_cleanup_data(void *data) {
|
void simple_archiver_hash_map_internal_cleanup_data(void *data) {
|
||||||
SDArchiverHashMapData *hash_map_data = data;
|
SDArchiverHashMapData *hash_map_data = data;
|
||||||
if (hash_map_data->value) {
|
if (hash_map_data->value) {
|
||||||
|
@ -69,11 +75,11 @@ int simple_archiver_hash_map_internal_pick_in_list(void *data, void *ud) {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long long simple_archiver_hash_map_internal_key_to_hash(
|
unsigned long long simple_archiver_hash_map_internal_key_to_hash(
|
||||||
void *key, unsigned int key_size) {
|
const void *key, size_t key_size) {
|
||||||
unsigned long long seed = 0;
|
unsigned long long seed = 0;
|
||||||
unsigned long long temp = 0;
|
unsigned long long temp = 0;
|
||||||
unsigned int count = 0;
|
size_t count = 0;
|
||||||
for (unsigned int idx = 0; idx < key_size; ++idx) {
|
for (size_t idx = 0; idx < key_size; ++idx) {
|
||||||
temp |= ((unsigned long long)*((unsigned char *)key + idx)) << (8 * count);
|
temp |= ((unsigned long long)*((unsigned char *)key + idx)) << (8 * count);
|
||||||
++count;
|
++count;
|
||||||
if (count >= 8) {
|
if (count >= 8) {
|
||||||
|
@ -95,28 +101,27 @@ void simple_archiver_hash_map_internal_no_free_fn(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns 0 on success.
|
/// Returns 0 on success.
|
||||||
int simple_archiver_hash_map_internal_rehash(SDArchiverHashMap **hash_map) {
|
int simple_archiver_hash_map_internal_rehash(SDArchiverHashMap *hash_map) {
|
||||||
if (!hash_map || !*hash_map) {
|
if (!hash_map) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
SDArchiverHashMap *new_hash_map = malloc(sizeof(SDArchiverHashMap));
|
SDArchiverHashMap new_hash_map;
|
||||||
new_hash_map->buckets_size = (*hash_map)->buckets_size * 2;
|
new_hash_map.buckets_size = hash_map->buckets_size * 2;
|
||||||
// Pointers have the same size (at least on the same machine), so
|
// Pointers have the same size (at least on the same machine), so
|
||||||
// sizeof(void*) should be ok.
|
// sizeof(void*) should be ok.
|
||||||
new_hash_map->buckets = malloc(sizeof(void *) * new_hash_map->buckets_size);
|
new_hash_map.buckets = malloc(sizeof(void *) * new_hash_map.buckets_size);
|
||||||
for (unsigned int idx = 0; idx < new_hash_map->buckets_size; ++idx) {
|
for (size_t idx = 0; idx < new_hash_map.buckets_size; ++idx) {
|
||||||
new_hash_map->buckets[idx] = simple_archiver_list_init();
|
new_hash_map.buckets[idx] = simple_archiver_list_init();
|
||||||
}
|
}
|
||||||
new_hash_map->count = 0;
|
new_hash_map.count = 0;
|
||||||
|
|
||||||
// Iterate through the old hash map to populate the new hash map.
|
// Iterate through the old hash map to populate the new hash map.
|
||||||
for (unsigned int bucket_idx = 0; bucket_idx < (*hash_map)->buckets_size;
|
for (size_t bucket_idx = 0; bucket_idx < hash_map->buckets_size;
|
||||||
++bucket_idx) {
|
++bucket_idx) {
|
||||||
SDArchiverLLNode *node = (*hash_map)->buckets[bucket_idx]->head;
|
SDArchiverLLNode *node = hash_map->buckets[bucket_idx]->head;
|
||||||
while (node) {
|
while (node) {
|
||||||
node = node->next;
|
node = node->next;
|
||||||
if (node && node != (*hash_map)->buckets[bucket_idx]->tail &&
|
if (node && node != hash_map->buckets[bucket_idx]->tail && node->data) {
|
||||||
node->data) {
|
|
||||||
SDArchiverHashMapData *data = node->data;
|
SDArchiverHashMapData *data = node->data;
|
||||||
simple_archiver_hash_map_insert(&new_hash_map, data->value, data->key,
|
simple_archiver_hash_map_insert(&new_hash_map, data->value, data->key,
|
||||||
data->key_size, data->value_cleanup_fn,
|
data->key_size, data->value_cleanup_fn,
|
||||||
|
@ -127,7 +132,14 @@ int simple_archiver_hash_map_internal_rehash(SDArchiverHashMap **hash_map) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
simple_archiver_hash_map_free(hash_map);
|
// Free the buckets in the old hash_map.
|
||||||
|
for (size_t idx = 0; idx < hash_map->buckets_size; ++idx) {
|
||||||
|
SDArchiverLinkedList **linked_list = hash_map->buckets + idx;
|
||||||
|
simple_archiver_list_free(linked_list);
|
||||||
|
}
|
||||||
|
free(hash_map->buckets);
|
||||||
|
|
||||||
|
// Move the new buckets and related data into the old hash_map.
|
||||||
*hash_map = new_hash_map;
|
*hash_map = new_hash_map;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -139,7 +151,7 @@ SDArchiverHashMap *simple_archiver_hash_map_init(void) {
|
||||||
// Pointers have the same size (at least on the same machine), so
|
// Pointers have the same size (at least on the same machine), so
|
||||||
// sizeof(void*) should be ok.
|
// sizeof(void*) should be ok.
|
||||||
hash_map->buckets = malloc(sizeof(void *) * hash_map->buckets_size);
|
hash_map->buckets = malloc(sizeof(void *) * hash_map->buckets_size);
|
||||||
for (unsigned int idx = 0; idx < hash_map->buckets_size; ++idx) {
|
for (size_t idx = 0; idx < hash_map->buckets_size; ++idx) {
|
||||||
hash_map->buckets[idx] = simple_archiver_list_init();
|
hash_map->buckets[idx] = simple_archiver_list_init();
|
||||||
}
|
}
|
||||||
hash_map->count = 0;
|
hash_map->count = 0;
|
||||||
|
@ -149,7 +161,7 @@ SDArchiverHashMap *simple_archiver_hash_map_init(void) {
|
||||||
|
|
||||||
void simple_archiver_hash_map_free(SDArchiverHashMap **hash_map) {
|
void simple_archiver_hash_map_free(SDArchiverHashMap **hash_map) {
|
||||||
if (hash_map && *hash_map) {
|
if (hash_map && *hash_map) {
|
||||||
for (unsigned int idx = 0; idx < (*hash_map)->buckets_size; ++idx) {
|
for (size_t idx = 0; idx < (*hash_map)->buckets_size; ++idx) {
|
||||||
SDArchiverLinkedList **linked_list = (*hash_map)->buckets + idx;
|
SDArchiverLinkedList **linked_list = (*hash_map)->buckets + idx;
|
||||||
simple_archiver_list_free(linked_list);
|
simple_archiver_list_free(linked_list);
|
||||||
}
|
}
|
||||||
|
@ -161,11 +173,11 @@ void simple_archiver_hash_map_free(SDArchiverHashMap **hash_map) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int simple_archiver_hash_map_insert(SDArchiverHashMap **hash_map, void *value,
|
int simple_archiver_hash_map_insert(SDArchiverHashMap *hash_map, void *value,
|
||||||
void *key, unsigned int key_size,
|
void *key, size_t key_size,
|
||||||
void (*value_cleanup_fn)(void *),
|
void (*value_cleanup_fn)(void *),
|
||||||
void (*key_cleanup_fn)(void *)) {
|
void (*key_cleanup_fn)(void *)) {
|
||||||
if ((*hash_map)->buckets_size <= (*hash_map)->count) {
|
if (hash_map->buckets_size <= hash_map->count) {
|
||||||
simple_archiver_hash_map_internal_rehash(hash_map);
|
simple_archiver_hash_map_internal_rehash(hash_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,13 +190,13 @@ int simple_archiver_hash_map_insert(SDArchiverHashMap **hash_map, void *value,
|
||||||
|
|
||||||
unsigned long long hash =
|
unsigned long long hash =
|
||||||
simple_archiver_hash_map_internal_key_to_hash(key, key_size) %
|
simple_archiver_hash_map_internal_key_to_hash(key, key_size) %
|
||||||
(*hash_map)->buckets_size;
|
hash_map->buckets_size;
|
||||||
int result = simple_archiver_list_add_front(
|
int result = simple_archiver_list_add_front(
|
||||||
(*hash_map)->buckets[hash], data,
|
hash_map->buckets[hash], data,
|
||||||
simple_archiver_hash_map_internal_cleanup_data);
|
simple_archiver_hash_map_internal_cleanup_data);
|
||||||
|
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
++(*hash_map)->count;
|
++hash_map->count;
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
if (value) {
|
if (value) {
|
||||||
|
@ -207,8 +219,8 @@ int simple_archiver_hash_map_insert(SDArchiverHashMap **hash_map, void *value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void *simple_archiver_hash_map_get(SDArchiverHashMap *hash_map, void *key,
|
void *simple_archiver_hash_map_get(const SDArchiverHashMap *hash_map,
|
||||||
unsigned int key_size) {
|
const void *key, size_t key_size) {
|
||||||
unsigned long long hash =
|
unsigned long long hash =
|
||||||
simple_archiver_hash_map_internal_key_to_hash(key, key_size) %
|
simple_archiver_hash_map_internal_key_to_hash(key, key_size) %
|
||||||
hash_map->buckets_size;
|
hash_map->buckets_size;
|
||||||
|
@ -228,7 +240,7 @@ void *simple_archiver_hash_map_get(SDArchiverHashMap *hash_map, void *key,
|
||||||
}
|
}
|
||||||
|
|
||||||
int simple_archiver_hash_map_remove(SDArchiverHashMap *hash_map, void *key,
|
int simple_archiver_hash_map_remove(SDArchiverHashMap *hash_map, void *key,
|
||||||
unsigned int key_size) {
|
size_t key_size) {
|
||||||
unsigned long long hash =
|
unsigned long long hash =
|
||||||
simple_archiver_hash_map_internal_key_to_hash(key, key_size) %
|
simple_archiver_hash_map_internal_key_to_hash(key, key_size) %
|
||||||
hash_map->buckets_size;
|
hash_map->buckets_size;
|
||||||
|
@ -248,3 +260,34 @@ int simple_archiver_hash_map_remove(SDArchiverHashMap *hash_map, void *key,
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int simple_archiver_internal_hash_map_bucket_iter_fn(void *data, void *ud) {
|
||||||
|
SDArchiverHashMapData *hash_map_data = data;
|
||||||
|
SDArchiverInternalIterContext *ctx = ud;
|
||||||
|
|
||||||
|
ctx->ret = ctx->iter_check_fn(hash_map_data->key, hash_map_data->key_size,
|
||||||
|
hash_map_data->value, ctx->user_data);
|
||||||
|
if (ctx->ret != 0) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int simple_archiver_hash_map_iter(const SDArchiverHashMap *hash_map,
|
||||||
|
int (*iter_check_fn)(const void *, size_t,
|
||||||
|
const void *, void *),
|
||||||
|
void *user_data) {
|
||||||
|
SDArchiverInternalIterContext ctx;
|
||||||
|
ctx.iter_check_fn = iter_check_fn;
|
||||||
|
ctx.ret = 0;
|
||||||
|
ctx.user_data = user_data;
|
||||||
|
for (size_t idx = 0; idx < hash_map->buckets_size; ++idx) {
|
||||||
|
if (simple_archiver_list_get(
|
||||||
|
hash_map->buckets[idx],
|
||||||
|
simple_archiver_internal_hash_map_bucket_iter_fn, &ctx) != 0) {
|
||||||
|
return ctx.ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ctx.ret;
|
||||||
|
}
|
||||||
|
|
|
@ -1,32 +1,34 @@
|
||||||
/*
|
// ISC License
|
||||||
* Copyright 2024 Stephen Seo
|
//
|
||||||
*
|
// Copyright (c) 2024 Stephen Seo
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
//
|
||||||
* you may not use this file except in compliance with the License.
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* You may obtain a copy of the License at
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
*
|
// copyright notice and this permission notice appear in all copies.
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
*
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
* See the License for the specific language governing permissions and
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
* limitations under the License.
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
*
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
* `hash_map.h` is the header for a hash map implementation.
|
//
|
||||||
*/
|
// `hash_map.h` is the header for a hash map implementation.
|
||||||
|
|
||||||
#ifndef SEODISPARATE_COM_SIMPLE_ARCHIVER_DATA_STRUCTURE_HASH_MAP_H_
|
#ifndef SEODISPARATE_COM_SIMPLE_ARCHIVER_DATA_STRUCTURE_HASH_MAP_H_
|
||||||
#define SEODISPARATE_COM_SIMPLE_ARCHIVER_DATA_STRUCTURE_HASH_MAP_H_
|
#define SEODISPARATE_COM_SIMPLE_ARCHIVER_DATA_STRUCTURE_HASH_MAP_H_
|
||||||
|
|
||||||
#define SC_SA_DS_HASH_MAP_START_BUCKET_SIZE 32
|
#define SC_SA_DS_HASH_MAP_START_BUCKET_SIZE 32
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "linked_list.h"
|
#include "linked_list.h"
|
||||||
|
|
||||||
typedef struct SDArchiverHashMap {
|
typedef struct SDArchiverHashMap {
|
||||||
SDArchiverLinkedList **buckets;
|
SDArchiverLinkedList **buckets;
|
||||||
unsigned int buckets_size;
|
size_t buckets_size;
|
||||||
unsigned int count;
|
size_t count;
|
||||||
} SDArchiverHashMap;
|
} SDArchiverHashMap;
|
||||||
|
|
||||||
SDArchiverHashMap *simple_archiver_hash_map_init(void);
|
SDArchiverHashMap *simple_archiver_hash_map_init(void);
|
||||||
|
@ -37,18 +39,31 @@ void simple_archiver_hash_map_free(SDArchiverHashMap **hash_map);
|
||||||
/// key must remain valid for the lifetime of its entry in the hash map.
|
/// key must remain valid for the lifetime of its entry in the hash map.
|
||||||
/// If value_cleanup_fn is NULL, then "free" is used instead.
|
/// If value_cleanup_fn is NULL, then "free" is used instead.
|
||||||
/// If key_cleanup_fn is NULL, then "free" is used instead.
|
/// If key_cleanup_fn is NULL, then "free" is used instead.
|
||||||
int simple_archiver_hash_map_insert(SDArchiverHashMap **hash_map, void *value,
|
/// NOTICE: You must not pass NULL to value, otherwise all "get" checks will
|
||||||
void *key, unsigned int key_size,
|
/// fail for the inserted key.
|
||||||
|
int simple_archiver_hash_map_insert(SDArchiverHashMap *hash_map, void *value,
|
||||||
|
void *key, size_t key_size,
|
||||||
void (*value_cleanup_fn)(void *),
|
void (*value_cleanup_fn)(void *),
|
||||||
void (*key_cleanup_fn)(void *));
|
void (*key_cleanup_fn)(void *));
|
||||||
|
|
||||||
/// Returns NULL if not found.
|
/// Returns NULL if not found.
|
||||||
void *simple_archiver_hash_map_get(SDArchiverHashMap *hash_map, void *key,
|
void *simple_archiver_hash_map_get(const SDArchiverHashMap *hash_map,
|
||||||
unsigned int key_size);
|
const void *key, size_t key_size);
|
||||||
|
|
||||||
/// Returns zero on success. Returns one if more than one entry was removed.
|
/// Returns zero on success. Returns one if more than one entry was removed.
|
||||||
/// Otherwise returns non-zero and non-one value on error.
|
/// Otherwise returns non-zero and non-one value on error.
|
||||||
int simple_archiver_hash_map_remove(SDArchiverHashMap *hash_map, void *key,
|
int simple_archiver_hash_map_remove(SDArchiverHashMap *hash_map, void *key,
|
||||||
unsigned int key_size);
|
size_t key_size);
|
||||||
|
|
||||||
|
/// Iterates through the hash map with the "iter_check_fn", which is passed the
|
||||||
|
/// key, key-size, value, and user_data. This function will call "iter_check_fn"
|
||||||
|
/// on every entry in the given hash_map. If "iter_check_fn" returns non-zero,
|
||||||
|
/// iteration will halt and this function will return the same value. If
|
||||||
|
/// "iter_check_fn" returns zero for every call, then this function will return
|
||||||
|
/// zero after having iterated through every key-value pair.
|
||||||
|
int simple_archiver_hash_map_iter(const SDArchiverHashMap *hash_map,
|
||||||
|
int (*iter_check_fn)(const void *, size_t,
|
||||||
|
const void *, void *),
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
/*
|
// ISC License
|
||||||
* Copyright 2024 Stephen Seo
|
//
|
||||||
*
|
// Copyright (c) 2024 Stephen Seo
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
//
|
||||||
* you may not use this file except in compliance with the License.
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* You may obtain a copy of the License at
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
*
|
// copyright notice and this permission notice appear in all copies.
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
*
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
* See the License for the specific language governing permissions and
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
* limitations under the License.
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
*
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
* `linked_list.c` is the source for a linked list data structure.
|
//
|
||||||
*/
|
// `linked_list.c` is the source for a linked list data structure.
|
||||||
|
|
||||||
#include "linked_list.h"
|
#include "linked_list.h"
|
||||||
|
|
||||||
|
@ -178,7 +178,7 @@ int simple_archiver_list_remove_once(SDArchiverLinkedList *list,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *simple_archiver_list_get(SDArchiverLinkedList *list,
|
void *simple_archiver_list_get(const SDArchiverLinkedList *list,
|
||||||
int (*data_check_fn)(void *, void *),
|
int (*data_check_fn)(void *, void *),
|
||||||
void *user_data) {
|
void *user_data) {
|
||||||
if (!list) {
|
if (!list) {
|
||||||
|
|
|
@ -1,24 +1,26 @@
|
||||||
/*
|
// ISC License
|
||||||
* Copyright 2024 Stephen Seo
|
//
|
||||||
*
|
// Copyright (c) 2024 Stephen Seo
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
//
|
||||||
* you may not use this file except in compliance with the License.
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* You may obtain a copy of the License at
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
*
|
// copyright notice and this permission notice appear in all copies.
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
*
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
* See the License for the specific language governing permissions and
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
* limitations under the License.
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
*
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
* `linked_list.h` is the header for a linked list data structure.
|
//
|
||||||
*/
|
// `linked_list.h` is the header for a linked list data structure.
|
||||||
|
|
||||||
#ifndef SEODISPARATE_COM_SIMPLE_ARCHIVER_DATA_STRUCTURE_LINKED_LIST_H_
|
#ifndef SEODISPARATE_COM_SIMPLE_ARCHIVER_DATA_STRUCTURE_LINKED_LIST_H_
|
||||||
#define SEODISPARATE_COM_SIMPLE_ARCHIVER_DATA_STRUCTURE_LINKED_LIST_H_
|
#define SEODISPARATE_COM_SIMPLE_ARCHIVER_DATA_STRUCTURE_LINKED_LIST_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
typedef struct SDArchiverLLNode {
|
typedef struct SDArchiverLLNode {
|
||||||
struct SDArchiverLLNode *next;
|
struct SDArchiverLLNode *next;
|
||||||
struct SDArchiverLLNode *prev;
|
struct SDArchiverLLNode *prev;
|
||||||
|
@ -29,7 +31,7 @@ typedef struct SDArchiverLLNode {
|
||||||
typedef struct SDArchiverLinkedList {
|
typedef struct SDArchiverLinkedList {
|
||||||
SDArchiverLLNode *head;
|
SDArchiverLLNode *head;
|
||||||
SDArchiverLLNode *tail;
|
SDArchiverLLNode *tail;
|
||||||
unsigned int count;
|
size_t count;
|
||||||
} SDArchiverLinkedList;
|
} SDArchiverLinkedList;
|
||||||
|
|
||||||
SDArchiverLinkedList *simple_archiver_list_init(void);
|
SDArchiverLinkedList *simple_archiver_list_init(void);
|
||||||
|
@ -62,7 +64,7 @@ int simple_archiver_list_remove_once(SDArchiverLinkedList *list,
|
||||||
/// Returns non-null on success.
|
/// Returns non-null on success.
|
||||||
/// data_check_fn must return non-zero if the data passed to it is to be
|
/// data_check_fn must return non-zero if the data passed to it is to be
|
||||||
/// returned.
|
/// returned.
|
||||||
void *simple_archiver_list_get(SDArchiverLinkedList *list,
|
void *simple_archiver_list_get(const SDArchiverLinkedList *list,
|
||||||
int (*data_check_fn)(void *, void *),
|
int (*data_check_fn)(void *, void *),
|
||||||
void *user_data);
|
void *user_data);
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
/*
|
// ISC License
|
||||||
* Copyright 2024 Stephen Seo
|
//
|
||||||
*
|
// Copyright (c) 2024 Stephen Seo
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
//
|
||||||
* you may not use this file except in compliance with the License.
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* You may obtain a copy of the License at
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
*
|
// copyright notice and this permission notice appear in all copies.
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
*
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
* See the License for the specific language governing permissions and
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
* limitations under the License.
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
*
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
* `priority_heap.c` is the source for a priority heap implementation.
|
//
|
||||||
*/
|
// `priority_heap.c` is the source for a priority heap implementation.
|
||||||
|
|
||||||
#include "priority_heap.h"
|
#include "priority_heap.h"
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ void simple_archiver_priority_heap_internal_realloc(
|
||||||
new_priority_heap->nodes =
|
new_priority_heap->nodes =
|
||||||
calloc(new_priority_heap->capacity, sizeof(SDArchiverPHNode));
|
calloc(new_priority_heap->capacity, sizeof(SDArchiverPHNode));
|
||||||
|
|
||||||
for (unsigned int idx = 1; idx < (*priority_heap)->size + 1; ++idx) {
|
for (size_t idx = 1; idx < (*priority_heap)->size + 1; ++idx) {
|
||||||
if ((*priority_heap)->nodes[idx].is_valid != 0) {
|
if ((*priority_heap)->nodes[idx].is_valid != 0) {
|
||||||
simple_archiver_priority_heap_insert(
|
simple_archiver_priority_heap_insert(
|
||||||
&new_priority_heap, (*priority_heap)->nodes[idx].priority,
|
&new_priority_heap, (*priority_heap)->nodes[idx].priority,
|
||||||
|
@ -79,7 +79,7 @@ SDArchiverPHeap *simple_archiver_priority_heap_init_less_fn(
|
||||||
|
|
||||||
void simple_archiver_priority_heap_free(SDArchiverPHeap **priority_heap) {
|
void simple_archiver_priority_heap_free(SDArchiverPHeap **priority_heap) {
|
||||||
if (priority_heap && *priority_heap) {
|
if (priority_heap && *priority_heap) {
|
||||||
for (unsigned int idx = 1; idx < (*priority_heap)->size + 1; ++idx) {
|
for (size_t idx = 1; idx < (*priority_heap)->size + 1; ++idx) {
|
||||||
if ((*priority_heap)->nodes[idx].is_valid != 0) {
|
if ((*priority_heap)->nodes[idx].is_valid != 0) {
|
||||||
if ((*priority_heap)->nodes[idx].data_cleanup_fn) {
|
if ((*priority_heap)->nodes[idx].data_cleanup_fn) {
|
||||||
(*priority_heap)
|
(*priority_heap)
|
||||||
|
@ -109,7 +109,7 @@ void simple_archiver_priority_heap_insert(SDArchiverPHeap **priority_heap,
|
||||||
simple_archiver_priority_heap_internal_realloc(priority_heap);
|
simple_archiver_priority_heap_internal_realloc(priority_heap);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int hole = (*priority_heap)->size + 1;
|
size_t hole = (*priority_heap)->size + 1;
|
||||||
|
|
||||||
while (hole > 1 &&
|
while (hole > 1 &&
|
||||||
(*priority_heap)
|
(*priority_heap)
|
||||||
|
@ -146,7 +146,7 @@ void *simple_archiver_priority_heap_pop(SDArchiverPHeap *priority_heap) {
|
||||||
SDArchiverPHNode end = priority_heap->nodes[priority_heap->size];
|
SDArchiverPHNode end = priority_heap->nodes[priority_heap->size];
|
||||||
priority_heap->nodes[priority_heap->size].is_valid = 0;
|
priority_heap->nodes[priority_heap->size].is_valid = 0;
|
||||||
|
|
||||||
unsigned int hole = 1;
|
size_t hole = 1;
|
||||||
while (hole * 2 + 1 <= priority_heap->size) {
|
while (hole * 2 + 1 <= priority_heap->size) {
|
||||||
if (priority_heap->nodes[hole * 2].is_valid != 0 &&
|
if (priority_heap->nodes[hole * 2].is_valid != 0 &&
|
||||||
priority_heap->nodes[hole * 2 + 1].is_valid != 0) {
|
priority_heap->nodes[hole * 2 + 1].is_valid != 0) {
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
/*
|
// ISC License
|
||||||
* Copyright 2024 Stephen Seo
|
//
|
||||||
*
|
// Copyright (c) 2024 Stephen Seo
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
//
|
||||||
* you may not use this file except in compliance with the License.
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* You may obtain a copy of the License at
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
*
|
// copyright notice and this permission notice appear in all copies.
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
*
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
* See the License for the specific language governing permissions and
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
* limitations under the License.
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
*
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
* `priority_heap.h` is the header for a priority heap implementation.
|
//
|
||||||
*/
|
// `priority_heap.h` is the header for a priority heap implementation.
|
||||||
|
|
||||||
#ifndef SEODISPARATE_COM_SIMPLE_ARCHIVER_DATA_STRUCTURE_PRIORITY_HEAP_H_
|
#ifndef SEODISPARATE_COM_SIMPLE_ARCHIVER_DATA_STRUCTURE_PRIORITY_HEAP_H_
|
||||||
#define SEODISPARATE_COM_SIMPLE_ARCHIVER_DATA_STRUCTURE_PRIORITY_HEAP_H_
|
#define SEODISPARATE_COM_SIMPLE_ARCHIVER_DATA_STRUCTURE_PRIORITY_HEAP_H_
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
/*
|
// ISC License
|
||||||
* Copyright 2024 Stephen Seo
|
//
|
||||||
*
|
// Copyright (c) 2024 Stephen Seo
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
//
|
||||||
* you may not use this file except in compliance with the License.
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* You may obtain a copy of the License at
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
*
|
// copyright notice and this permission notice appear in all copies.
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
*
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
* See the License for the specific language governing permissions and
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
* limitations under the License.
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
*
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
* `data_structures/test.c` is the source for testing data structure code.
|
//
|
||||||
*/
|
// `data_structures/test.c` is the source for testing data structure code.
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -25,6 +25,8 @@
|
||||||
#include "linked_list.h"
|
#include "linked_list.h"
|
||||||
#include "priority_heap.h"
|
#include "priority_heap.h"
|
||||||
|
|
||||||
|
#define SDARCHIVER_DS_TEST_HASH_MAP_ITER_SIZE 100
|
||||||
|
|
||||||
static int checks_checked = 0;
|
static int checks_checked = 0;
|
||||||
static int checks_passed = 0;
|
static int checks_passed = 0;
|
||||||
|
|
||||||
|
@ -63,6 +65,26 @@ int get_three_fn(void *data, __attribute__((unused)) void *ud) {
|
||||||
|
|
||||||
int more_fn(long long a, long long b) { return a > b ? 1 : 0; }
|
int more_fn(long long a, long long b) { return a > b ? 1 : 0; }
|
||||||
|
|
||||||
|
int hash_map_iter_check_fn(__attribute__((unused)) const void *key,
|
||||||
|
__attribute__((unused)) size_t key_size,
|
||||||
|
const void *value, void *ud) {
|
||||||
|
char *found_buf = ud;
|
||||||
|
const size_t real_value = (const size_t)value;
|
||||||
|
if (real_value < SDARCHIVER_DS_TEST_HASH_MAP_ITER_SIZE) {
|
||||||
|
found_buf[real_value] += 1;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int hash_map_iter_check_fn2(__attribute__((unused)) const void *key,
|
||||||
|
__attribute__((unused)) size_t key_size,
|
||||||
|
__attribute__((unused)) const void *value,
|
||||||
|
__attribute__((unused)) void *ud) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
// Test LinkedList.
|
// Test LinkedList.
|
||||||
{
|
{
|
||||||
|
@ -123,8 +145,8 @@ int main(void) {
|
||||||
key = malloc(sizeof(int));
|
key = malloc(sizeof(int));
|
||||||
*value = idx;
|
*value = idx;
|
||||||
*key = idx;
|
*key = idx;
|
||||||
simple_archiver_hash_map_insert(&hash_map, value, key, sizeof(int),
|
simple_archiver_hash_map_insert(hash_map, value, key, sizeof(int), NULL,
|
||||||
NULL, NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,10 +184,38 @@ int main(void) {
|
||||||
*copy_value = idx;
|
*copy_value = idx;
|
||||||
unsigned int *copy_key = malloc(sizeof(unsigned int));
|
unsigned int *copy_key = malloc(sizeof(unsigned int));
|
||||||
*copy_key = idx;
|
*copy_key = idx;
|
||||||
simple_archiver_hash_map_insert(&hash_map, copy_value, copy_key,
|
simple_archiver_hash_map_insert(hash_map, copy_value, copy_key,
|
||||||
sizeof(unsigned int), NULL, NULL);
|
sizeof(unsigned int), NULL, NULL);
|
||||||
}
|
}
|
||||||
simple_archiver_hash_map_free(&hash_map);
|
simple_archiver_hash_map_free(&hash_map);
|
||||||
|
|
||||||
|
// Hash map iter test.
|
||||||
|
hash_map = simple_archiver_hash_map_init();
|
||||||
|
|
||||||
|
for (size_t idx = 0; idx < SDARCHIVER_DS_TEST_HASH_MAP_ITER_SIZE; ++idx) {
|
||||||
|
simple_archiver_hash_map_insert(hash_map, (void *)idx, &idx,
|
||||||
|
sizeof(size_t), no_free_fn, no_free_fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
char found[SDARCHIVER_DS_TEST_HASH_MAP_ITER_SIZE] = {0};
|
||||||
|
|
||||||
|
CHECK_TRUE(simple_archiver_hash_map_iter(hash_map, hash_map_iter_check_fn,
|
||||||
|
found) == 0);
|
||||||
|
|
||||||
|
for (unsigned int idx = 0; idx < SDARCHIVER_DS_TEST_HASH_MAP_ITER_SIZE;
|
||||||
|
++idx) {
|
||||||
|
CHECK_TRUE(found[idx] == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK_TRUE(simple_archiver_hash_map_iter(hash_map, hash_map_iter_check_fn2,
|
||||||
|
found) == 2);
|
||||||
|
|
||||||
|
for (unsigned int idx = 0; idx < SDARCHIVER_DS_TEST_HASH_MAP_ITER_SIZE;
|
||||||
|
++idx) {
|
||||||
|
CHECK_TRUE(found[idx] == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
simple_archiver_hash_map_free(&hash_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test PriorityHeap.
|
// Test PriorityHeap.
|
||||||
|
|
243
src/helpers.c
243
src/helpers.c
|
@ -1,33 +1,84 @@
|
||||||
/*
|
// ISC License
|
||||||
* Copyright 2024 Stephen Seo
|
//
|
||||||
*
|
// Copyright (c) 2024 Stephen Seo
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
//
|
||||||
* you may not use this file except in compliance with the License.
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* You may obtain a copy of the License at
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
*
|
// copyright notice and this permission notice appear in all copies.
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
*
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
* See the License for the specific language governing permissions and
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
* limitations under the License.
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
*
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
* `helpers.c` is the source for helpful/utility functions.
|
//
|
||||||
*/
|
// `helpers.c` is the source for helpful/utility functions.
|
||||||
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "platforms.h"
|
||||||
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
||||||
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
||||||
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void simple_archiver_helper_cleanup_FILE(FILE **fd) {
|
||||||
|
if (fd && *fd) {
|
||||||
|
fclose(*fd);
|
||||||
|
*fd = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void simple_archiver_helper_cleanup_malloced(void **data) {
|
||||||
|
if (data && *data) {
|
||||||
|
free(*data);
|
||||||
|
*data = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void simple_archiver_helper_cleanup_c_string(char **str) {
|
||||||
|
if (str && *str) {
|
||||||
|
free(*str);
|
||||||
|
*str = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void simple_archiver_helper_cleanup_chdir_back(char **original) {
|
||||||
|
if (original && *original) {
|
||||||
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX || \
|
||||||
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
||||||
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN
|
||||||
|
__attribute__((unused)) int unused_ret = chdir(*original);
|
||||||
|
#endif
|
||||||
|
free(*original);
|
||||||
|
*original = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void simple_archiver_helper_datastructure_cleanup_nop(
|
||||||
|
__attribute__((unused)) void *unused) {}
|
||||||
|
|
||||||
int simple_archiver_helper_is_big_endian(void) {
|
int simple_archiver_helper_is_big_endian(void) {
|
||||||
union {
|
union {
|
||||||
unsigned int i;
|
uint32_t i;
|
||||||
char c[4];
|
char c[4];
|
||||||
} bint = {0x01020304};
|
} bint = {0x01020304};
|
||||||
|
|
||||||
return bint.c[0] == 1 ? 1 : 0;
|
return bint.c[0] == 1 ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void simple_archiver_helper_16_bit_be(unsigned short *value) {
|
void simple_archiver_helper_16_bit_be(uint16_t *value) {
|
||||||
if (simple_archiver_helper_is_big_endian() == 0) {
|
if (simple_archiver_helper_is_big_endian() == 0) {
|
||||||
unsigned char c = ((unsigned char *)value)[0];
|
unsigned char c = ((unsigned char *)value)[0];
|
||||||
((unsigned char *)value)[0] = ((unsigned char *)value)[1];
|
((unsigned char *)value)[0] = ((unsigned char *)value)[1];
|
||||||
|
@ -35,7 +86,7 @@ void simple_archiver_helper_16_bit_be(unsigned short *value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void simple_archiver_helper_32_bit_be(unsigned int *value) {
|
void simple_archiver_helper_32_bit_be(uint32_t *value) {
|
||||||
if (simple_archiver_helper_is_big_endian() == 0) {
|
if (simple_archiver_helper_is_big_endian() == 0) {
|
||||||
for (unsigned int i = 0; i < 2; ++i) {
|
for (unsigned int i = 0; i < 2; ++i) {
|
||||||
unsigned char c = ((unsigned char *)value)[i];
|
unsigned char c = ((unsigned char *)value)[i];
|
||||||
|
@ -45,7 +96,7 @@ void simple_archiver_helper_32_bit_be(unsigned int *value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void simple_archiver_helper_64_bit_be(unsigned long long *value) {
|
void simple_archiver_helper_64_bit_be(uint64_t *value) {
|
||||||
if (simple_archiver_helper_is_big_endian() == 0) {
|
if (simple_archiver_helper_is_big_endian() == 0) {
|
||||||
for (unsigned int i = 0; i < 4; ++i) {
|
for (unsigned int i = 0; i < 4; ++i) {
|
||||||
unsigned char c = ((unsigned char *)value)[i];
|
unsigned char c = ((unsigned char *)value)[i];
|
||||||
|
@ -54,3 +105,153 @@ void simple_archiver_helper_64_bit_be(unsigned long long *value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char **simple_archiver_helper_cmd_string_to_argv(const char *cmd) {
|
||||||
|
unsigned int capacity = 16;
|
||||||
|
unsigned int idx = 0;
|
||||||
|
// Size of every pointer is the same, so using size of (void*) should be ok.
|
||||||
|
char **args = malloc(sizeof(void *) * capacity);
|
||||||
|
memset(args, 0, sizeof(void *) * capacity);
|
||||||
|
|
||||||
|
unsigned int word_capacity = 16;
|
||||||
|
unsigned int word_idx = 0;
|
||||||
|
char *word = malloc(word_capacity);
|
||||||
|
memset(word, 0, word_capacity);
|
||||||
|
for (const char *c = cmd; *c != 0; ++c) {
|
||||||
|
if (isspace(*c)) {
|
||||||
|
if (word_idx > 0) {
|
||||||
|
if (idx >= capacity) {
|
||||||
|
capacity *= 2;
|
||||||
|
args = realloc(args, sizeof(void *) * capacity);
|
||||||
|
}
|
||||||
|
args[idx] = malloc(word_idx + 1);
|
||||||
|
memcpy(args[idx], word, word_idx);
|
||||||
|
args[idx][word_idx] = 0;
|
||||||
|
++idx;
|
||||||
|
word_idx = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (word_idx >= word_capacity) {
|
||||||
|
word_capacity *= 2;
|
||||||
|
word = realloc(word, word_capacity);
|
||||||
|
}
|
||||||
|
word[word_idx++] = *c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (word_idx > 0) {
|
||||||
|
if (idx >= capacity) {
|
||||||
|
capacity *= 2;
|
||||||
|
args = realloc(args, sizeof(void *) * capacity);
|
||||||
|
}
|
||||||
|
args[idx] = malloc(word_idx + 1);
|
||||||
|
memcpy(args[idx], word, word_idx);
|
||||||
|
args[idx][word_idx] = 0;
|
||||||
|
++idx;
|
||||||
|
word_idx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(word);
|
||||||
|
|
||||||
|
if (idx >= capacity) {
|
||||||
|
args = realloc(args, sizeof(void *) * (capacity + 1));
|
||||||
|
args[capacity] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
void simple_archiver_helper_cmd_string_argv_free(char **argv_strs) {
|
||||||
|
if (argv_strs) {
|
||||||
|
for (char **iter = argv_strs; *iter != 0; ++iter) {
|
||||||
|
free(*iter);
|
||||||
|
}
|
||||||
|
free(argv_strs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void simple_archiver_helper_cmd_string_argv_free_ptr(char ***argv_strs) {
|
||||||
|
if (argv_strs) {
|
||||||
|
simple_archiver_helper_cmd_string_argv_free(*argv_strs);
|
||||||
|
*argv_strs = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int simple_archiver_helper_make_dirs(const char *file_path) {
|
||||||
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
||||||
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
||||||
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
||||||
|
__attribute__((
|
||||||
|
cleanup(simple_archiver_helper_cleanup_c_string))) char *path_dup =
|
||||||
|
strdup(file_path);
|
||||||
|
if (!path_dup) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
const char *dir = dirname(path_dup);
|
||||||
|
if (strcmp(dir, "/") == 0 || strcmp(dir, ".") == 0) {
|
||||||
|
// At root.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dir_fd = open(dir, O_RDONLY | O_DIRECTORY);
|
||||||
|
if (dir_fd == -1) {
|
||||||
|
if (errno == ENOTDIR) {
|
||||||
|
// Error, somehow got non-dir in path.
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
// Directory does not exist. Check parent dir first.
|
||||||
|
int ret = simple_archiver_helper_make_dirs(dir);
|
||||||
|
if (ret != 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
// Now make dir.
|
||||||
|
ret = mkdir(dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||||
|
if (ret != 0) {
|
||||||
|
// Error.
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Exists.
|
||||||
|
close(dir_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
char *simple_archiver_helper_cut_substr(const char *s, size_t start_idx,
|
||||||
|
size_t end_idx) {
|
||||||
|
size_t s_len = strlen(s);
|
||||||
|
if (start_idx > end_idx || start_idx >= s_len || end_idx > s_len) {
|
||||||
|
return NULL;
|
||||||
|
} else if (end_idx == s_len) {
|
||||||
|
if (start_idx == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
char *new_s = malloc(start_idx + 1);
|
||||||
|
strncpy(new_s, s, start_idx + 1);
|
||||||
|
new_s[start_idx] = 0;
|
||||||
|
return new_s;
|
||||||
|
} else if (start_idx == 0) {
|
||||||
|
char *new_s = malloc(s_len - end_idx + 1);
|
||||||
|
strncpy(new_s, s + end_idx, s_len - end_idx + 1);
|
||||||
|
return new_s;
|
||||||
|
} else {
|
||||||
|
char *new_s = malloc(start_idx + s_len - end_idx + 1);
|
||||||
|
strncpy(new_s, s, start_idx);
|
||||||
|
strncpy(new_s + start_idx, s + end_idx, s_len - end_idx + 1);
|
||||||
|
return new_s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t simple_archiver_helper_num_digits(size_t value) {
|
||||||
|
size_t digits = 0;
|
||||||
|
do {
|
||||||
|
++digits;
|
||||||
|
value /= 10;
|
||||||
|
} while (value != 0);
|
||||||
|
|
||||||
|
return digits;
|
||||||
|
}
|
||||||
|
|
|
@ -1,36 +1,65 @@
|
||||||
/*
|
// ISC License
|
||||||
* Copyright 2024 Stephen Seo
|
//
|
||||||
*
|
// Copyright (c) 2024 Stephen Seo
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
//
|
||||||
* you may not use this file except in compliance with the License.
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* You may obtain a copy of the License at
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
*
|
// copyright notice and this permission notice appear in all copies.
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
*
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
* See the License for the specific language governing permissions and
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
* limitations under the License.
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
*
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
* `helpers.h` is the header for helpful/utility functions.
|
//
|
||||||
*/
|
// `helpers.h` is the header for helpful/utility functions.
|
||||||
|
|
||||||
#ifndef SEODISPARATE_COM_SIMPLE_ARCHIVER_HELPERS_H_
|
#ifndef SEODISPARATE_COM_SIMPLE_ARCHIVER_HELPERS_H_
|
||||||
#define SEODISPARATE_COM_SIMPLE_ARCHIVER_HELPERS_H_
|
#define SEODISPARATE_COM_SIMPLE_ARCHIVER_HELPERS_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
static const unsigned int MAX_SYMBOLIC_LINK_SIZE = 512;
|
static const unsigned int MAX_SYMBOLIC_LINK_SIZE = 512;
|
||||||
|
|
||||||
/// Returns non-zero if this system is big-endian.
|
/// Returns non-zero if this system is big-endian.
|
||||||
int simple_archiver_helper_is_big_endian(void);
|
int simple_archiver_helper_is_big_endian(void);
|
||||||
|
|
||||||
/// Swaps value from/to big-endian. Nop on big-endian systems.
|
/// Swaps value from/to big-endian. Nop on big-endian systems.
|
||||||
void simple_archiver_helper_16_bit_be(unsigned short *value);
|
void simple_archiver_helper_16_bit_be(uint16_t *value);
|
||||||
|
|
||||||
/// Swaps value from/to big-endian. Nop on big-endian systems.
|
/// Swaps value from/to big-endian. Nop on big-endian systems.
|
||||||
void simple_archiver_helper_32_bit_be(unsigned int *value);
|
void simple_archiver_helper_32_bit_be(uint32_t *value);
|
||||||
|
|
||||||
/// Swaps value from/to big-endian. Nop on big-endian systems.
|
/// Swaps value from/to big-endian. Nop on big-endian systems.
|
||||||
void simple_archiver_helper_64_bit_be(unsigned long long *value);
|
void simple_archiver_helper_64_bit_be(uint64_t *value);
|
||||||
|
|
||||||
|
/// Returns a array of c-strings on success, NULL on error.
|
||||||
|
/// The returned array must be free'd with
|
||||||
|
/// simple_archiver_helper_cmd_string_argv_free(...).
|
||||||
|
char **simple_archiver_helper_cmd_string_to_argv(const char *cmd);
|
||||||
|
|
||||||
|
void simple_archiver_helper_cmd_string_argv_free(char **argv_strs);
|
||||||
|
void simple_archiver_helper_cmd_string_argv_free_ptr(char ***argv_strs);
|
||||||
|
|
||||||
|
/// Returns zero on success.
|
||||||
|
int simple_archiver_helper_make_dirs(const char *file_path);
|
||||||
|
|
||||||
|
/// Returns non-NULL on success.
|
||||||
|
/// Must be free'd with "free()" if non-NULL.
|
||||||
|
/// start_idx is inclusive and end_idx is exclusive.
|
||||||
|
char *simple_archiver_helper_cut_substr(const char *s, size_t start_idx,
|
||||||
|
size_t end_idx);
|
||||||
|
|
||||||
|
size_t simple_archiver_helper_num_digits(size_t value);
|
||||||
|
|
||||||
|
void simple_archiver_helper_cleanup_FILE(FILE **fd);
|
||||||
|
void simple_archiver_helper_cleanup_malloced(void **data);
|
||||||
|
void simple_archiver_helper_cleanup_c_string(char **str);
|
||||||
|
void simple_archiver_helper_cleanup_chdir_back(char **original);
|
||||||
|
|
||||||
|
void simple_archiver_helper_datastructure_cleanup_nop(void *unused);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
172
src/main.c
172
src/main.c
|
@ -1,50 +1,174 @@
|
||||||
/*
|
// ISC License
|
||||||
* Copyright 2024 Stephen Seo
|
//
|
||||||
*
|
// Copyright (c) 2024 Stephen Seo
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
//
|
||||||
* you may not use this file except in compliance with the License.
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* You may obtain a copy of the License at
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
*
|
// copyright notice and this permission notice appear in all copies.
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
*
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
* See the License for the specific language governing permissions and
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
* limitations under the License.
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
*
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
* `main.c` is the entry-point of this software/program.
|
//
|
||||||
*/
|
// `main.c` is the entry-point of this software/program.
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "platforms.h"
|
||||||
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
||||||
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
||||||
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "archiver.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
int print_list_fn(void *data, __attribute__((unused)) void *ud) {
|
int print_list_fn(void *data, __attribute__((unused)) void *ud) {
|
||||||
const SDArchiverFileInfo *file_info = data;
|
const SDArchiverFileInfo *file_info = data;
|
||||||
if (file_info->link_dest == NULL) {
|
if (file_info->link_dest == NULL) {
|
||||||
printf(" REGULAR FILE: %s\n", file_info->filename);
|
fprintf(stderr, " REGULAR FILE: %s\n", file_info->filename);
|
||||||
} else {
|
} else {
|
||||||
printf(" SYMBOLIC LINK: %s -> %s\n", file_info->filename,
|
fprintf(stderr, " SYMBOLIC LINK: %s -> %s\n", file_info->filename,
|
||||||
file_info->link_dest);
|
file_info->link_dest);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, const char **argv) {
|
int main(int argc, const char **argv) {
|
||||||
|
__attribute__((
|
||||||
|
cleanup(simple_archiver_free_parsed))) SDArchiverParsed parsed =
|
||||||
|
simple_archiver_create_parsed();
|
||||||
|
|
||||||
|
if (simple_archiver_parse_args(argc, argv, &parsed)) {
|
||||||
|
fprintf(stderr, "Failed to parse args.\n");
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parsed.filename && (parsed.flags & 0x10) == 0) {
|
||||||
|
fprintf(stderr, "ERROR: Filename not specified!\n");
|
||||||
simple_archiver_print_usage();
|
simple_archiver_print_usage();
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
|
||||||
__attribute__((cleanup(simple_archiver_free_parsed)))
|
if ((parsed.flags & 0x3) == 0 && (parsed.flags & 0x4) == 0) {
|
||||||
SDArchiverParsed parsed = simple_archiver_create_parsed();
|
FILE *file = fopen(parsed.filename, "r");
|
||||||
|
if (file != NULL) {
|
||||||
simple_archiver_parse_args(argc, argv, &parsed);
|
fclose(file);
|
||||||
|
fprintf(
|
||||||
|
stderr,
|
||||||
|
"ERROR: Archive file exists but --overwrite-create not specified!\n");
|
||||||
|
simple_archiver_print_usage();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
__attribute__((cleanup(simple_archiver_list_free)))
|
__attribute__((cleanup(simple_archiver_list_free)))
|
||||||
SDArchiverLinkedList *filenames =
|
SDArchiverLinkedList *filenames =
|
||||||
simple_archiver_parsed_to_filenames(&parsed);
|
simple_archiver_parsed_to_filenames(&parsed);
|
||||||
|
if (!filenames) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR: Failed to resolve filenames from positional arguments!\n");
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
puts("Filenames:");
|
if (filenames->count > 0) {
|
||||||
|
fprintf(stderr, "Filenames:\n");
|
||||||
simple_archiver_list_get(filenames, print_list_fn, NULL);
|
simple_archiver_list_get(filenames, print_list_fn, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((parsed.flags & 3) == 0) {
|
||||||
|
// Is creating archive.
|
||||||
|
__attribute__((cleanup(simple_archiver_free_state)))
|
||||||
|
SDArchiverState *state = simple_archiver_init_state(&parsed);
|
||||||
|
if ((parsed.flags & 0x10) == 0) {
|
||||||
|
FILE *file = fopen(parsed.filename, "wb");
|
||||||
|
if (!file) {
|
||||||
|
fprintf(stderr, "ERROR: Failed to open \"%s\" for writing!\n",
|
||||||
|
parsed.filename);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = simple_archiver_write_all(file, state, filenames);
|
||||||
|
if (ret != SDAS_SUCCESS) {
|
||||||
|
fprintf(stderr, "Error during writing.\n");
|
||||||
|
char *error_str = simple_archiver_error_to_string(ret);
|
||||||
|
fprintf(stderr, " %s\n", error_str);
|
||||||
|
}
|
||||||
|
fclose(file);
|
||||||
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
||||||
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
||||||
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
||||||
|
if (ret != SDAS_SUCCESS) {
|
||||||
|
unlink(parsed.filename);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
int ret = simple_archiver_write_all(stdout, state, filenames);
|
||||||
|
if (ret != SDAS_SUCCESS) {
|
||||||
|
fprintf(stderr, "Error during writing.\n");
|
||||||
|
char *error_str = simple_archiver_error_to_string(ret);
|
||||||
|
fprintf(stderr, " %s\n", error_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ((parsed.flags & 3) == 2) {
|
||||||
|
// Is checking archive.
|
||||||
|
if ((parsed.flags & 0x10) == 0) {
|
||||||
|
FILE *file = fopen(parsed.filename, "rb");
|
||||||
|
if (!file) {
|
||||||
|
fprintf(stderr, "ERROR: Failed to open \"%s\" for reading!\n",
|
||||||
|
parsed.filename);
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = simple_archiver_parse_archive_info(file, 0, NULL);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf(stderr, "Error during archive checking/examining.\n");
|
||||||
|
char *error_str = simple_archiver_error_to_string(ret);
|
||||||
|
fprintf(stderr, " %s\n", error_str);
|
||||||
|
}
|
||||||
|
fclose(file);
|
||||||
|
} else {
|
||||||
|
int ret = simple_archiver_parse_archive_info(stdin, 0, NULL);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf(stderr, "Error during archive checking/examining.\n");
|
||||||
|
char *error_str = simple_archiver_error_to_string(ret);
|
||||||
|
fprintf(stderr, " %s\n", error_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ((parsed.flags & 3) == 1) {
|
||||||
|
// Is extracting archive.
|
||||||
|
__attribute__((cleanup(simple_archiver_free_state)))
|
||||||
|
SDArchiverState *state = simple_archiver_init_state(&parsed);
|
||||||
|
if ((parsed.flags & 0x10) == 0) {
|
||||||
|
FILE *file = fopen(parsed.filename, "rb");
|
||||||
|
if (!file) {
|
||||||
|
fprintf(stderr, "ERROR: Failed to open \"%s\" for reading!\n",
|
||||||
|
parsed.filename);
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = simple_archiver_parse_archive_info(file, 1, state);
|
||||||
|
if (ret != SDAS_SUCCESS) {
|
||||||
|
fprintf(stderr, "Error during archive extracting.\n");
|
||||||
|
char *error_str = simple_archiver_error_to_string(ret);
|
||||||
|
fprintf(stderr, " %s\n", error_str);
|
||||||
|
}
|
||||||
|
fclose(file);
|
||||||
|
} else {
|
||||||
|
int ret = simple_archiver_parse_archive_info(stdin, 1, state);
|
||||||
|
if (ret != SDAS_SUCCESS) {
|
||||||
|
fprintf(stderr, "Error during archive extracting.\n");
|
||||||
|
char *error_str = simple_archiver_error_to_string(ret);
|
||||||
|
fprintf(stderr, " %s\n", error_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
418
src/parser.c
418
src/parser.c
|
@ -1,20 +1,20 @@
|
||||||
/*
|
// ISC License
|
||||||
* Copyright 2024 Stephen Seo
|
//
|
||||||
*
|
// Copyright (c) 2024 Stephen Seo
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
//
|
||||||
* you may not use this file except in compliance with the License.
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* You may obtain a copy of the License at
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
*
|
// copyright notice and this permission notice appear in all copies.
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
*
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
* See the License for the specific language governing permissions and
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
* limitations under the License.
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
*
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
* `parser.c` is the source file for parsing args.
|
//
|
||||||
*/
|
// `parser.c` is the source file for parsing args.
|
||||||
|
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
|
@ -31,12 +31,6 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#elif SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_WINDOWS
|
|
||||||
#include <fileapi.h>
|
|
||||||
#include <wchar.h>
|
|
||||||
#include <windows.h>
|
|
||||||
#include <winioctl.h>
|
|
||||||
#include <winnt.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "data_structures/hash_map.h"
|
#include "data_structures/hash_map.h"
|
||||||
|
@ -45,15 +39,15 @@
|
||||||
#include "parser_internal.h"
|
#include "parser_internal.h"
|
||||||
|
|
||||||
/// Gets the first non "./"-like character in the filename.
|
/// Gets the first non "./"-like character in the filename.
|
||||||
unsigned int simple_archiver_parser_internal_filename_idx(
|
size_t simple_archiver_parser_internal_get_first_non_current_idx(
|
||||||
const char *filename) {
|
const char *filename) {
|
||||||
unsigned int idx = 0;
|
size_t idx = 0;
|
||||||
unsigned int known_good_idx = 0;
|
size_t known_good_idx = 0;
|
||||||
const unsigned int length = strlen(filename);
|
const size_t length = strlen(filename);
|
||||||
|
|
||||||
// 0b0001 - checked that idx char is '.'
|
// 0b0001 - checked that idx char is '.'
|
||||||
// 0b0010 - checked that idx char is '/'
|
// 0b0010 - checked that idx char is '/'
|
||||||
unsigned int flags = 0;
|
size_t flags = 0;
|
||||||
|
|
||||||
for (; idx < length; ++idx) {
|
for (; idx < length; ++idx) {
|
||||||
if ((flags & 3) == 0) {
|
if ((flags & 3) == 0) {
|
||||||
|
@ -67,11 +61,7 @@ unsigned int simple_archiver_parser_internal_filename_idx(
|
||||||
} else if ((flags & 3) == 1) {
|
} else if ((flags & 3) == 1) {
|
||||||
if (filename[idx] == 0) {
|
if (filename[idx] == 0) {
|
||||||
return known_good_idx;
|
return known_good_idx;
|
||||||
#if SIMPLE_ARCHIVER_PLATFORM != SIMPLE_ARCHIVER_PLATFORM_WINDOWS
|
|
||||||
} else if (filename[idx] == '/') {
|
} else if (filename[idx] == '/') {
|
||||||
#else
|
|
||||||
} else if (filename[idx] == '\\') {
|
|
||||||
#endif
|
|
||||||
flags |= 2;
|
flags |= 2;
|
||||||
} else {
|
} else {
|
||||||
return idx - 1;
|
return idx - 1;
|
||||||
|
@ -79,11 +69,7 @@ unsigned int simple_archiver_parser_internal_filename_idx(
|
||||||
} else if ((flags & 3) == 3) {
|
} else if ((flags & 3) == 3) {
|
||||||
if (filename[idx] == 0) {
|
if (filename[idx] == 0) {
|
||||||
return known_good_idx;
|
return known_good_idx;
|
||||||
#if SIMPLE_ARCHIVER_PLATFORM != SIMPLE_ARCHIVER_PLATFORM_WINDOWS
|
|
||||||
} else if (filename[idx] == '/') {
|
} else if (filename[idx] == '/') {
|
||||||
#else
|
|
||||||
} else if (filename[idx] == '\\') {
|
|
||||||
#endif
|
|
||||||
continue;
|
continue;
|
||||||
} else if (filename[idx] == '.') {
|
} else if (filename[idx] == '.') {
|
||||||
flags &= 0xFFFFFFFC;
|
flags &= 0xFFFFFFFC;
|
||||||
|
@ -104,8 +90,8 @@ unsigned int simple_archiver_parser_internal_filename_idx(
|
||||||
}
|
}
|
||||||
|
|
||||||
void simple_archiver_parser_internal_remove_end_slash(char *filename) {
|
void simple_archiver_parser_internal_remove_end_slash(char *filename) {
|
||||||
int len = strlen(filename);
|
size_t len = strlen(filename);
|
||||||
int idx;
|
size_t idx;
|
||||||
for (idx = len; idx-- > 0;) {
|
for (idx = len; idx-- > 0;) {
|
||||||
if (filename[idx] != '/') {
|
if (filename[idx] != '/') {
|
||||||
++idx;
|
++idx;
|
||||||
|
@ -117,34 +103,6 @@ void simple_archiver_parser_internal_remove_end_slash(char *filename) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char *simple_archiver_internal_forward_to_backward_slash(const char *string) {
|
|
||||||
unsigned int len = strlen(string) + 1;
|
|
||||||
char *backward_slash_string = malloc(len);
|
|
||||||
strncpy(backward_slash_string, string, len);
|
|
||||||
|
|
||||||
for (unsigned int idx = 0; idx < len; ++idx) {
|
|
||||||
if (backward_slash_string[idx] == '/') {
|
|
||||||
backward_slash_string[idx] = '\\';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return backward_slash_string;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *simple_archiver_internal_backward_to_forward_slash(const char *string) {
|
|
||||||
unsigned int len = strlen(string) + 1;
|
|
||||||
char *forward_slash_string = malloc(len);
|
|
||||||
strncpy(forward_slash_string, string, len);
|
|
||||||
|
|
||||||
for (unsigned int idx = 0; idx < len; ++idx) {
|
|
||||||
if (forward_slash_string[idx] == '\\') {
|
|
||||||
forward_slash_string[idx] = '/';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return forward_slash_string;
|
|
||||||
}
|
|
||||||
|
|
||||||
void simple_archiver_internal_free_file_info_fn(void *data) {
|
void simple_archiver_internal_free_file_info_fn(void *data) {
|
||||||
SDArchiverFileInfo *file_info = data;
|
SDArchiverFileInfo *file_info = data;
|
||||||
if (file_info) {
|
if (file_info) {
|
||||||
|
@ -165,8 +123,6 @@ int list_get_last_fn(void *data, void *ud) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void container_no_free_fn(__attribute__((unused)) void *data) { return; }
|
|
||||||
|
|
||||||
int list_remove_same_str_fn(void *data, void *ud) {
|
int list_remove_same_str_fn(void *data, void *ud) {
|
||||||
if (strcmp((char *)data, (char *)ud) == 0) {
|
if (strcmp((char *)data, (char *)ud) == 0) {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -176,15 +132,40 @@ int list_remove_same_str_fn(void *data, void *ud) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void simple_archiver_print_usage(void) {
|
void simple_archiver_print_usage(void) {
|
||||||
puts("Usage flags:");
|
fprintf(stderr, "Usage flags:\n");
|
||||||
puts("-c : create archive file");
|
fprintf(stderr, "-c : create archive file\n");
|
||||||
puts("-x : extract archive file");
|
fprintf(stderr, "-x : extract archive file\n");
|
||||||
puts("-f <filename> : filename to work on");
|
fprintf(stderr, "-t : examine archive file\n");
|
||||||
puts("--compressor <full_compress_cmd> : requires --decompressor");
|
fprintf(stderr, "-f <filename> : filename to work on\n");
|
||||||
puts("--decompressor <full_decompress_cmd> : requires --compressor");
|
fprintf(stderr,
|
||||||
puts("-- : specifies remaining arguments are files to archive/extract");
|
" Use \"-f -\" to work on stdout when creating archive or stdin "
|
||||||
puts("If creating archive file, remaining args specify files to archive.");
|
"when reading archive\n");
|
||||||
puts("If extracting archive file, remaining args specify files to extract.");
|
fprintf(stderr, " NOTICE: \"-f\" is not affected by \"-C\"!\n");
|
||||||
|
fprintf(stderr,
|
||||||
|
"-C <dir> : Change current working directory before "
|
||||||
|
"archiving/extracting\n");
|
||||||
|
fprintf(stderr,
|
||||||
|
"--compressor <full_compress_cmd> : requires --decompressor\n");
|
||||||
|
fprintf(stderr,
|
||||||
|
"--decompressor <full_decompress_cmd> : requires --compressor\n");
|
||||||
|
fprintf(stderr,
|
||||||
|
" Specifying \"--decompressor\" when extracting overrides archive "
|
||||||
|
"file's stored decompressor cmd\n");
|
||||||
|
fprintf(stderr, "--overwrite-create : allows overwriting an archive file\n");
|
||||||
|
fprintf(stderr, "--overwrite-extract : allows overwriting when extracting\n");
|
||||||
|
fprintf(stderr,
|
||||||
|
"--no-abs-symlink : do not store absolute paths for symlinks\n");
|
||||||
|
fprintf(stderr,
|
||||||
|
"--temp-files-dir <dir> : where to store temporary files created "
|
||||||
|
"when compressing (defaults to current working directory)\n");
|
||||||
|
fprintf(stderr,
|
||||||
|
"-- : specifies remaining arguments are files to archive/extract\n");
|
||||||
|
fprintf(
|
||||||
|
stderr,
|
||||||
|
"If creating archive file, remaining args specify files to archive.\n");
|
||||||
|
fprintf(
|
||||||
|
stderr,
|
||||||
|
"If extracting archive file, remaining args specify files to extract.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SDArchiverParsed simple_archiver_create_parsed(void) {
|
SDArchiverParsed simple_archiver_create_parsed(void) {
|
||||||
|
@ -195,6 +176,8 @@ SDArchiverParsed simple_archiver_create_parsed(void) {
|
||||||
parsed.compressor = NULL;
|
parsed.compressor = NULL;
|
||||||
parsed.decompressor = NULL;
|
parsed.decompressor = NULL;
|
||||||
parsed.working_files = NULL;
|
parsed.working_files = NULL;
|
||||||
|
parsed.temp_dir = NULL;
|
||||||
|
parsed.user_cwd = NULL;
|
||||||
|
|
||||||
return parsed;
|
return parsed;
|
||||||
}
|
}
|
||||||
|
@ -222,30 +205,89 @@ int simple_archiver_parse_args(int argc, const char **argv,
|
||||||
|
|
||||||
while (argc > 0) {
|
while (argc > 0) {
|
||||||
if (!is_remaining_args) {
|
if (!is_remaining_args) {
|
||||||
if (strcmp(argv[0], "-c") == 0) {
|
if (strcmp(argv[0], "-h") == 0 || strcmp(argv[0], "--help") == 0) {
|
||||||
// unset first bit.
|
simple_archiver_free_parsed(out);
|
||||||
out->flags &= 0xFFFFFFFE;
|
simple_archiver_print_usage();
|
||||||
|
exit(0);
|
||||||
|
} else if (strcmp(argv[0], "-c") == 0) {
|
||||||
|
// unset first two bits.
|
||||||
|
out->flags &= 0xFFFFFFFC;
|
||||||
} else if (strcmp(argv[0], "-x") == 0) {
|
} else if (strcmp(argv[0], "-x") == 0) {
|
||||||
|
// unset first two bits.
|
||||||
|
out->flags &= 0xFFFFFFFC;
|
||||||
// set first bit.
|
// set first bit.
|
||||||
out->flags |= 0x1;
|
out->flags |= 0x1;
|
||||||
} else if (strcmp(argv[0], "-f") == 0 && argc > 1) {
|
} else if (strcmp(argv[0], "-t") == 0) {
|
||||||
int size = strlen(argv[1]) + 1;
|
// unset first two bits.
|
||||||
|
out->flags &= 0xFFFFFFFC;
|
||||||
|
// set second bit.
|
||||||
|
out->flags |= 0x2;
|
||||||
|
} else if (strcmp(argv[0], "-f") == 0) {
|
||||||
|
if (argc < 2) {
|
||||||
|
fprintf(stderr, "ERROR: -f specified but missing argument!\n");
|
||||||
|
simple_archiver_print_usage();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (strcmp(argv[1], "-") == 0) {
|
||||||
|
out->flags |= 0x10;
|
||||||
|
if (out->filename) {
|
||||||
|
free(out->filename);
|
||||||
|
}
|
||||||
|
out->filename = NULL;
|
||||||
|
} else {
|
||||||
|
out->flags &= 0xFFFFFFEF;
|
||||||
|
size_t size = strlen(argv[1]) + 1;
|
||||||
out->filename = malloc(size);
|
out->filename = malloc(size);
|
||||||
strncpy(out->filename, argv[1], size);
|
strncpy(out->filename, argv[1], size);
|
||||||
|
}
|
||||||
--argc;
|
--argc;
|
||||||
++argv;
|
++argv;
|
||||||
} else if (strcmp(argv[0], "--compressor") == 0 && argc > 1) {
|
} else if (strcmp(argv[0], "-C") == 0) {
|
||||||
int size = strlen(argv[1]) + 1;
|
if (argc < 2) {
|
||||||
|
fprintf(stderr, "ERROR: -C specified but missing argument!\n");
|
||||||
|
simple_archiver_print_usage();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
out->user_cwd = argv[1];
|
||||||
|
--argc;
|
||||||
|
++argv;
|
||||||
|
} else if (strcmp(argv[0], "--compressor") == 0) {
|
||||||
|
if (argc < 2) {
|
||||||
|
fprintf(stderr, "--compressor specfied but missing argument!\n");
|
||||||
|
simple_archiver_print_usage();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
size_t size = strlen(argv[1]) + 1;
|
||||||
out->compressor = malloc(size);
|
out->compressor = malloc(size);
|
||||||
strncpy(out->compressor, argv[1], size);
|
strncpy(out->compressor, argv[1], size);
|
||||||
--argc;
|
--argc;
|
||||||
++argv;
|
++argv;
|
||||||
} else if (strcmp(argv[0], "--decompressor") == 0 && argc > 1) {
|
} else if (strcmp(argv[0], "--decompressor") == 0) {
|
||||||
int size = strlen(argv[1]) + 1;
|
if (argc < 2) {
|
||||||
|
fprintf(stderr, "--decompressor specfied but missing argument!\n");
|
||||||
|
simple_archiver_print_usage();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
size_t size = strlen(argv[1]) + 1;
|
||||||
out->decompressor = malloc(size);
|
out->decompressor = malloc(size);
|
||||||
strncpy(out->decompressor, argv[1], size);
|
strncpy(out->decompressor, argv[1], size);
|
||||||
--argc;
|
--argc;
|
||||||
++argv;
|
++argv;
|
||||||
|
} else if (strcmp(argv[0], "--overwrite-create") == 0) {
|
||||||
|
out->flags |= 0x4;
|
||||||
|
} else if (strcmp(argv[0], "--overwrite-extract") == 0) {
|
||||||
|
out->flags |= 0x8;
|
||||||
|
} else if (strcmp(argv[0], "--no-abs-symlink") == 0) {
|
||||||
|
out->flags |= 0x20;
|
||||||
|
} else if (strcmp(argv[0], "--temp-files-dir") == 0) {
|
||||||
|
if (argc < 2) {
|
||||||
|
fprintf(stderr, "ERROR: --temp-files-dir is missing an argument!\n");
|
||||||
|
simple_archiver_print_usage();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
out->temp_dir = argv[1];
|
||||||
|
--argc;
|
||||||
|
++argv;
|
||||||
} else if (argv[0][0] == '-' && argv[0][1] == '-' && argv[0][2] == 0) {
|
} else if (argv[0][0] == '-' && argv[0][1] == '-' && argv[0][2] == 0) {
|
||||||
is_remaining_args = 1;
|
is_remaining_args = 1;
|
||||||
} else if (argv[0][0] != '-') {
|
} else if (argv[0][0] != '-') {
|
||||||
|
@ -255,15 +297,15 @@ int simple_archiver_parse_args(int argc, const char **argv,
|
||||||
} else {
|
} else {
|
||||||
if (out->working_files == NULL) {
|
if (out->working_files == NULL) {
|
||||||
out->working_files = malloc(sizeof(char *) * 2);
|
out->working_files = malloc(sizeof(char *) * 2);
|
||||||
unsigned int arg_idx =
|
size_t arg_idx =
|
||||||
simple_archiver_parser_internal_filename_idx(argv[0]);
|
simple_archiver_parser_internal_get_first_non_current_idx(argv[0]);
|
||||||
int arg_length = strlen(argv[0] + arg_idx) + 1;
|
size_t arg_length = strlen(argv[0] + arg_idx) + 1;
|
||||||
out->working_files[0] = malloc(arg_length);
|
out->working_files[0] = malloc(arg_length);
|
||||||
strncpy(out->working_files[0], argv[0] + arg_idx, arg_length);
|
strncpy(out->working_files[0], argv[0] + arg_idx, arg_length);
|
||||||
simple_archiver_parser_internal_remove_end_slash(out->working_files[0]);
|
simple_archiver_parser_internal_remove_end_slash(out->working_files[0]);
|
||||||
out->working_files[1] = NULL;
|
out->working_files[1] = NULL;
|
||||||
} else {
|
} else {
|
||||||
int working_size = 1;
|
size_t working_size = 1;
|
||||||
char **ptr = out->working_files;
|
char **ptr = out->working_files;
|
||||||
while (ptr && *ptr) {
|
while (ptr && *ptr) {
|
||||||
++working_size;
|
++working_size;
|
||||||
|
@ -276,9 +318,9 @@ int simple_archiver_parse_args(int argc, const char **argv,
|
||||||
|
|
||||||
// Set new actual last element to NULL.
|
// Set new actual last element to NULL.
|
||||||
out->working_files[working_size] = NULL;
|
out->working_files[working_size] = NULL;
|
||||||
unsigned int arg_idx =
|
size_t arg_idx =
|
||||||
simple_archiver_parser_internal_filename_idx(argv[0]);
|
simple_archiver_parser_internal_get_first_non_current_idx(argv[0]);
|
||||||
int size = strlen(argv[0] + arg_idx) + 1;
|
size_t size = strlen(argv[0] + arg_idx) + 1;
|
||||||
// Set last element to the arg.
|
// Set last element to the arg.
|
||||||
out->working_files[working_size - 1] = malloc(size);
|
out->working_files[working_size - 1] = malloc(size);
|
||||||
strncpy(out->working_files[working_size - 1], argv[0] + arg_idx, size);
|
strncpy(out->working_files[working_size - 1], argv[0] + arg_idx, size);
|
||||||
|
@ -291,6 +333,10 @@ int simple_archiver_parse_args(int argc, const char **argv,
|
||||||
++argv;
|
++argv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!out->temp_dir) {
|
||||||
|
out->temp_dir = "./";
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,19 +375,31 @@ SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
|
||||||
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
||||||
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
||||||
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
||||||
|
__attribute__((cleanup(
|
||||||
|
simple_archiver_helper_cleanup_chdir_back))) char *original_cwd = NULL;
|
||||||
|
if (parsed->user_cwd) {
|
||||||
|
original_cwd = realpath(".", NULL);
|
||||||
|
if (chdir(parsed->user_cwd)) {
|
||||||
|
simple_archiver_list_free(&files_list);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (char **iter = parsed->working_files; iter && *iter; ++iter) {
|
for (char **iter = parsed->working_files; iter && *iter; ++iter) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
memset(&st, 0, sizeof(struct stat));
|
memset(&st, 0, sizeof(struct stat));
|
||||||
fstatat(AT_FDCWD, *iter, &st, AT_SYMLINK_NOFOLLOW);
|
char *file_path = *iter;
|
||||||
|
fstatat(AT_FDCWD, file_path, &st, AT_SYMLINK_NOFOLLOW);
|
||||||
if ((st.st_mode & S_IFMT) == S_IFREG || (st.st_mode & S_IFMT) == S_IFLNK) {
|
if ((st.st_mode & S_IFMT) == S_IFREG || (st.st_mode & S_IFMT) == S_IFLNK) {
|
||||||
// Is a regular file or a symbolic link.
|
// Is a regular file or a symbolic link.
|
||||||
int len = strlen(*iter) + 1;
|
size_t len = strlen(file_path) + 1;
|
||||||
char *filename = malloc(len);
|
char *filename = malloc(len);
|
||||||
strncpy(filename, *iter, len);
|
strncpy(filename, file_path, len);
|
||||||
if (simple_archiver_hash_map_get(hash_map, filename, len - 1) == NULL) {
|
if (simple_archiver_hash_map_get(hash_map, filename, len - 1) == NULL) {
|
||||||
SDArchiverFileInfo *file_info = malloc(sizeof(SDArchiverFileInfo));
|
SDArchiverFileInfo *file_info = malloc(sizeof(SDArchiverFileInfo));
|
||||||
file_info->filename = filename;
|
file_info->filename = filename;
|
||||||
if ((st.st_mode & S_IFMT) == S_IFLNK) {
|
if ((st.st_mode & S_IFMT) == S_IFLNK) {
|
||||||
|
// Is a symlink.
|
||||||
file_info->link_dest = malloc(MAX_SYMBOLIC_LINK_SIZE);
|
file_info->link_dest = malloc(MAX_SYMBOLIC_LINK_SIZE);
|
||||||
ssize_t count = readlinkat(AT_FDCWD, filename, file_info->link_dest,
|
ssize_t count = readlinkat(AT_FDCWD, filename, file_info->link_dest,
|
||||||
MAX_SYMBOLIC_LINK_SIZE - 1);
|
MAX_SYMBOLIC_LINK_SIZE - 1);
|
||||||
|
@ -351,19 +409,42 @@ SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
|
||||||
file_info->link_dest[count] = 0;
|
file_info->link_dest[count] = 0;
|
||||||
} else {
|
} else {
|
||||||
// Failure.
|
// Failure.
|
||||||
|
fprintf(stderr,
|
||||||
|
"WARNING: Could not get link info for file \"%s\"!\n",
|
||||||
|
file_info->filename);
|
||||||
free(file_info->link_dest);
|
free(file_info->link_dest);
|
||||||
free(file_info);
|
free(file_info);
|
||||||
free(filename);
|
free(filename);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Is a regular file.
|
||||||
file_info->link_dest = NULL;
|
file_info->link_dest = NULL;
|
||||||
|
// Check that the file is readable by opening it. Easier than to
|
||||||
|
// check permissions because that would also require checking if the
|
||||||
|
// current USER can open the file.
|
||||||
|
FILE *readable_file = fopen(file_info->filename, "rb");
|
||||||
|
if (!readable_file) {
|
||||||
|
// Cannot open file, so it must be unreadable (at least by the
|
||||||
|
// current USER).
|
||||||
|
fprintf(stderr, "WARNING: \"%s\" is not readable, skipping!\n",
|
||||||
|
file_info->filename);
|
||||||
|
free(file_info->link_dest);
|
||||||
|
free(file_info);
|
||||||
|
free(filename);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
fclose(readable_file);
|
||||||
|
// fprintf(stderr, "DEBUG: \"%s\" is readable.\n",
|
||||||
|
// file_info->filename);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
simple_archiver_list_add(files_list, file_info,
|
simple_archiver_list_add(files_list, file_info,
|
||||||
simple_archiver_internal_free_file_info_fn);
|
simple_archiver_internal_free_file_info_fn);
|
||||||
simple_archiver_hash_map_insert(&hash_map, &hash_map_sentinel, filename,
|
simple_archiver_hash_map_insert(
|
||||||
len - 1, container_no_free_fn,
|
hash_map, &hash_map_sentinel, filename, len - 1,
|
||||||
container_no_free_fn);
|
simple_archiver_helper_datastructure_cleanup_nop,
|
||||||
|
simple_archiver_helper_datastructure_cleanup_nop);
|
||||||
} else {
|
} else {
|
||||||
free(filename);
|
free(filename);
|
||||||
}
|
}
|
||||||
|
@ -371,7 +452,9 @@ SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
|
||||||
// Is a directory.
|
// Is a directory.
|
||||||
__attribute__((cleanup(simple_archiver_list_free)))
|
__attribute__((cleanup(simple_archiver_list_free)))
|
||||||
SDArchiverLinkedList *dir_list = simple_archiver_list_init();
|
SDArchiverLinkedList *dir_list = simple_archiver_list_init();
|
||||||
simple_archiver_list_add(dir_list, *iter, container_no_free_fn);
|
simple_archiver_list_add(
|
||||||
|
dir_list, file_path,
|
||||||
|
simple_archiver_helper_datastructure_cleanup_nop);
|
||||||
char *next;
|
char *next;
|
||||||
while (dir_list->count != 0) {
|
while (dir_list->count != 0) {
|
||||||
simple_archiver_list_get(dir_list, list_get_last_fn, &next);
|
simple_archiver_list_get(dir_list, list_get_last_fn, &next);
|
||||||
|
@ -387,13 +470,15 @@ SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
|
||||||
strcmp(dir_entry->d_name, "..") == 0) {
|
strcmp(dir_entry->d_name, "..") == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
printf("dir entry in %s is %s\n", next, dir_entry->d_name);
|
// fprintf(stderr, "dir entry in %s is %s\n", next,
|
||||||
int combined_size = strlen(next) + strlen(dir_entry->d_name) + 2;
|
// dir_entry->d_name);
|
||||||
|
size_t combined_size = strlen(next) + strlen(dir_entry->d_name) + 2;
|
||||||
char *combined_path = malloc(combined_size);
|
char *combined_path = malloc(combined_size);
|
||||||
snprintf(combined_path, combined_size, "%s/%s", next,
|
snprintf(combined_path, combined_size, "%s/%s", next,
|
||||||
dir_entry->d_name);
|
dir_entry->d_name);
|
||||||
unsigned int valid_idx =
|
size_t valid_idx =
|
||||||
simple_archiver_parser_internal_filename_idx(combined_path);
|
simple_archiver_parser_internal_get_first_non_current_idx(
|
||||||
|
combined_path);
|
||||||
if (valid_idx > 0) {
|
if (valid_idx > 0) {
|
||||||
char *new_path = malloc(combined_size - valid_idx);
|
char *new_path = malloc(combined_size - valid_idx);
|
||||||
strncpy(new_path, combined_path + valid_idx,
|
strncpy(new_path, combined_path + valid_idx,
|
||||||
|
@ -413,6 +498,7 @@ SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
|
||||||
malloc(sizeof(SDArchiverFileInfo));
|
malloc(sizeof(SDArchiverFileInfo));
|
||||||
file_info->filename = combined_path;
|
file_info->filename = combined_path;
|
||||||
if ((st.st_mode & S_IFMT) == S_IFLNK) {
|
if ((st.st_mode & S_IFMT) == S_IFLNK) {
|
||||||
|
// Is a symlink.
|
||||||
file_info->link_dest = malloc(MAX_SYMBOLIC_LINK_SIZE);
|
file_info->link_dest = malloc(MAX_SYMBOLIC_LINK_SIZE);
|
||||||
ssize_t count =
|
ssize_t count =
|
||||||
readlinkat(AT_FDCWD, combined_path, file_info->link_dest,
|
readlinkat(AT_FDCWD, combined_path, file_info->link_dest,
|
||||||
|
@ -429,15 +515,36 @@ SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Is a regular file.
|
||||||
file_info->link_dest = NULL;
|
file_info->link_dest = NULL;
|
||||||
|
// Check that the file is readable by opening it. Easier than
|
||||||
|
// to check permissions because that would also require
|
||||||
|
// checking if the current USER can open the file.
|
||||||
|
FILE *readable_file = fopen(file_info->filename, "rb");
|
||||||
|
if (!readable_file) {
|
||||||
|
// Cannot open file, so it must be unreadable (at least by
|
||||||
|
// the current USER).
|
||||||
|
fprintf(stderr,
|
||||||
|
"WARNING: \"%s\" is not readable, skipping!\n",
|
||||||
|
file_info->filename);
|
||||||
|
free(file_info->link_dest);
|
||||||
|
free(file_info);
|
||||||
|
free(combined_path);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
fclose(readable_file);
|
||||||
|
// fprintf(stderr, "DEBUG: \"%s\" is readable.\n",
|
||||||
|
// file_info->filename);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
simple_archiver_list_add(
|
simple_archiver_list_add(
|
||||||
files_list, file_info,
|
files_list, file_info,
|
||||||
simple_archiver_internal_free_file_info_fn);
|
simple_archiver_internal_free_file_info_fn);
|
||||||
simple_archiver_hash_map_insert(
|
simple_archiver_hash_map_insert(
|
||||||
&hash_map, &hash_map_sentinel, combined_path,
|
hash_map, &hash_map_sentinel, combined_path,
|
||||||
combined_size - 1, container_no_free_fn,
|
combined_size - 1,
|
||||||
container_no_free_fn);
|
simple_archiver_helper_datastructure_cleanup_nop,
|
||||||
|
simple_archiver_helper_datastructure_cleanup_nop);
|
||||||
} else {
|
} else {
|
||||||
free(combined_path);
|
free(combined_path);
|
||||||
}
|
}
|
||||||
|
@ -460,87 +567,44 @@ SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
|
||||||
// Unhandled type. TODO handle this.
|
// Unhandled type. TODO handle this.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#elif SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_WINDOWS
|
|
||||||
for (char **iter = parsed->working_files; iter && *iter; ++iter) {
|
|
||||||
DWORD file_stats = GetFileAttributesA(*iter);
|
|
||||||
if (file_stats == INVALID_FILE_ATTRIBUTES) {
|
|
||||||
printf("Failed to get attributes for %s\n", *iter);
|
|
||||||
continue;
|
|
||||||
} else if ((file_stats & FILE_ATTRIBUTE_DIRECTORY) == 0) {
|
|
||||||
// Is not a directory.
|
|
||||||
if ((file_stats & FILE_ATTRIBUTE_REPARSE_POINT) == 0) {
|
|
||||||
// Is not a symbolic link. Is probably a regular file.
|
|
||||||
printf("%s is probably a regular file.\n", *iter);
|
|
||||||
} else {
|
|
||||||
// Check if "reparse point" is a symbolic link.
|
|
||||||
WIN32_FIND_DATAA find_data;
|
|
||||||
HANDLE find_handle = FindFirstFileA(*iter, &find_data);
|
|
||||||
if (find_handle == INVALID_HANDLE_VALUE) {
|
|
||||||
printf("Unable to verify if %s is a symbolic link!\n", *iter);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
printf("Filename in find data structure is \"%s\".\n",
|
|
||||||
find_data.cFileName);
|
|
||||||
if (find_data.dwReserved0 != IO_REPARSE_TAG_SYMLINK) {
|
|
||||||
puts("NOTICE: result of FindFirstFileA does not have symlink tag!");
|
|
||||||
// printf("%s is not a symbolic link but is a reparse point (tag is
|
|
||||||
// %#lx).\n", *iter, find_data.dwReserved0);
|
|
||||||
// FindClose(find_handle);
|
|
||||||
// continue;
|
|
||||||
}
|
|
||||||
FindClose(find_handle);
|
|
||||||
// Is a symbolic link.
|
|
||||||
printf("%s is a symbolic link.\n", *iter);
|
|
||||||
HANDLE symlink_handle =
|
|
||||||
CreateFileA(*iter, GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
||||||
OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, NULL);
|
|
||||||
if (symlink_handle == INVALID_HANDLE_VALUE) {
|
|
||||||
puts("Failed to get handle on symbolic link!");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
REPARSE_GUID_DATA_BUFFER output;
|
|
||||||
printf("Size of REPARSE_GUID_DATA_BUFFER is %llu\n",
|
|
||||||
sizeof(REPARSE_GUID_DATA_BUFFER));
|
|
||||||
DWORD count;
|
|
||||||
OVERLAPPED overlapped;
|
|
||||||
if (DeviceIoControl(symlink_handle, FSCTL_GET_REPARSE_POINT, NULL, 0,
|
|
||||||
&output, sizeof(REPARSE_GUID_DATA_BUFFER), &count,
|
|
||||||
&overlapped) == 0) {
|
|
||||||
DWORD error = GetLastError();
|
|
||||||
printf("Failed to get info on symlink handle (%lu %#lx)!\n", error,
|
|
||||||
error);
|
|
||||||
CloseHandle(symlink_handle);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
printf("link destination count is %lu.\n", count);
|
|
||||||
// printf("First bytes:\n %#hhx %#hhx %#hhx %#hhx %#hhx %#hhx %#hhx
|
|
||||||
// %#hhx\n", output[0], output[1], output[2], output[3], output[4],
|
|
||||||
// output[5], output[6], output[7]);
|
|
||||||
|
|
||||||
// printf("Link to: %s\n", output.SymbolicLinkReparseBuffer.);
|
|
||||||
CloseHandle(symlink_handle);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Is a directory.
|
|
||||||
printf("%s is a directory.\n", *iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Remove leading "./" entries from files_list.
|
|
||||||
for (SDArchiverLLNode *iter = files_list->head->next;
|
for (SDArchiverLLNode *iter = files_list->head->next;
|
||||||
iter != files_list->tail; iter = iter->next) {
|
iter != files_list->tail; iter = iter->next) {
|
||||||
SDArchiverFileInfo *file_info = iter->data;
|
SDArchiverFileInfo *file_info = iter->data;
|
||||||
unsigned int idx =
|
|
||||||
simple_archiver_parser_internal_filename_idx(file_info->filename);
|
// Remove leading "./" entries from files_list.
|
||||||
|
size_t idx = simple_archiver_parser_internal_get_first_non_current_idx(
|
||||||
|
file_info->filename);
|
||||||
if (idx > 0) {
|
if (idx > 0) {
|
||||||
int len = strlen(file_info->filename) + 1 - idx;
|
size_t len = strlen(file_info->filename) + 1 - idx;
|
||||||
char *substr = malloc(len);
|
char *substr = malloc(len);
|
||||||
strncpy(substr, file_info->filename + idx, len);
|
strncpy(substr, file_info->filename + idx, len);
|
||||||
free(file_info->filename);
|
free(file_info->filename);
|
||||||
file_info->filename = substr;
|
file_info->filename = substr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove "./" entries inside the file path.
|
||||||
|
int slash_found = 0;
|
||||||
|
int dot_found = 0;
|
||||||
|
for (idx = strlen(file_info->filename); idx-- > 0;) {
|
||||||
|
if (file_info->filename[idx] == '/') {
|
||||||
|
if (dot_found) {
|
||||||
|
char *temp = simple_archiver_helper_cut_substr(file_info->filename,
|
||||||
|
idx + 1, idx + 3);
|
||||||
|
free(file_info->filename);
|
||||||
|
file_info->filename = temp;
|
||||||
|
} else {
|
||||||
|
slash_found = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (file_info->filename[idx] == '.' && slash_found) {
|
||||||
|
dot_found = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
slash_found = 0;
|
||||||
|
dot_found = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return files_list;
|
return files_list;
|
||||||
|
|
52
src/parser.h
52
src/parser.h
|
@ -1,20 +1,20 @@
|
||||||
/*
|
// ISC License
|
||||||
* Copyright 2024 Stephen Seo
|
//
|
||||||
*
|
// Copyright (c) 2024 Stephen Seo
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
//
|
||||||
* you may not use this file except in compliance with the License.
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* You may obtain a copy of the License at
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
*
|
// copyright notice and this permission notice appear in all copies.
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
*
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
* See the License for the specific language governing permissions and
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
* limitations under the License.
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
*
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
* `parser.h` is the header for parsing args.
|
//
|
||||||
*/
|
// `parser.h` is the header for parsing args.
|
||||||
|
|
||||||
#ifndef SEODISPARATE_COM_SIMPLE_ARCHIVER_PARSER_H_
|
#ifndef SEODISPARATE_COM_SIMPLE_ARCHIVER_PARSER_H_
|
||||||
#define SEODISPARATE_COM_SIMPLE_ARCHIVER_PARSER_H_
|
#define SEODISPARATE_COM_SIMPLE_ARCHIVER_PARSER_H_
|
||||||
|
@ -23,8 +23,14 @@
|
||||||
|
|
||||||
typedef struct SDArchiverParsed {
|
typedef struct SDArchiverParsed {
|
||||||
/// Each bit is a flag.
|
/// Each bit is a flag.
|
||||||
/// 0b0 - is creating.
|
/// 0b xxxx xx00 - is creating.
|
||||||
/// 0b1 - is extracting.
|
/// 0b xxxx xx01 - is extracting.
|
||||||
|
/// 0b xxxx xx10 - is checking/examining.
|
||||||
|
/// 0b xxxx x0xx - Do NOT allow create archive overwrite.
|
||||||
|
/// 0b xxxx x1xx - Allow create archive overwrite.
|
||||||
|
/// 0b xxxx 1xxx - Allow extract overwrite.
|
||||||
|
/// 0b xxx1 xxxx - Create archive to stdout or read archive from stdin.
|
||||||
|
/// 0b xx1x xxxx - Do not save absolute paths for symlinks.
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
/// Null-terminated string.
|
/// Null-terminated string.
|
||||||
char *filename;
|
char *filename;
|
||||||
|
@ -34,8 +40,13 @@ typedef struct SDArchiverParsed {
|
||||||
char *decompressor;
|
char *decompressor;
|
||||||
/// Null-terminated strings in array of strings.
|
/// Null-terminated strings in array of strings.
|
||||||
/// Last entry should be NULL.
|
/// Last entry should be NULL.
|
||||||
/// Not used when extracting.
|
/// Determines a "white-list" of files to extract when extracting.
|
||||||
char **working_files;
|
char **working_files;
|
||||||
|
/// Determines where to place temporary files. If NULL, temporary files are
|
||||||
|
/// created in the current working directory.
|
||||||
|
const char *temp_dir;
|
||||||
|
/// Dir specified by "-C".
|
||||||
|
const char *user_cwd;
|
||||||
} SDArchiverParsed;
|
} SDArchiverParsed;
|
||||||
|
|
||||||
typedef struct SDArchiverFileInfo {
|
typedef struct SDArchiverFileInfo {
|
||||||
|
@ -51,6 +62,7 @@ SDArchiverParsed simple_archiver_create_parsed(void);
|
||||||
/// Expects the user to pass a pointer to an SDArchiverParsed.
|
/// Expects the user to pass a pointer to an SDArchiverParsed.
|
||||||
/// This means the user should have a SDArchiverParsed variable
|
/// This means the user should have a SDArchiverParsed variable
|
||||||
/// and it should be passed with e.g. "&var".
|
/// and it should be passed with e.g. "&var".
|
||||||
|
/// Returns 0 on success.
|
||||||
int simple_archiver_parse_args(int argc, const char **argv,
|
int simple_archiver_parse_args(int argc, const char **argv,
|
||||||
SDArchiverParsed *out);
|
SDArchiverParsed *out);
|
||||||
|
|
||||||
|
|
|
@ -1,26 +1,27 @@
|
||||||
/*
|
// ISC License
|
||||||
* Copyright 2024 Stephen Seo
|
//
|
||||||
*
|
// Copyright (c) 2024 Stephen Seo
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
//
|
||||||
* you may not use this file except in compliance with the License.
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* You may obtain a copy of the License at
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
*
|
// copyright notice and this permission notice appear in all copies.
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
*
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
* See the License for the specific language governing permissions and
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
* limitations under the License.
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
*
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
* `parser_internal.h` is the header for parsing args with internal functions.
|
//
|
||||||
*/
|
// `parser_internal.h` is the header for parsing args with internal functions.
|
||||||
|
|
||||||
#ifndef SEODISPARATE_COM_SIMPLE_ARCHIVER_PARSER_INTERNAL_H_
|
#ifndef SEODISPARATE_COM_SIMPLE_ARCHIVER_PARSER_INTERNAL_H_
|
||||||
#define SEODISPARATE_COM_SIMPLE_ARCHIVER_PARSER_INTERNAL_H_
|
#define SEODISPARATE_COM_SIMPLE_ARCHIVER_PARSER_INTERNAL_H_
|
||||||
|
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
unsigned int simple_archiver_parser_internal_filename_idx(const char *filename);
|
size_t simple_archiver_parser_internal_get_first_non_current_idx(
|
||||||
|
const char *filename);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
/*
|
// ISC License
|
||||||
* Copyright 2024 Stephen Seo
|
//
|
||||||
*
|
// Copyright (c) 2024 Stephen Seo
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
//
|
||||||
* you may not use this file except in compliance with the License.
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* You may obtain a copy of the License at
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
*
|
// copyright notice and this permission notice appear in all copies.
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
*
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
* See the License for the specific language governing permissions and
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
* limitations under the License.
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
*
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
* `platforms.h` is the header that determines what platform this program is
|
//
|
||||||
* compiled for.
|
// `platforms.h` is the header that determines what platform this program is
|
||||||
*/
|
// compiled for.
|
||||||
|
|
||||||
#ifndef SEODISPARATE_COM_SIMPLE_ARCHIVER_PLATFORMS_H_
|
#ifndef SEODISPARATE_COM_SIMPLE_ARCHIVER_PLATFORMS_H_
|
||||||
#define SEODISPARATE_COM_SIMPLE_ARCHIVER_PLATFORMS_H_
|
#define SEODISPARATE_COM_SIMPLE_ARCHIVER_PLATFORMS_H_
|
||||||
|
|
128
src/test.c
128
src/test.c
|
@ -1,20 +1,20 @@
|
||||||
/*
|
// ISC License
|
||||||
* Copyright 2024 Stephen Seo
|
//
|
||||||
*
|
// Copyright (c) 2024 Stephen Seo
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
//
|
||||||
* you may not use this file except in compliance with the License.
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* You may obtain a copy of the License at
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
*
|
// copyright notice and this permission notice appear in all copies.
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
*
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
* See the License for the specific language governing permissions and
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
* limitations under the License.
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
*
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
* `test.c` is the source for testing code.
|
//
|
||||||
*/
|
// `test.c` is the source for testing code.
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -44,38 +44,55 @@ static int checks_passed = 0;
|
||||||
++checks_passed; \
|
++checks_passed; \
|
||||||
} \
|
} \
|
||||||
} while (0);
|
} while (0);
|
||||||
|
#define CHECK_STREQ(a, b) \
|
||||||
|
do { \
|
||||||
|
++checks_checked; \
|
||||||
|
if (strcmp((a), (b)) == 0) { \
|
||||||
|
++checks_passed; \
|
||||||
|
} else { \
|
||||||
|
printf("CHECK_STREQ at line %u failed: %s != %s\n", __LINE__, #a, #b); \
|
||||||
|
} \
|
||||||
|
} while (0);
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
// Test parser.
|
// Test parser.
|
||||||
{
|
{
|
||||||
unsigned int idx = simple_archiver_parser_internal_filename_idx("test");
|
unsigned int idx =
|
||||||
|
simple_archiver_parser_internal_get_first_non_current_idx("test");
|
||||||
CHECK_TRUE(idx == 0);
|
CHECK_TRUE(idx == 0);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_filename_idx("./test");
|
idx = simple_archiver_parser_internal_get_first_non_current_idx("./test");
|
||||||
CHECK_TRUE(idx == 2);
|
CHECK_TRUE(idx == 2);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_filename_idx("././test");
|
idx = simple_archiver_parser_internal_get_first_non_current_idx("././test");
|
||||||
CHECK_TRUE(idx == 4);
|
CHECK_TRUE(idx == 4);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_filename_idx("././//././//./test");
|
idx = simple_archiver_parser_internal_get_first_non_current_idx(
|
||||||
|
"././//././//./test");
|
||||||
CHECK_TRUE(idx == 14);
|
CHECK_TRUE(idx == 14);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_filename_idx("/././//././//./test");
|
idx = simple_archiver_parser_internal_get_first_non_current_idx(
|
||||||
|
"/././//././//./test");
|
||||||
CHECK_TRUE(idx == 0);
|
CHECK_TRUE(idx == 0);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_filename_idx(".derp/.//././//./test");
|
idx = simple_archiver_parser_internal_get_first_non_current_idx(
|
||||||
|
".derp/.//././//./test");
|
||||||
CHECK_TRUE(idx == 0);
|
CHECK_TRUE(idx == 0);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_filename_idx("././/.derp/.///./test");
|
idx = simple_archiver_parser_internal_get_first_non_current_idx(
|
||||||
|
"././/.derp/.///./test");
|
||||||
CHECK_TRUE(idx == 5);
|
CHECK_TRUE(idx == 5);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_filename_idx("././/.//.//./");
|
idx = simple_archiver_parser_internal_get_first_non_current_idx(
|
||||||
|
"././/.//.//./");
|
||||||
CHECK_TRUE(idx == 11);
|
CHECK_TRUE(idx == 11);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_filename_idx("././/.//.//.");
|
idx = simple_archiver_parser_internal_get_first_non_current_idx(
|
||||||
|
"././/.//.//.");
|
||||||
CHECK_TRUE(idx == 11);
|
CHECK_TRUE(idx == 11);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_filename_idx("././/.//.//");
|
idx = simple_archiver_parser_internal_get_first_non_current_idx(
|
||||||
|
"././/.//.//");
|
||||||
CHECK_TRUE(idx == 8);
|
CHECK_TRUE(idx == 8);
|
||||||
|
|
||||||
SDArchiverParsed parsed = simple_archiver_create_parsed();
|
SDArchiverParsed parsed = simple_archiver_create_parsed();
|
||||||
|
@ -114,7 +131,7 @@ int main(void) {
|
||||||
{
|
{
|
||||||
// Only if system is little-endian.
|
// Only if system is little-endian.
|
||||||
if (simple_archiver_helper_is_big_endian() == 0) {
|
if (simple_archiver_helper_is_big_endian() == 0) {
|
||||||
unsigned short u16 = 0x0102;
|
uint16_t u16 = 0x0102;
|
||||||
CHECK_TRUE(((unsigned char *)&u16)[0] == 2);
|
CHECK_TRUE(((unsigned char *)&u16)[0] == 2);
|
||||||
CHECK_TRUE(((unsigned char *)&u16)[1] == 1);
|
CHECK_TRUE(((unsigned char *)&u16)[1] == 1);
|
||||||
simple_archiver_helper_16_bit_be(&u16);
|
simple_archiver_helper_16_bit_be(&u16);
|
||||||
|
@ -124,7 +141,7 @@ int main(void) {
|
||||||
CHECK_TRUE(((unsigned char *)&u16)[0] == 2);
|
CHECK_TRUE(((unsigned char *)&u16)[0] == 2);
|
||||||
CHECK_TRUE(((unsigned char *)&u16)[1] == 1);
|
CHECK_TRUE(((unsigned char *)&u16)[1] == 1);
|
||||||
|
|
||||||
unsigned int u32 = 0x01020304;
|
uint32_t u32 = 0x01020304;
|
||||||
CHECK_TRUE(((unsigned char *)&u32)[0] == 4);
|
CHECK_TRUE(((unsigned char *)&u32)[0] == 4);
|
||||||
CHECK_TRUE(((unsigned char *)&u32)[1] == 3);
|
CHECK_TRUE(((unsigned char *)&u32)[1] == 3);
|
||||||
CHECK_TRUE(((unsigned char *)&u32)[2] == 2);
|
CHECK_TRUE(((unsigned char *)&u32)[2] == 2);
|
||||||
|
@ -140,7 +157,7 @@ int main(void) {
|
||||||
CHECK_TRUE(((unsigned char *)&u32)[2] == 2);
|
CHECK_TRUE(((unsigned char *)&u32)[2] == 2);
|
||||||
CHECK_TRUE(((unsigned char *)&u32)[3] == 1);
|
CHECK_TRUE(((unsigned char *)&u32)[3] == 1);
|
||||||
|
|
||||||
unsigned long long u64 = 0x010203040a0b0c0d;
|
uint64_t u64 = 0x010203040a0b0c0d;
|
||||||
CHECK_TRUE(((unsigned char *)&u64)[0] == 0xd);
|
CHECK_TRUE(((unsigned char *)&u64)[0] == 0xd);
|
||||||
CHECK_TRUE(((unsigned char *)&u64)[1] == 0xc);
|
CHECK_TRUE(((unsigned char *)&u64)[1] == 0xc);
|
||||||
CHECK_TRUE(((unsigned char *)&u64)[2] == 0xb);
|
CHECK_TRUE(((unsigned char *)&u64)[2] == 0xb);
|
||||||
|
@ -170,6 +187,57 @@ int main(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test helpers cmd string to argv.
|
||||||
|
do {
|
||||||
|
const char *cmd = "zstd --compress --ultra\n -20 derp_file";
|
||||||
|
char **result_argv = simple_archiver_helper_cmd_string_to_argv(cmd);
|
||||||
|
CHECK_TRUE(result_argv);
|
||||||
|
if (!result_argv) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
CHECK_STREQ("zstd", result_argv[0]);
|
||||||
|
CHECK_STREQ("--compress", result_argv[1]);
|
||||||
|
CHECK_STREQ("--ultra", result_argv[2]);
|
||||||
|
CHECK_STREQ("-20", result_argv[3]);
|
||||||
|
CHECK_STREQ("derp_file", result_argv[4]);
|
||||||
|
CHECK_TRUE(result_argv[5] == NULL);
|
||||||
|
|
||||||
|
simple_archiver_helper_cmd_string_argv_free(result_argv);
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
// Test helpers cut substr.
|
||||||
|
{
|
||||||
|
const char *s = "one two three.";
|
||||||
|
unsigned int s_len = strlen(s);
|
||||||
|
// Invalid range.
|
||||||
|
char *out = simple_archiver_helper_cut_substr(s, 1, 0);
|
||||||
|
CHECK_FALSE(out);
|
||||||
|
// First idx out of range.
|
||||||
|
out = simple_archiver_helper_cut_substr(s, s_len, s_len + 1);
|
||||||
|
CHECK_FALSE(out);
|
||||||
|
// Second idx out of range.
|
||||||
|
out = simple_archiver_helper_cut_substr(s, 1, s_len + 1);
|
||||||
|
CHECK_FALSE(out);
|
||||||
|
// Invalid cut of full string.
|
||||||
|
out = simple_archiver_helper_cut_substr(s, 0, s_len);
|
||||||
|
CHECK_FALSE(out);
|
||||||
|
// Cut end of string.
|
||||||
|
out = simple_archiver_helper_cut_substr(s, 2, s_len);
|
||||||
|
CHECK_TRUE(out);
|
||||||
|
CHECK_STREQ(out, "on");
|
||||||
|
free(out);
|
||||||
|
// Cut start of string.
|
||||||
|
out = simple_archiver_helper_cut_substr(s, 0, s_len - 3);
|
||||||
|
CHECK_TRUE(out);
|
||||||
|
CHECK_STREQ(out, "ee.");
|
||||||
|
free(out);
|
||||||
|
// Cut inside string.
|
||||||
|
out = simple_archiver_helper_cut_substr(s, 4, 8);
|
||||||
|
CHECK_TRUE(out);
|
||||||
|
CHECK_STREQ(out, "one three.");
|
||||||
|
free(out);
|
||||||
|
}
|
||||||
|
|
||||||
printf("Checks checked: %u\n", checks_checked);
|
printf("Checks checked: %u\n", checks_checked);
|
||||||
printf("Checks passed: %u\n", checks_passed);
|
printf("Checks passed: %u\n", checks_passed);
|
||||||
return checks_passed == checks_checked ? 0 : 1;
|
return checks_passed == checks_checked ? 0 : 1;
|
||||||
|
|
Loading…
Reference in a new issue