Compare commits
1 commit
Author | SHA1 | Date | |
---|---|---|---|
664dcfaa89 |
24 changed files with 735 additions and 3185 deletions
|
@ -7,7 +7,6 @@ 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,15 +1,201 @@
|
||||||
ISC License
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
Copyright (c) 2024 Stephen Seo
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
1. Definitions.
|
||||||
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
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
||||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
the copyright owner that is granting the License.
|
||||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
||||||
PERFORMANCE OF THIS SOFTWARE.
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
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,7 +1,6 @@
|
||||||
# Simple Archiver
|
# Simple Archiver
|
||||||
|
|
||||||
This program ~~is not yet~~ almost finished! Basic functionality is implemented
|
This program is not yet finished! You can track progress
|
||||||
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
|
||||||
|
@ -10,30 +9,6 @@ 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 [ISC License](https://choosealicense.com/licenses/isc/).
|
Uses the [Apache License 2.0](https://choosealicense.com/licenses/apache-2.0).
|
||||||
|
|
|
@ -7,7 +7,6 @@ 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 \
|
||||||
|
@ -17,7 +16,6 @@ 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,7 +1,5 @@
|
||||||
# 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"
|
||||||
|
@ -45,18 +43,8 @@ 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. The first bit is "other write permission".
|
1. Currently unused.
|
||||||
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.
|
||||||
|
@ -73,6 +61,5 @@ 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");
|
||||||
// Permission to use, copy, modify, and/or distribute this software for any
|
* you may not use this file except in compliance with the License.
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
* You may obtain a copy of the License at
|
||||||
// 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
|
*
|
||||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
* See the License for the specific language governing permissions and
|
||||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
* limitations under the License.
|
||||||
// PERFORMANCE OF THIS SOFTWARE.
|
*
|
||||||
//
|
* `linear_congruential_gen.c` is the source for the linear congruential
|
||||||
// `linear_congruential_gen.c` is the source for the linear congruential
|
* generator algorithm.
|
||||||
// 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");
|
||||||
// Permission to use, copy, modify, and/or distribute this software for any
|
* you may not use this file except in compliance with the License.
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
* You may obtain a copy of the License at
|
||||||
// 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
|
*
|
||||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
* See the License for the specific language governing permissions and
|
||||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
* limitations under the License.
|
||||||
// PERFORMANCE OF THIS SOFTWARE.
|
*
|
||||||
//
|
* `linear_congruential_gen.h` is the header for the linear congruential
|
||||||
// `linear_congruential_gen.h` is the header for the linear congruential
|
* generator algorithm.
|
||||||
// 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
1913
src/archiver.c
File diff suppressed because it is too large
Load diff
|
@ -1,73 +0,0 @@
|
||||||
// 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");
|
||||||
// Permission to use, copy, modify, and/or distribute this software for any
|
* you may not use this file except in compliance with the License.
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
* You may obtain a copy of the License at
|
||||||
// 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
|
*
|
||||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
* See the License for the specific language governing permissions and
|
||||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
* limitations under the License.
|
||||||
// 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,22 +26,16 @@
|
||||||
typedef struct SDArchiverHashMapData {
|
typedef struct SDArchiverHashMapData {
|
||||||
void *value;
|
void *value;
|
||||||
void *key;
|
void *key;
|
||||||
size_t key_size;
|
unsigned int 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;
|
||||||
size_t key_size;
|
unsigned int 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) {
|
||||||
|
@ -75,11 +69,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(
|
||||||
const void *key, size_t key_size) {
|
void *key, unsigned int key_size) {
|
||||||
unsigned long long seed = 0;
|
unsigned long long seed = 0;
|
||||||
unsigned long long temp = 0;
|
unsigned long long temp = 0;
|
||||||
size_t count = 0;
|
unsigned int count = 0;
|
||||||
for (size_t idx = 0; idx < key_size; ++idx) {
|
for (unsigned int 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) {
|
||||||
|
@ -101,27 +95,28 @@ 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) {
|
if (!hash_map || !*hash_map) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
SDArchiverHashMap new_hash_map;
|
SDArchiverHashMap *new_hash_map = malloc(sizeof(SDArchiverHashMap));
|
||||||
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 (size_t idx = 0; idx < new_hash_map.buckets_size; ++idx) {
|
for (unsigned int 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 (size_t bucket_idx = 0; bucket_idx < hash_map->buckets_size;
|
for (unsigned int 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 && node->data) {
|
if (node && node != (*hash_map)->buckets[bucket_idx]->tail &&
|
||||||
|
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,
|
||||||
|
@ -132,14 +127,7 @@ int simple_archiver_hash_map_internal_rehash(SDArchiverHashMap *hash_map) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free the buckets in the old hash_map.
|
simple_archiver_hash_map_free(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;
|
||||||
|
@ -151,7 +139,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 (size_t idx = 0; idx < hash_map->buckets_size; ++idx) {
|
for (unsigned int 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;
|
||||||
|
@ -161,7 +149,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 (size_t idx = 0; idx < (*hash_map)->buckets_size; ++idx) {
|
for (unsigned int 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);
|
||||||
}
|
}
|
||||||
|
@ -173,11 +161,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, size_t key_size,
|
void *key, unsigned int 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,13 +178,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) {
|
||||||
|
@ -219,8 +207,8 @@ int simple_archiver_hash_map_insert(SDArchiverHashMap *hash_map, void *value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void *simple_archiver_hash_map_get(const SDArchiverHashMap *hash_map,
|
void *simple_archiver_hash_map_get(SDArchiverHashMap *hash_map, void *key,
|
||||||
const void *key, size_t key_size) {
|
unsigned int 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;
|
||||||
|
@ -240,7 +228,7 @@ void *simple_archiver_hash_map_get(const SDArchiverHashMap *hash_map,
|
||||||
}
|
}
|
||||||
|
|
||||||
int simple_archiver_hash_map_remove(SDArchiverHashMap *hash_map, void *key,
|
int simple_archiver_hash_map_remove(SDArchiverHashMap *hash_map, void *key,
|
||||||
size_t key_size) {
|
unsigned int 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;
|
||||||
|
@ -260,34 +248,3 @@ 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,34 +1,32 @@
|
||||||
// ISC License
|
/*
|
||||||
//
|
* Copyright 2024 Stephen Seo
|
||||||
// Copyright (c) 2024 Stephen Seo
|
*
|
||||||
//
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// Permission to use, copy, modify, and/or distribute this software for any
|
* you may not use this file except in compliance with the License.
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
* You may obtain a copy of the License at
|
||||||
// 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
|
*
|
||||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
* See the License for the specific language governing permissions and
|
||||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
* limitations under the License.
|
||||||
// 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;
|
||||||
size_t buckets_size;
|
unsigned int buckets_size;
|
||||||
size_t count;
|
unsigned int count;
|
||||||
} SDArchiverHashMap;
|
} SDArchiverHashMap;
|
||||||
|
|
||||||
SDArchiverHashMap *simple_archiver_hash_map_init(void);
|
SDArchiverHashMap *simple_archiver_hash_map_init(void);
|
||||||
|
@ -39,31 +37,18 @@ 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.
|
||||||
/// NOTICE: You must not pass NULL to value, otherwise all "get" checks will
|
int simple_archiver_hash_map_insert(SDArchiverHashMap **hash_map, void *value,
|
||||||
/// fail for the inserted key.
|
void *key, unsigned int key_size,
|
||||||
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(const SDArchiverHashMap *hash_map,
|
void *simple_archiver_hash_map_get(SDArchiverHashMap *hash_map, void *key,
|
||||||
const void *key, size_t key_size);
|
unsigned int 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,
|
||||||
size_t key_size);
|
unsigned int 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");
|
||||||
// Permission to use, copy, modify, and/or distribute this software for any
|
* you may not use this file except in compliance with the License.
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
* You may obtain a copy of the License at
|
||||||
// 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
|
*
|
||||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
* See the License for the specific language governing permissions and
|
||||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
* limitations under the License.
|
||||||
// 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(const SDArchiverLinkedList *list,
|
void *simple_archiver_list_get(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,26 +1,24 @@
|
||||||
// ISC License
|
/*
|
||||||
//
|
* Copyright 2024 Stephen Seo
|
||||||
// Copyright (c) 2024 Stephen Seo
|
*
|
||||||
//
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// Permission to use, copy, modify, and/or distribute this software for any
|
* you may not use this file except in compliance with the License.
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
* You may obtain a copy of the License at
|
||||||
// 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
|
*
|
||||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
* See the License for the specific language governing permissions and
|
||||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
* limitations under the License.
|
||||||
// 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;
|
||||||
|
@ -31,7 +29,7 @@ typedef struct SDArchiverLLNode {
|
||||||
typedef struct SDArchiverLinkedList {
|
typedef struct SDArchiverLinkedList {
|
||||||
SDArchiverLLNode *head;
|
SDArchiverLLNode *head;
|
||||||
SDArchiverLLNode *tail;
|
SDArchiverLLNode *tail;
|
||||||
size_t count;
|
unsigned int count;
|
||||||
} SDArchiverLinkedList;
|
} SDArchiverLinkedList;
|
||||||
|
|
||||||
SDArchiverLinkedList *simple_archiver_list_init(void);
|
SDArchiverLinkedList *simple_archiver_list_init(void);
|
||||||
|
@ -64,7 +62,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(const SDArchiverLinkedList *list,
|
void *simple_archiver_list_get(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");
|
||||||
// Permission to use, copy, modify, and/or distribute this software for any
|
* you may not use this file except in compliance with the License.
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
* You may obtain a copy of the License at
|
||||||
// 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
|
*
|
||||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
* See the License for the specific language governing permissions and
|
||||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
* limitations under the License.
|
||||||
// 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 (size_t idx = 1; idx < (*priority_heap)->size + 1; ++idx) {
|
for (unsigned int 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 (size_t idx = 1; idx < (*priority_heap)->size + 1; ++idx) {
|
for (unsigned int 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t hole = (*priority_heap)->size + 1;
|
unsigned int 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;
|
||||||
|
|
||||||
size_t hole = 1;
|
unsigned int 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");
|
||||||
// Permission to use, copy, modify, and/or distribute this software for any
|
* you may not use this file except in compliance with the License.
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
* You may obtain a copy of the License at
|
||||||
// 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
|
*
|
||||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
* See the License for the specific language governing permissions and
|
||||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
* limitations under the License.
|
||||||
// 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");
|
||||||
// Permission to use, copy, modify, and/or distribute this software for any
|
* you may not use this file except in compliance with the License.
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
* You may obtain a copy of the License at
|
||||||
// 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
|
*
|
||||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
* See the License for the specific language governing permissions and
|
||||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
* limitations under the License.
|
||||||
// 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,8 +25,6 @@
|
||||||
#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;
|
||||||
|
|
||||||
|
@ -65,26 +63,6 @@ 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.
|
||||||
{
|
{
|
||||||
|
@ -145,8 +123,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), NULL,
|
simple_archiver_hash_map_insert(&hash_map, value, key, sizeof(int),
|
||||||
NULL);
|
NULL, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,38 +162,10 @@ 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,84 +1,33 @@
|
||||||
// ISC License
|
/*
|
||||||
//
|
* Copyright 2024 Stephen Seo
|
||||||
// Copyright (c) 2024 Stephen Seo
|
*
|
||||||
//
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// Permission to use, copy, modify, and/or distribute this software for any
|
* you may not use this file except in compliance with the License.
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
* You may obtain a copy of the License at
|
||||||
// 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
|
*
|
||||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
* See the License for the specific language governing permissions and
|
||||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
* limitations under the License.
|
||||||
// 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 {
|
||||||
uint32_t i;
|
unsigned int 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(uint16_t *value) {
|
void simple_archiver_helper_16_bit_be(unsigned short *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];
|
||||||
|
@ -86,7 +35,7 @@ void simple_archiver_helper_16_bit_be(uint16_t *value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void simple_archiver_helper_32_bit_be(uint32_t *value) {
|
void simple_archiver_helper_32_bit_be(unsigned int *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];
|
||||||
|
@ -96,7 +45,7 @@ void simple_archiver_helper_32_bit_be(uint32_t *value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void simple_archiver_helper_64_bit_be(uint64_t *value) {
|
void simple_archiver_helper_64_bit_be(unsigned long long *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];
|
||||||
|
@ -105,153 +54,3 @@ void simple_archiver_helper_64_bit_be(uint64_t *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,65 +1,36 @@
|
||||||
// ISC License
|
/*
|
||||||
//
|
* Copyright 2024 Stephen Seo
|
||||||
// Copyright (c) 2024 Stephen Seo
|
*
|
||||||
//
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// Permission to use, copy, modify, and/or distribute this software for any
|
* you may not use this file except in compliance with the License.
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
* You may obtain a copy of the License at
|
||||||
// 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
|
*
|
||||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
* See the License for the specific language governing permissions and
|
||||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
* limitations under the License.
|
||||||
// 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(uint16_t *value);
|
void simple_archiver_helper_16_bit_be(unsigned short *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(uint32_t *value);
|
void simple_archiver_helper_32_bit_be(unsigned int *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(uint64_t *value);
|
void simple_archiver_helper_64_bit_be(unsigned long long *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
|
||||||
|
|
176
src/main.c
176
src/main.c
|
@ -1,174 +1,50 @@
|
||||||
// ISC License
|
/*
|
||||||
//
|
* Copyright 2024 Stephen Seo
|
||||||
// Copyright (c) 2024 Stephen Seo
|
*
|
||||||
//
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// Permission to use, copy, modify, and/or distribute this software for any
|
* you may not use this file except in compliance with the License.
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
* You may obtain a copy of the License at
|
||||||
// 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
|
*
|
||||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
* See the License for the specific language governing permissions and
|
||||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
* limitations under the License.
|
||||||
// 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) {
|
||||||
fprintf(stderr, " REGULAR FILE: %s\n", file_info->filename);
|
printf(" REGULAR FILE: %s\n", file_info->filename);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, " SYMBOLIC LINK: %s -> %s\n", file_info->filename,
|
printf(" 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__((
|
simple_archiver_print_usage();
|
||||||
cleanup(simple_archiver_free_parsed))) SDArchiverParsed parsed =
|
|
||||||
simple_archiver_create_parsed();
|
|
||||||
|
|
||||||
if (simple_archiver_parse_args(argc, argv, &parsed)) {
|
__attribute__((cleanup(simple_archiver_free_parsed)))
|
||||||
fprintf(stderr, "Failed to parse args.\n");
|
SDArchiverParsed parsed = simple_archiver_create_parsed();
|
||||||
return 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!parsed.filename && (parsed.flags & 0x10) == 0) {
|
simple_archiver_parse_args(argc, argv, &parsed);
|
||||||
fprintf(stderr, "ERROR: Filename not specified!\n");
|
|
||||||
simple_archiver_print_usage();
|
|
||||||
return 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((parsed.flags & 0x3) == 0 && (parsed.flags & 0x4) == 0) {
|
|
||||||
FILE *file = fopen(parsed.filename, "r");
|
|
||||||
if (file != NULL) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filenames->count > 0) {
|
puts("Filenames:");
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
422
src/parser.c
422
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");
|
||||||
// Permission to use, copy, modify, and/or distribute this software for any
|
* you may not use this file except in compliance with the License.
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
* You may obtain a copy of the License at
|
||||||
// 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
|
*
|
||||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
* See the License for the specific language governing permissions and
|
||||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
* limitations under the License.
|
||||||
// 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,6 +31,12 @@
|
||||||
#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"
|
||||||
|
@ -39,15 +45,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.
|
||||||
size_t simple_archiver_parser_internal_get_first_non_current_idx(
|
unsigned int simple_archiver_parser_internal_filename_idx(
|
||||||
const char *filename) {
|
const char *filename) {
|
||||||
size_t idx = 0;
|
unsigned int idx = 0;
|
||||||
size_t known_good_idx = 0;
|
unsigned int known_good_idx = 0;
|
||||||
const size_t length = strlen(filename);
|
const unsigned int 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 '/'
|
||||||
size_t flags = 0;
|
unsigned int flags = 0;
|
||||||
|
|
||||||
for (; idx < length; ++idx) {
|
for (; idx < length; ++idx) {
|
||||||
if ((flags & 3) == 0) {
|
if ((flags & 3) == 0) {
|
||||||
|
@ -61,7 +67,11 @@ size_t simple_archiver_parser_internal_get_first_non_current_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;
|
||||||
|
@ -69,7 +79,11 @@ size_t simple_archiver_parser_internal_get_first_non_current_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;
|
||||||
|
@ -90,8 +104,8 @@ size_t simple_archiver_parser_internal_get_first_non_current_idx(
|
||||||
}
|
}
|
||||||
|
|
||||||
void simple_archiver_parser_internal_remove_end_slash(char *filename) {
|
void simple_archiver_parser_internal_remove_end_slash(char *filename) {
|
||||||
size_t len = strlen(filename);
|
int len = strlen(filename);
|
||||||
size_t idx;
|
int idx;
|
||||||
for (idx = len; idx-- > 0;) {
|
for (idx = len; idx-- > 0;) {
|
||||||
if (filename[idx] != '/') {
|
if (filename[idx] != '/') {
|
||||||
++idx;
|
++idx;
|
||||||
|
@ -103,6 +117,34 @@ 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) {
|
||||||
|
@ -123,6 +165,8 @@ 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;
|
||||||
|
@ -132,40 +176,15 @@ int list_remove_same_str_fn(void *data, void *ud) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void simple_archiver_print_usage(void) {
|
void simple_archiver_print_usage(void) {
|
||||||
fprintf(stderr, "Usage flags:\n");
|
puts("Usage flags:");
|
||||||
fprintf(stderr, "-c : create archive file\n");
|
puts("-c : create archive file");
|
||||||
fprintf(stderr, "-x : extract archive file\n");
|
puts("-x : extract archive file");
|
||||||
fprintf(stderr, "-t : examine archive file\n");
|
puts("-f <filename> : filename to work on");
|
||||||
fprintf(stderr, "-f <filename> : filename to work on\n");
|
puts("--compressor <full_compress_cmd> : requires --decompressor");
|
||||||
fprintf(stderr,
|
puts("--decompressor <full_decompress_cmd> : requires --compressor");
|
||||||
" Use \"-f -\" to work on stdout when creating archive or stdin "
|
puts("-- : specifies remaining arguments are files to archive/extract");
|
||||||
"when reading archive\n");
|
puts("If creating archive file, remaining args specify files to archive.");
|
||||||
fprintf(stderr, " NOTICE: \"-f\" is not affected by \"-C\"!\n");
|
puts("If extracting archive file, remaining args specify files to extract.");
|
||||||
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) {
|
||||||
|
@ -176,8 +195,6 @@ 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;
|
||||||
}
|
}
|
||||||
|
@ -205,89 +222,30 @@ 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], "-h") == 0 || strcmp(argv[0], "--help") == 0) {
|
if (strcmp(argv[0], "-c") == 0) {
|
||||||
simple_archiver_free_parsed(out);
|
// unset first bit.
|
||||||
simple_archiver_print_usage();
|
out->flags &= 0xFFFFFFFE;
|
||||||
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], "-t") == 0) {
|
} else if (strcmp(argv[0], "-f") == 0 && argc > 1) {
|
||||||
// unset first two bits.
|
int size = strlen(argv[1]) + 1;
|
||||||
out->flags &= 0xFFFFFFFC;
|
out->filename = malloc(size);
|
||||||
// set second bit.
|
strncpy(out->filename, argv[1], size);
|
||||||
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);
|
|
||||||
strncpy(out->filename, argv[1], size);
|
|
||||||
}
|
|
||||||
--argc;
|
--argc;
|
||||||
++argv;
|
++argv;
|
||||||
} else if (strcmp(argv[0], "-C") == 0) {
|
} else if (strcmp(argv[0], "--compressor") == 0 && argc > 1) {
|
||||||
if (argc < 2) {
|
int size = strlen(argv[1]) + 1;
|
||||||
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) {
|
} else if (strcmp(argv[0], "--decompressor") == 0 && argc > 1) {
|
||||||
if (argc < 2) {
|
int size = strlen(argv[1]) + 1;
|
||||||
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] != '-') {
|
||||||
|
@ -297,15 +255,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);
|
||||||
size_t arg_idx =
|
unsigned int arg_idx =
|
||||||
simple_archiver_parser_internal_get_first_non_current_idx(argv[0]);
|
simple_archiver_parser_internal_filename_idx(argv[0]);
|
||||||
size_t arg_length = strlen(argv[0] + arg_idx) + 1;
|
int 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 {
|
||||||
size_t working_size = 1;
|
int working_size = 1;
|
||||||
char **ptr = out->working_files;
|
char **ptr = out->working_files;
|
||||||
while (ptr && *ptr) {
|
while (ptr && *ptr) {
|
||||||
++working_size;
|
++working_size;
|
||||||
|
@ -318,9 +276,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;
|
||||||
size_t arg_idx =
|
unsigned int arg_idx =
|
||||||
simple_archiver_parser_internal_get_first_non_current_idx(argv[0]);
|
simple_archiver_parser_internal_filename_idx(argv[0]);
|
||||||
size_t size = strlen(argv[0] + arg_idx) + 1;
|
int 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);
|
||||||
|
@ -333,10 +291,6 @@ int simple_archiver_parse_args(int argc, const char **argv,
|
||||||
++argv;
|
++argv;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!out->temp_dir) {
|
|
||||||
out->temp_dir = "./";
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,31 +329,19 @@ 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));
|
||||||
char *file_path = *iter;
|
fstatat(AT_FDCWD, *iter, &st, AT_SYMLINK_NOFOLLOW);
|
||||||
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.
|
||||||
size_t len = strlen(file_path) + 1;
|
int len = strlen(*iter) + 1;
|
||||||
char *filename = malloc(len);
|
char *filename = malloc(len);
|
||||||
strncpy(filename, file_path, len);
|
strncpy(filename, *iter, 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);
|
||||||
|
@ -409,42 +351,19 @@ 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(
|
simple_archiver_hash_map_insert(&hash_map, &hash_map_sentinel, filename,
|
||||||
hash_map, &hash_map_sentinel, filename, len - 1,
|
len - 1, container_no_free_fn,
|
||||||
simple_archiver_helper_datastructure_cleanup_nop,
|
container_no_free_fn);
|
||||||
simple_archiver_helper_datastructure_cleanup_nop);
|
|
||||||
} else {
|
} else {
|
||||||
free(filename);
|
free(filename);
|
||||||
}
|
}
|
||||||
|
@ -452,9 +371,7 @@ 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(
|
simple_archiver_list_add(dir_list, *iter, container_no_free_fn);
|
||||||
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);
|
||||||
|
@ -470,15 +387,13 @@ SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
|
||||||
strcmp(dir_entry->d_name, "..") == 0) {
|
strcmp(dir_entry->d_name, "..") == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// fprintf(stderr, "dir entry in %s is %s\n", next,
|
printf("dir entry in %s is %s\n", next, dir_entry->d_name);
|
||||||
// dir_entry->d_name);
|
int combined_size = strlen(next) + strlen(dir_entry->d_name) + 2;
|
||||||
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);
|
||||||
size_t valid_idx =
|
unsigned int valid_idx =
|
||||||
simple_archiver_parser_internal_get_first_non_current_idx(
|
simple_archiver_parser_internal_filename_idx(combined_path);
|
||||||
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,
|
||||||
|
@ -498,7 +413,6 @@ 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,
|
||||||
|
@ -515,36 +429,15 @@ 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,
|
combined_size - 1, container_no_free_fn,
|
||||||
simple_archiver_helper_datastructure_cleanup_nop,
|
container_no_free_fn);
|
||||||
simple_archiver_helper_datastructure_cleanup_nop);
|
|
||||||
} else {
|
} else {
|
||||||
free(combined_path);
|
free(combined_path);
|
||||||
}
|
}
|
||||||
|
@ -567,44 +460,87 @@ 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 =
|
||||||
// Remove leading "./" entries from files_list.
|
simple_archiver_parser_internal_filename_idx(file_info->filename);
|
||||||
size_t idx = simple_archiver_parser_internal_get_first_non_current_idx(
|
|
||||||
file_info->filename);
|
|
||||||
if (idx > 0) {
|
if (idx > 0) {
|
||||||
size_t len = strlen(file_info->filename) + 1 - idx;
|
int 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");
|
||||||
// Permission to use, copy, modify, and/or distribute this software for any
|
* you may not use this file except in compliance with the License.
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
* You may obtain a copy of the License at
|
||||||
// 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
|
*
|
||||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
* See the License for the specific language governing permissions and
|
||||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
* limitations under the License.
|
||||||
// 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,14 +23,8 @@
|
||||||
|
|
||||||
typedef struct SDArchiverParsed {
|
typedef struct SDArchiverParsed {
|
||||||
/// Each bit is a flag.
|
/// Each bit is a flag.
|
||||||
/// 0b xxxx xx00 - is creating.
|
/// 0b0 - is creating.
|
||||||
/// 0b xxxx xx01 - is extracting.
|
/// 0b1 - 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;
|
||||||
|
@ -40,13 +34,8 @@ 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.
|
||||||
/// Determines a "white-list" of files to extract when extracting.
|
/// Not used 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 {
|
||||||
|
@ -62,7 +51,6 @@ 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,27 +1,26 @@
|
||||||
// ISC License
|
/*
|
||||||
//
|
* Copyright 2024 Stephen Seo
|
||||||
// Copyright (c) 2024 Stephen Seo
|
*
|
||||||
//
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// Permission to use, copy, modify, and/or distribute this software for any
|
* you may not use this file except in compliance with the License.
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
* You may obtain a copy of the License at
|
||||||
// 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
|
*
|
||||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
* See the License for the specific language governing permissions and
|
||||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
* limitations under the License.
|
||||||
// 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"
|
||||||
|
|
||||||
size_t simple_archiver_parser_internal_get_first_non_current_idx(
|
unsigned int simple_archiver_parser_internal_filename_idx(const char *filename);
|
||||||
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");
|
||||||
// Permission to use, copy, modify, and/or distribute this software for any
|
* you may not use this file except in compliance with the License.
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
* You may obtain a copy of the License at
|
||||||
// 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
|
*
|
||||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
* See the License for the specific language governing permissions and
|
||||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
* limitations under the License.
|
||||||
// PERFORMANCE OF THIS SOFTWARE.
|
*
|
||||||
//
|
* `platforms.h` is the header that determines what platform this program is
|
||||||
// `platforms.h` is the header that determines what platform this program is
|
* compiled for.
|
||||||
// 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");
|
||||||
// Permission to use, copy, modify, and/or distribute this software for any
|
* you may not use this file except in compliance with the License.
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
* You may obtain a copy of the License at
|
||||||
// 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
|
*
|
||||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
* See the License for the specific language governing permissions and
|
||||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
* limitations under the License.
|
||||||
// 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,55 +44,38 @@ 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 =
|
unsigned int idx = simple_archiver_parser_internal_filename_idx("test");
|
||||||
simple_archiver_parser_internal_get_first_non_current_idx("test");
|
|
||||||
CHECK_TRUE(idx == 0);
|
CHECK_TRUE(idx == 0);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_get_first_non_current_idx("./test");
|
idx = simple_archiver_parser_internal_filename_idx("./test");
|
||||||
CHECK_TRUE(idx == 2);
|
CHECK_TRUE(idx == 2);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_get_first_non_current_idx("././test");
|
idx = simple_archiver_parser_internal_filename_idx("././test");
|
||||||
CHECK_TRUE(idx == 4);
|
CHECK_TRUE(idx == 4);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_get_first_non_current_idx(
|
idx = simple_archiver_parser_internal_filename_idx("././//././//./test");
|
||||||
"././//././//./test");
|
|
||||||
CHECK_TRUE(idx == 14);
|
CHECK_TRUE(idx == 14);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_get_first_non_current_idx(
|
idx = simple_archiver_parser_internal_filename_idx("/././//././//./test");
|
||||||
"/././//././//./test");
|
|
||||||
CHECK_TRUE(idx == 0);
|
CHECK_TRUE(idx == 0);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_get_first_non_current_idx(
|
idx = simple_archiver_parser_internal_filename_idx(".derp/.//././//./test");
|
||||||
".derp/.//././//./test");
|
|
||||||
CHECK_TRUE(idx == 0);
|
CHECK_TRUE(idx == 0);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_get_first_non_current_idx(
|
idx = simple_archiver_parser_internal_filename_idx("././/.derp/.///./test");
|
||||||
"././/.derp/.///./test");
|
|
||||||
CHECK_TRUE(idx == 5);
|
CHECK_TRUE(idx == 5);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_get_first_non_current_idx(
|
idx = simple_archiver_parser_internal_filename_idx("././/.//.//./");
|
||||||
"././/.//.//./");
|
|
||||||
CHECK_TRUE(idx == 11);
|
CHECK_TRUE(idx == 11);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_get_first_non_current_idx(
|
idx = simple_archiver_parser_internal_filename_idx("././/.//.//.");
|
||||||
"././/.//.//.");
|
|
||||||
CHECK_TRUE(idx == 11);
|
CHECK_TRUE(idx == 11);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_get_first_non_current_idx(
|
idx = simple_archiver_parser_internal_filename_idx("././/.//.//");
|
||||||
"././/.//.//");
|
|
||||||
CHECK_TRUE(idx == 8);
|
CHECK_TRUE(idx == 8);
|
||||||
|
|
||||||
SDArchiverParsed parsed = simple_archiver_create_parsed();
|
SDArchiverParsed parsed = simple_archiver_create_parsed();
|
||||||
|
@ -131,7 +114,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) {
|
||||||
uint16_t u16 = 0x0102;
|
unsigned short 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);
|
||||||
|
@ -141,7 +124,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);
|
||||||
|
|
||||||
uint32_t u32 = 0x01020304;
|
unsigned int 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);
|
||||||
|
@ -157,7 +140,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);
|
||||||
|
|
||||||
uint64_t u64 = 0x010203040a0b0c0d;
|
unsigned long long 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);
|
||||||
|
@ -187,57 +170,6 @@ 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