forked from vieter-v/libvieter
Compare commits
33 Commits
efbd9eaef9
...
9452fea2ab
Author | SHA1 | Date |
---|---|---|
GreekStapler | 9452fea2ab | |
GreekStapler | 10eb08b8e4 | |
GreekStapler | d1a8ba7737 | |
GreekStapler | 2ce7a819a9 | |
GreekStapler | 2d6ac2ac19 | |
GreekStapler | 6d731d788c | |
GreekStapler | a60c923547 | |
GreekStapler | 276fa99e4b | |
Jef Roosens | 379a05a7b6 | |
Jef Roosens | 167611e6fa | |
Jef Roosens | 5b2ce6acaa | |
Jef Roosens | d77b3e4fee | |
Jef Roosens | ab418e57b3 | |
Jef Roosens | a6bdd39776 | |
Jef Roosens | 05b96d1fd6 | |
Jef Roosens | 3ec2e76af9 | |
Jef Roosens | dc557f57ab | |
Jef Roosens | 63100c5b99 | |
Jef Roosens | 6845e67cb6 | |
Jef Roosens | 95d8c9972b | |
Jef Roosens | 09c488aa0f | |
Jef Roosens | 6cf4eaaf0b | |
Jef Roosens | 3c8c33b47a | |
Jef Roosens | c1ad26cf0c | |
Jef Roosens | 16b78b8431 | |
Jef Roosens | 0c673a2751 | |
Jef Roosens | d11d074960 | |
Jef Roosens | 13a63d548c | |
Jef Roosens | 8609769389 | |
Jef Roosens | 2cc974accc | |
Jef Roosens | ef625ed14e | |
Jef Roosens | 6823050c2f | |
Jef Roosens | 050e99b413 |
|
@ -0,0 +1,16 @@
|
|||
variables:
|
||||
&image 'git.rustybever.be/chewing_bever/c-devop:alpine3.17'
|
||||
|
||||
branches:
|
||||
exclude: [ main ]
|
||||
platform: linux/amd64
|
||||
|
||||
pipeline:
|
||||
lint:
|
||||
image: *image
|
||||
pull: true
|
||||
commands:
|
||||
- make lint
|
||||
- make objs CFLAGS='-Werror -fsyntax-only'
|
||||
when:
|
||||
event: [push, pull_request]
|
|
@ -0,0 +1,20 @@
|
|||
variables:
|
||||
&image 'git.rustybever.be/chewing_bever/c-devop:alpine3.17'
|
||||
|
||||
branches:
|
||||
exclude: [ main ]
|
||||
platform: linux/amd64
|
||||
|
||||
depends_on:
|
||||
- test
|
||||
|
||||
pipeline:
|
||||
test:
|
||||
image: *image
|
||||
pull: true
|
||||
commands:
|
||||
- make test-mem
|
||||
- make clean
|
||||
- make test-mem CFLAGS='-O3 -Werror -Wall'
|
||||
when:
|
||||
event: [push, pull_request]
|
|
@ -11,26 +11,12 @@ branches:
|
|||
platform: ${PLATFORM}
|
||||
|
||||
pipeline:
|
||||
lint:
|
||||
build-and-test:
|
||||
image: *image
|
||||
pull: true
|
||||
commands:
|
||||
- make lint
|
||||
when:
|
||||
event: [push, pull_request]
|
||||
|
||||
build:
|
||||
image: *image
|
||||
commands:
|
||||
- make
|
||||
- make clean
|
||||
- CFLAGS='-O3' make
|
||||
when:
|
||||
event: [push, pull_request]
|
||||
|
||||
test:
|
||||
image: *image
|
||||
commands:
|
||||
- make test
|
||||
- make clean
|
||||
- make test CFLAGS='-O3 -Werror -Wall'
|
||||
when:
|
||||
event: [push, pull_request]
|
48
Makefile
48
Makefile
|
@ -8,6 +8,8 @@ SRC_DIR ?= src
|
|||
TEST_DIR ?= test
|
||||
INC_DIRS ?= include
|
||||
|
||||
LIB := $(BUILD_DIR)/$(LIB_FILENAME)
|
||||
|
||||
SRCS != find '$(SRC_DIR)' -iname '*.c'
|
||||
SRCS_H != find $(INC_DIRS) -iname '*.h'
|
||||
SRCS_TEST != find '$(TEST_DIR)' -iname '*.c'
|
||||
|
@ -17,6 +19,8 @@ OBJS_TEST := $(SRCS_TEST:%=$(BUILD_DIR)/%.o)
|
|||
DEPS := $(SRCS:%=$(BUILD_DIR)/%.d) $(SRCS_TEST:%=$(BUILD_DIR)/%.d)
|
||||
|
||||
BINS_TEST := $(OBJS_TEST:%.c.o=%)
|
||||
TARGETS_TEST := $(BINS_TEST:%=test-%)
|
||||
TARGETS_MEM_TEST := $(BINS_TEST:%=test-mem-%)
|
||||
|
||||
INC_FLAGS := $(addprefix -I,$(INC_DIRS))
|
||||
|
||||
|
@ -25,42 +29,66 @@ INC_FLAGS := $(addprefix -I,$(INC_DIRS))
|
|||
# object file is also recompiled if only a header is changed.
|
||||
# -MP: generate a dummy target for every header file (according to the docs it
|
||||
# prevents some errors when removing header files)
|
||||
CFLAGS ?= -MMD -MP -Wall -Werror -Wextra
|
||||
CFLAGS += $(INC_FLAGS)
|
||||
CFLAGS ?= -MMD -MP -g
|
||||
VIETERCFLAGS := $(INC_FLAGS) $(CFLAGS) -Wall -Wextra
|
||||
|
||||
.PHONY: all
|
||||
all: vieter
|
||||
|
||||
|
||||
# =====COMPILATION=====
|
||||
# Utility used by the CI to lint
|
||||
.PHONY: objs
|
||||
objs: $(OBJS)
|
||||
|
||||
.PHONY: vieter
|
||||
vieter: $(BUILD_DIR)/$(LIB_FILENAME)
|
||||
vieter: $(LIB)
|
||||
$(BUILD_DIR)/$(LIB_FILENAME): $(OBJS)
|
||||
ar -rcs $@ $(OBJS)
|
||||
|
||||
$(BUILD_DIR)/$(SRC_DIR)/%.c.o: $(SRC_DIR)/%.c
|
||||
mkdir -p $(dir $@)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
$(CC) $(VIETERCFLAGS) -c $< -o $@
|
||||
|
||||
|
||||
# =====TESTING=====
|
||||
.PHONY: test
|
||||
test: build-test
|
||||
@ $(foreach bin,$(BINS_TEST),./$(bin);)
|
||||
test: $(TARGETS_TEST)
|
||||
|
||||
.PHONY: test-mem
|
||||
test-mem: $(TARGETS_MEM_TEST)
|
||||
|
||||
.PHONY: $(TARGETS_TEST)
|
||||
$(TARGETS_TEST): test-%: %
|
||||
./$^
|
||||
|
||||
.PHONY: $(TARGETS_MEM_TEST)
|
||||
$(TARGETS_MEM_TEST): test-mem-%: %
|
||||
valgrind --tool=memcheck --error-exitcode=1 --track-origins=yes --leak-check=full ./$^
|
||||
|
||||
.PHONY: build-test
|
||||
build-test: $(BINS_TEST)
|
||||
|
||||
# For simplicity, we link every object file to each of the test files. This
|
||||
# might be changed later if this starts to become too slow.
|
||||
<<<<<<< HEAD
|
||||
$(BINS_TEST): %: %.c.o $(LIB)
|
||||
$(CC) \
|
||||
$^ -o $@
|
||||
=======
|
||||
$(BINS_TEST): %: %.c.o $(OBJS)
|
||||
$(CC) $^ -o $@
|
||||
$(CC) $^ -larchive -o $@
|
||||
>>>>>>> c94ab92 (refactor: Add libarchive link to test compilation area of the Makefile. Created test units with xcursor-dmz as test package.)
|
||||
|
||||
# Each test includes the test directory, which contains the acutest header file
|
||||
# Along with the include directory, each test includes $(TEST_DIR) (which
|
||||
# contains the acutest.h header file), and the src directory of the module it's
|
||||
# testing. This allows tests to access internal methods, which aren't publicly
|
||||
# exposed.
|
||||
$(BUILD_DIR)/$(TEST_DIR)/%.c.o: $(TEST_DIR)/%.c
|
||||
mkdir -p $(dir $@)
|
||||
$(CC) $(CFLAGS) -I$(TEST_DIR) -c $< -o $@
|
||||
|
||||
$(CC) $(VIETERCFLAGS) -I$(TEST_DIR) \
|
||||
-I$(dir $(@:$(BUILD_DIR)/$(TEST_DIR)/%=$(SRC_DIR)/%)) \
|
||||
-c $< -o $@
|
||||
|
||||
# =====MAINTENANCE=====
|
||||
.PHONY: lint
|
||||
|
|
41
README.md
41
README.md
|
@ -1,15 +1,12 @@
|
|||
# libvieter
|
||||
|
||||
This library powers part of Vieter, most noteably the sections that can easily
|
||||
This library powers part of Vieter, most notably the sections that can easily
|
||||
be implemented in C (or just parts I want to implement in C because it's fun).
|
||||
|
||||
The goal of this library is to be completely self-contained, meaning any
|
||||
required data structures have to be implemented as well. It can only depend on
|
||||
the C standard libraries.
|
||||
The goal of this library is to be as self-contained as possible; data
|
||||
structures should be implemented manually if possible.
|
||||
|
||||
Currently it contains the following:
|
||||
|
||||
* Cron expression parser & next time calculator
|
||||
See the [source code](src) for the list of modules.
|
||||
|
||||
## Development
|
||||
|
||||
|
@ -18,13 +15,41 @@ Currently it contains the following:
|
|||
Everything is handled by the provided Makefile. To compile the static library,
|
||||
simply run `make`.
|
||||
|
||||
### Project structure
|
||||
|
||||
Each module has its own subdirectory inside `src`, e.g. `src/cron`. This
|
||||
directory contains the actual implementation of a module, along with any
|
||||
internally used header files. Each internal function should be defined in a
|
||||
header file, as to make testing these possible.
|
||||
|
||||
Each module should also have its own header file inside the `include`
|
||||
directory. This header file defines the public API that the library exposes for
|
||||
this specific module.
|
||||
|
||||
Any code in a module may only import internal headers from that module, along
|
||||
with any of the public API header files. Modules should not depend on each
|
||||
other's internal implementationns.
|
||||
|
||||
Each module should contain a README describing its contents.
|
||||
|
||||
All file names, function names... (even internals) should follow snake case
|
||||
convention and have a prefix unique to that module, starting with `vieter_`.
|
||||
For example, the `cron` modules uses the `vieter_cron_` prefix for everything.
|
||||
|
||||
Header files should only import what they explicitely need. If some function is
|
||||
only used in a .c file, the import should be placed in the .c file instead.
|
||||
|
||||
### Testing
|
||||
|
||||
This library uses [Acutest](https://github.com/mity/acutest) for its tests.
|
||||
Tests should be placed in the `test` subdirectory, further divided into
|
||||
directories that correspond those in `src`. Test files should begin with
|
||||
directories that correspond to those in `src`. Test files should begin with
|
||||
`test_`, and their format should follow the expected format for Acutest.
|
||||
|
||||
Each `test_` is compiled separately into a binary, linked with libvieter. A
|
||||
test file can import any of the public API header files, along with any header
|
||||
files defined in its respective module. This allows testing internal functions.
|
||||
|
||||
To run the tests, simply run `make test`. If you wish to only run a specific
|
||||
test binary, you can find them in `build/test`.
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef VIETER_DYNARRAY
|
||||
#define VIETER_DYNARRAY
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct dyn_array DynArray;
|
||||
struct dyn_array {
|
||||
char **array;
|
||||
size_t capacity;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
DynArray *dynarray_init(size_t initial_capacity);
|
||||
void dynarray_add(DynArray *da, const char * s);
|
||||
void dynarray_free(DynArray *da);
|
||||
|
||||
/**
|
||||
* Convert a DynArray into an array by freeing all its surrounding components
|
||||
* and returning the underlying array pointer.
|
||||
*/
|
||||
char **dynarray_convert(DynArray *da);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef VIETER_PACKAGE
|
||||
#define VIETER_PACKAGE
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "archive.h"
|
||||
#include "archive_entry.h"
|
||||
|
||||
#include "package_info.h"
|
||||
#include "dynarray.h"
|
||||
|
||||
typedef struct pkg {
|
||||
char *path;
|
||||
PkgInfo *info;
|
||||
DynArray *files;
|
||||
int compression;
|
||||
} Pkg;
|
||||
|
||||
Pkg *package_read_archive(const char *pkg_path);
|
||||
void package_free(Pkg ** ptp);
|
||||
char *package_to_description(Pkg *pkg);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef VIETER_PACKAGE_INFO
|
||||
#define VIETER_PACKAGE_INFO
|
||||
|
||||
#define FREE_STRING(sp) if (sp != NULL) free(sp)
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "dynarray.h"
|
||||
|
||||
typedef struct pkg_info {
|
||||
char *name;
|
||||
char *base;
|
||||
char *version;
|
||||
char *description;
|
||||
int64_t size;
|
||||
int64_t csize;
|
||||
char *url;
|
||||
char *arch;
|
||||
int64_t build_date;
|
||||
char *packager;
|
||||
char *pgpsig;
|
||||
int64_t pgpsigsize;
|
||||
|
||||
DynArray *groups;
|
||||
DynArray *licenses;
|
||||
DynArray *replaces;
|
||||
DynArray *depends;
|
||||
DynArray *conflicts;
|
||||
DynArray *provides;
|
||||
DynArray *optdepends;
|
||||
DynArray *makedepends;
|
||||
DynArray *checkdepends;
|
||||
} PkgInfo;
|
||||
|
||||
PkgInfo *package_info_init();
|
||||
void package_info_parse(PkgInfo *pkg_info, char *pkg_info_str);
|
||||
void package_info_free(PkgInfo *pkg_info);
|
||||
|
||||
#endif
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef VIETER_CRON
|
||||
#define VIETER_CRON
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -35,18 +34,38 @@ typedef struct vieter_cron_simple_time {
|
|||
int minute;
|
||||
} vieter_cron_simple_time;
|
||||
|
||||
vieter_cron_expression *ce_init();
|
||||
/*
|
||||
* Allocate and initialize a new empty cron expression.
|
||||
*/
|
||||
vieter_cron_expression *vieter_cron_expr_init();
|
||||
|
||||
/*
|
||||
* Deallocate a cron expression.
|
||||
*/
|
||||
void vieter_cron_expr_free(vieter_cron_expression *ce);
|
||||
|
||||
/*
|
||||
* Given a cron expression and a reference time, calculate the next time after
|
||||
* the reference time that this expression matches.
|
||||
*/
|
||||
void vieter_cron_expr_next(vieter_cron_simple_time *out,
|
||||
vieter_cron_expression *ce,
|
||||
vieter_cron_simple_time *ref);
|
||||
|
||||
/*
|
||||
* Convencience wrapper around vieter_cron_expr_next that uses the current time
|
||||
* as the reference time.
|
||||
*/
|
||||
void vieter_cron_expr_next_from_now(vieter_cron_simple_time *out,
|
||||
vieter_cron_expression *ce);
|
||||
|
||||
enum vieter_cron_parse_error vieter_cron_expr_parse(vieter_cron_expression *out,
|
||||
const char *expression);
|
||||
/*
|
||||
* Try to parse a string into a cron expression. Note that the cron expression
|
||||
* is updated in-place, meaning it can contain invalid information if the
|
||||
* function returns an error. The cron expression should only be used if the
|
||||
* function succeeded.
|
||||
*/
|
||||
vieter_cron_parse_error vieter_cron_expr_parse(vieter_cron_expression *out,
|
||||
const char *expression);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
#ifndef VIETER_HEAP
|
||||
#define VIETER_HEAP
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct vieter_heap vieter_heap;
|
||||
|
||||
typedef enum vieter_heap_error {
|
||||
vieter_heap_ok = 0,
|
||||
vieter_heap_empty = 1
|
||||
} vieter_heap_error;
|
||||
|
||||
/*
|
||||
* Allocate and initialize an empty heap.
|
||||
*/
|
||||
vieter_heap *vieter_heap_init();
|
||||
|
||||
/*
|
||||
* Deallocate a heap.
|
||||
*/
|
||||
void vieter_heap_free(vieter_heap *heap);
|
||||
|
||||
/*
|
||||
* Return how many elements are currently in the heap.
|
||||
*/
|
||||
uint64_t vieter_heap_size(vieter_heap *heap);
|
||||
|
||||
/*
|
||||
* Insert a new value into the heap.
|
||||
*/
|
||||
vieter_heap_error vieter_heap_insert(vieter_heap *heap, uint64_t key,
|
||||
void *data);
|
||||
|
||||
/*
|
||||
* Remove the smallest element from the heap.
|
||||
*/
|
||||
vieter_heap_error vieter_heap_pop(void **out, vieter_heap *heap);
|
||||
|
||||
/*
|
||||
* Get the smallest element in the heap without removing it.
|
||||
*/
|
||||
vieter_heap_error vieter_heap_peek(void **out, vieter_heap *heap);
|
||||
|
||||
/*
|
||||
* Acquire a read lock on the heap. Return value is the result of
|
||||
* pthread_rwlock_rdlock.
|
||||
*/
|
||||
int vieter_heap_rlock(vieter_heap *heap);
|
||||
|
||||
/*
|
||||
* Acquire a write lock on the heap. Return value is the result of
|
||||
* pthread_rwlock_wrlock.
|
||||
*/
|
||||
int vieter_heap_wlock(vieter_heap *heap);
|
||||
|
||||
/*
|
||||
* Unlock the lock after having acquired it. Return value is the result of
|
||||
* pthread_rwlock_unlock.
|
||||
*/
|
||||
int vieter_heap_unlock(vieter_heap *heap);
|
||||
|
||||
#endif
|
|
@ -1,4 +1,8 @@
|
|||
#include "vieter_cron.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
// This prefix is needed to properly compile
|
||||
const uint8_t parse_month_days[] = {31, 28, 31, 30, 31, 30,
|
|
@ -0,0 +1,33 @@
|
|||
This min-heap implementation is a pretty standard binomial heap.
|
||||
|
||||
## Representation in memory
|
||||
|
||||
A heap consists of one or more binomial trees, each with a different order `k`
|
||||
and `2^k` total nodes. This heap can contain `2^64 - 1` elements at most, which
|
||||
is far more than your memory can contain, but it's still fun to mention.
|
||||
|
||||
A tree does not have its own memory structure; a node that's the root of a
|
||||
binomial tree is simply called the tree.
|
||||
|
||||
Each node has the following layout:
|
||||
|
||||
```c
|
||||
typedef struct vieter_heap_node {
|
||||
uint64_t key;
|
||||
void *data;
|
||||
struct vieter_heap_node *largest_order;
|
||||
union {
|
||||
struct vieter_heap_node *next_tree;
|
||||
struct vieter_heap_node *next_largest_order;
|
||||
} ptr;
|
||||
uint8_t order;
|
||||
} vieter_heap_node;
|
||||
```
|
||||
|
||||
Each node has a pointer to its child with the largest order (if the node's
|
||||
order is `0`, this pointer will be NULL). Each non-root node has a pointer to
|
||||
its sibling with the next-highest order. These pointers allow the children of a
|
||||
binomial tree to be recombined into a new tree, once their root has been
|
||||
pop'ed.
|
||||
|
||||
Roots point to the binomial tree in the heap with the next largest order.
|
|
@ -0,0 +1,96 @@
|
|||
#include "vieter_heap_internal.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
vieter_heap *vieter_heap_init() {
|
||||
vieter_heap *heap = calloc(1, sizeof(vieter_heap));
|
||||
|
||||
pthread_rwlock_init(&heap->lock, NULL);
|
||||
|
||||
return heap;
|
||||
}
|
||||
|
||||
uint64_t vieter_heap_size(vieter_heap *heap) {
|
||||
uint64_t size = 0;
|
||||
vieter_heap_node *tree = heap->tree;
|
||||
|
||||
while (tree != NULL) {
|
||||
size |= (uint64_t)1 << tree->order;
|
||||
|
||||
tree = tree->ptr.next_tree;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void vieter_heap_free(vieter_heap *heap) {
|
||||
vieter_heap_node *tree = heap->tree;
|
||||
vieter_heap_node *next;
|
||||
|
||||
while (tree != NULL) {
|
||||
next = tree->ptr.next_tree;
|
||||
vieter_heap_tree_free(tree);
|
||||
tree = next;
|
||||
}
|
||||
|
||||
free(heap);
|
||||
}
|
||||
|
||||
vieter_heap_error vieter_heap_insert(vieter_heap *heap, uint64_t key,
|
||||
void *data) {
|
||||
vieter_heap_node *new_tree = vieter_heap_node_init();
|
||||
new_tree->key = key;
|
||||
new_tree->data = data;
|
||||
new_tree->order = 0;
|
||||
|
||||
if (heap->tree == NULL) {
|
||||
heap->tree = new_tree;
|
||||
} else {
|
||||
heap->tree = vieter_heap_tree_merge(heap->tree, new_tree);
|
||||
}
|
||||
|
||||
return vieter_heap_ok;
|
||||
}
|
||||
|
||||
vieter_heap_error vieter_heap_pop(void **out, vieter_heap *heap) {
|
||||
if (heap->tree == NULL) {
|
||||
return vieter_heap_empty;
|
||||
}
|
||||
|
||||
heap->tree = vieter_heap_tree_pop(out, heap->tree);
|
||||
|
||||
return vieter_heap_ok;
|
||||
}
|
||||
|
||||
vieter_heap_error vieter_heap_peek(void **out, vieter_heap *heap) {
|
||||
if (heap->tree == NULL) {
|
||||
return vieter_heap_empty;
|
||||
}
|
||||
|
||||
vieter_heap_node *tree = heap->tree;
|
||||
uint64_t smallest_key = tree->key;
|
||||
*out = tree->data;
|
||||
|
||||
while (tree->ptr.next_tree != NULL) {
|
||||
tree = tree->ptr.next_tree;
|
||||
|
||||
if (tree->key < smallest_key) {
|
||||
smallest_key = tree->key;
|
||||
*out = tree->data;
|
||||
}
|
||||
}
|
||||
|
||||
return vieter_heap_ok;
|
||||
}
|
||||
|
||||
int vieter_heap_rlock(vieter_heap *heap) {
|
||||
return pthread_rwlock_rdlock(&heap->lock);
|
||||
}
|
||||
|
||||
int vieter_heap_wlock(vieter_heap *heap) {
|
||||
return pthread_rwlock_wrlock(&heap->lock);
|
||||
}
|
||||
|
||||
int vieter_heap_unlock(vieter_heap *heap) {
|
||||
return pthread_rwlock_unlock(&heap->lock);
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#include "vieter_heap.h"
|
||||
#include "vieter_heap_tree.h"
|
||||
#include <pthread.h>
|
||||
|
||||
struct vieter_heap {
|
||||
vieter_heap_node *tree;
|
||||
pthread_rwlock_t lock;
|
||||
};
|
|
@ -0,0 +1,192 @@
|
|||
#include "vieter_heap_tree.h"
|
||||
|
||||
vieter_heap_node *vieter_heap_node_init() {
|
||||
return calloc(1, sizeof(vieter_heap_node));
|
||||
}
|
||||
|
||||
void vieter_heap_node_free(vieter_heap_node *node) { free(node); }
|
||||
|
||||
void vieter_heap_tree_free(vieter_heap_node *root) {
|
||||
if (root->order == 0) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
uint64_t size = 1;
|
||||
vieter_heap_node **stack =
|
||||
malloc(((uint64_t)1 << root->order) * sizeof(vieter_heap_node *));
|
||||
stack[0] = root->largest_order;
|
||||
|
||||
vieter_heap_node *node;
|
||||
|
||||
while (size > 0) {
|
||||
node = stack[size - 1];
|
||||
size--;
|
||||
|
||||
if (node->largest_order != NULL) {
|
||||
stack[size] = node->largest_order;
|
||||
size++;
|
||||
}
|
||||
|
||||
if (node->ptr.next_largest_order != NULL) {
|
||||
stack[size] = node->ptr.next_largest_order;
|
||||
size++;
|
||||
}
|
||||
|
||||
vieter_heap_node_free(node);
|
||||
}
|
||||
|
||||
free(stack);
|
||||
|
||||
end:
|
||||
vieter_heap_node_free(root);
|
||||
}
|
||||
|
||||
vieter_heap_node *vieter_heap_tree_merge_same_order(vieter_heap_node *root_a,
|
||||
vieter_heap_node *root_b) {
|
||||
vieter_heap_node *root, *child;
|
||||
|
||||
if (root_a->key <= root_b->key) {
|
||||
root = root_a;
|
||||
child = root_b;
|
||||
} else {
|
||||
root = root_b;
|
||||
child = root_a;
|
||||
}
|
||||
|
||||
child->ptr.next_largest_order = root->largest_order;
|
||||
root->largest_order = child;
|
||||
|
||||
root->order++;
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
vieter_heap_node *vieter_heap_tree_merge(vieter_heap_node *target_tree,
|
||||
vieter_heap_node *other_tree) {
|
||||
vieter_heap_node *out = target_tree;
|
||||
|
||||
vieter_heap_node *next_other_tree, *next_target_tree;
|
||||
vieter_heap_node *previous_target_tree = NULL;
|
||||
|
||||
while (target_tree != NULL && other_tree != NULL) {
|
||||
if (target_tree->order == other_tree->order) {
|
||||
next_other_tree = other_tree->ptr.next_tree;
|
||||
next_target_tree = target_tree->ptr.next_tree;
|
||||
|
||||
target_tree = vieter_heap_tree_merge_same_order(target_tree, other_tree);
|
||||
|
||||
target_tree->ptr.next_tree = next_target_tree;
|
||||
|
||||
// If this merge produces a binomial tree whose size is already in
|
||||
// target, it will be the next target. Therefore, we can merge target's
|
||||
// trees until we no longer have a duplicate depth.
|
||||
while (next_target_tree != NULL &&
|
||||
next_target_tree->order == target_tree->order) {
|
||||
next_target_tree = next_target_tree->ptr.next_tree;
|
||||
target_tree = vieter_heap_tree_merge_same_order(
|
||||
target_tree, target_tree->ptr.next_tree);
|
||||
target_tree->ptr.next_tree = next_target_tree;
|
||||
}
|
||||
|
||||
if (previous_target_tree != NULL) {
|
||||
previous_target_tree->ptr.next_tree = target_tree;
|
||||
} else {
|
||||
out = target_tree;
|
||||
}
|
||||
|
||||
other_tree = next_other_tree;
|
||||
} else if (target_tree->order > other_tree->order) {
|
||||
next_other_tree = other_tree->ptr.next_tree;
|
||||
|
||||
if (previous_target_tree == NULL) {
|
||||
previous_target_tree = other_tree;
|
||||
out = other_tree;
|
||||
} else {
|
||||
previous_target_tree->ptr.next_tree = other_tree;
|
||||
|
||||
// This single missing line right here broke this entire function for
|
||||
// nearly a week.
|
||||
previous_target_tree = other_tree;
|
||||
}
|
||||
|
||||
other_tree->ptr.next_tree = target_tree;
|
||||
other_tree = next_other_tree;
|
||||
} else {
|
||||
if (previous_target_tree == NULL) {
|
||||
out = target_tree;
|
||||
}
|
||||
|
||||
previous_target_tree = target_tree;
|
||||
target_tree = target_tree->ptr.next_tree;
|
||||
}
|
||||
}
|
||||
|
||||
// Append final part of tree to target
|
||||
if (target_tree == NULL) {
|
||||
previous_target_tree->ptr.next_tree = other_tree;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
vieter_heap_node *vieter_heap_tree_pop(void **out, vieter_heap_node *tree) {
|
||||
vieter_heap_node *tree_before_smallest = NULL;
|
||||
vieter_heap_node *previous_tree = NULL;
|
||||
vieter_heap_node *original_root = tree;
|
||||
|
||||
uint64_t smallest_key = tree->key;
|
||||
|
||||
while (tree->ptr.next_tree != NULL) {
|
||||
previous_tree = tree;
|
||||
tree = tree->ptr.next_tree;
|
||||
|
||||
if (tree->key < smallest_key) {
|
||||
smallest_key = tree->key;
|
||||
tree_before_smallest = previous_tree;
|
||||
}
|
||||
}
|
||||
|
||||
vieter_heap_node *tree_to_pop;
|
||||
|
||||
if (tree_before_smallest != NULL) {
|
||||
tree_to_pop = tree_before_smallest->ptr.next_tree;
|
||||
tree_before_smallest->ptr.next_tree = tree_to_pop->ptr.next_tree;
|
||||
} else {
|
||||
tree_to_pop = original_root;
|
||||
original_root = original_root->ptr.next_tree;
|
||||
}
|
||||
|
||||
*out = tree_to_pop->data;
|
||||
|
||||
if (tree_to_pop->order == 0) {
|
||||
vieter_heap_tree_free(tree_to_pop);
|
||||
|
||||
return original_root;
|
||||
}
|
||||
|
||||
// Each child has a pointer to its sibling with the next largest order. If we
|
||||
// want to convert this list of children into their own tree, these pointers
|
||||
// have to be reversed.
|
||||
previous_tree = tree_to_pop->largest_order;
|
||||
vieter_heap_node_free(tree_to_pop);
|
||||
|
||||
tree = previous_tree->ptr.next_largest_order;
|
||||
previous_tree->ptr.next_tree = NULL;
|
||||
|
||||
vieter_heap_node *next_tree;
|
||||
|
||||
while (tree != NULL) {
|
||||
next_tree = tree->ptr.next_largest_order;
|
||||
tree->ptr.next_tree = previous_tree;
|
||||
|
||||
previous_tree = tree;
|
||||
tree = next_tree;
|
||||
}
|
||||
|
||||
// original_root is zero if the heap only contained a single tree.
|
||||
if (original_root != NULL) {
|
||||
return vieter_heap_tree_merge(original_root, previous_tree);
|
||||
} else {
|
||||
return previous_tree;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
#ifndef VIETER_HEAP_TREE
|
||||
#define VIETER_HEAP_TREE
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct vieter_heap_node {
|
||||
uint64_t key;
|
||||
void *data;
|
||||
struct vieter_heap_node *largest_order;
|
||||
union {
|
||||
// Roots point to next tree in the heap, other nodes point to their first
|
||||
// neighbour.
|
||||
struct vieter_heap_node *next_tree;
|
||||
struct vieter_heap_node *next_largest_order;
|
||||
} ptr;
|
||||
uint8_t order;
|
||||
} vieter_heap_node;
|
||||
|
||||
/*
|
||||
* Allocate and initialize a heap node object.
|
||||
*/
|
||||
vieter_heap_node *vieter_heap_node_init();
|
||||
|
||||
/*
|
||||
* Deallocate a node object.
|
||||
*/
|
||||
void vieter_heap_node_free(vieter_heap_node *node);
|
||||
|
||||
/*
|
||||
* Deallocate a node's entire structure.
|
||||
*/
|
||||
void vieter_heap_tree_free(vieter_heap_node *root);
|
||||
|
||||
/*
|
||||
* Given the roots of the smallest trees in two heaps, merge them into a single
|
||||
* large heap.
|
||||
*/
|
||||
vieter_heap_node *vieter_heap_tree_merge(vieter_heap_node *root_a, vieter_heap_node *root_b);
|
||||
|
||||
/*
|
||||
* Given the roots of two trees of the same order, merge them into a heap of one
|
||||
* order larger.
|
||||
*/
|
||||
vieter_heap_node *vieter_heap_tree_merge_same_order(vieter_heap_node *root_a,
|
||||
vieter_heap_node *root_b);
|
||||
|
||||
/*
|
||||
* Remove the smallest element from the given heap.
|
||||
*/
|
||||
vieter_heap_node *vieter_heap_tree_pop(void **out, vieter_heap_node *root);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,50 @@
|
|||
#include "dynarray.h"
|
||||
|
||||
DynArray *dynarray_init(size_t initial_capacity) {
|
||||
DynArray *da = malloc(sizeof(DynArray));
|
||||
da->size = 0;
|
||||
da->capacity = initial_capacity;
|
||||
|
||||
return da;
|
||||
}
|
||||
|
||||
void dynarray_add(DynArray *da, const char *s) {
|
||||
// An empty dynarray does not have an allocated internal array yet
|
||||
if (da->size == 0) {
|
||||
da->array = malloc(sizeof(char*) * da->capacity);
|
||||
}
|
||||
// Double array size if it's full
|
||||
else if (da->size == da->capacity) {
|
||||
// if the realloc fails, access to memory in da->array is lost
|
||||
da->array = realloc(da->array, sizeof(char*) * da->capacity * 2);
|
||||
da->capacity *= 2;
|
||||
}
|
||||
|
||||
da->array[da->size] = strdup(s);
|
||||
da->size++;
|
||||
}
|
||||
|
||||
void dynarray_free(DynArray *da) {
|
||||
if (da == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (da->array != NULL) {
|
||||
for (size_t i = 0; i < da->size; i++) {
|
||||
free(da->array[i]);
|
||||
}
|
||||
|
||||
free(da->array);
|
||||
}
|
||||
|
||||
free(da);
|
||||
}
|
||||
|
||||
char **dynarray_convert(DynArray *da) {
|
||||
char **array = da->array;
|
||||
|
||||
da->array = NULL;
|
||||
dynarray_free(da);
|
||||
|
||||
return array;
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
#include "package.h"
|
||||
|
||||
#define SMALL_BUFF_SIZE 128
|
||||
|
||||
#define ADD_STRING(section, field) if (pkg_info->field != 0) { \
|
||||
snprintf(aux, SMALL_BUFF_SIZE, section, pkg_info->field); \
|
||||
if (buff_size < strlen(description) + SMALL_BUFF_SIZE + 1) { \
|
||||
description = realloc(description, buff_size * 2); \
|
||||
buff_size *= 2; \
|
||||
} \
|
||||
strcat(description, aux); \
|
||||
}
|
||||
#define ADD_ARRAY(section, field) i = 0; if (pkg_info->field != NULL) { \
|
||||
snprintf(aux, SMALL_BUFF_SIZE, section, pkg_info->field->array[i]); i++; \
|
||||
if (buff_size < strlen(description) + SMALL_BUFF_SIZE + 1) { \
|
||||
description = realloc(description, buff_size * 2); \
|
||||
buff_size *= 2; \
|
||||
} \
|
||||
strcat(description, aux); \
|
||||
while (pkg_info->field->array[i] != NULL) { \
|
||||
snprintf(aux, SMALL_BUFF_SIZE, "\n%s", pkg_info->field->array[i]); i++; \
|
||||
if (buff_size < strlen(description) + SMALL_BUFF_SIZE + 1) { \
|
||||
description = realloc(description, buff_size * 2); \
|
||||
buff_size *= 2; \
|
||||
} \
|
||||
strcat(description, aux); \
|
||||
} \
|
||||
}
|
||||
|
||||
static char *ignored_names[5] = {
|
||||
".BUILDINFO",
|
||||
".INSTALL",
|
||||
".MTREE",
|
||||
".PKGINFO",
|
||||
".CHANGELOG"
|
||||
};
|
||||
static size_t ignored_words_len = sizeof(ignored_names) / sizeof(char *);
|
||||
|
||||
Pkg *package_init() {
|
||||
return calloc(sizeof(PkgInfo), 1);
|
||||
}
|
||||
|
||||
Pkg *package_read_archive(const char *pkg_path) {
|
||||
struct archive *a = archive_read_new();
|
||||
struct archive_entry *entry = archive_entry_new();
|
||||
|
||||
// These three are the most commonly used compression methods
|
||||
archive_read_support_filter_zstd(a);
|
||||
archive_read_support_filter_gzip(a);
|
||||
archive_read_support_filter_xz(a);
|
||||
|
||||
// Contents should always be a tarball
|
||||
archive_read_support_format_tar(a);
|
||||
|
||||
// TODO where does this 10240 come from?
|
||||
int r = archive_read_open_filename(a, pkg_path, 10240);
|
||||
|
||||
// Exit early if we weren't able to successfully open the archive for reading
|
||||
if (r != ARCHIVE_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int compression_code = archive_filter_code(a, 0);
|
||||
const char *path_name;
|
||||
|
||||
PkgInfo *pkg_info;
|
||||
DynArray *files = dynarray_init(16);
|
||||
dynarray_add(files, "%FILES%");
|
||||
|
||||
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
|
||||
path_name = archive_entry_pathname(entry);
|
||||
|
||||
bool ignore = false;
|
||||
|
||||
for (size_t i = 0; i < ignored_words_len; i++) {
|
||||
if (strcmp(path_name, ignored_names[i]) == 0) {
|
||||
ignore = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ignore) {
|
||||
dynarray_add(files, path_name);
|
||||
}
|
||||
|
||||
if (strcmp(path_name, ".PKGINFO") == 0) {
|
||||
// Read data of file into memory buffer
|
||||
int size = archive_entry_size(entry);
|
||||
char *buf = malloc(size);
|
||||
archive_read_data(a, buf, size);
|
||||
|
||||
// Parse package info string into a struct
|
||||
pkg_info = package_info_init();
|
||||
package_info_parse(pkg_info, buf);
|
||||
|
||||
free(buf);
|
||||
} else {
|
||||
archive_read_data_skip(a);
|
||||
}
|
||||
}
|
||||
|
||||
// Get size of file
|
||||
struct stat stats;
|
||||
|
||||
if (stat(pkg_path, &stats) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pkg_info->csize = stats.st_size;
|
||||
|
||||
archive_read_free(a);
|
||||
|
||||
// Create final return value
|
||||
Pkg *pkg = package_init();
|
||||
pkg->path = strdup(pkg_path);
|
||||
pkg->info = pkg_info;
|
||||
pkg->files = files;
|
||||
pkg->compression = compression_code;
|
||||
|
||||
return pkg;
|
||||
}
|
||||
|
||||
void sha256sum(Pkg *pkg, char *res) {
|
||||
char command[SMALL_BUFF_SIZE];
|
||||
snprintf(command, SMALL_BUFF_SIZE, "sha256sum %s", pkg->path);
|
||||
FILE *p = popen(command, "r");
|
||||
|
||||
fgets(res, 65, p);
|
||||
pclose(p);
|
||||
}
|
||||
|
||||
char *package_to_description(Pkg *pkg) {
|
||||
PkgInfo *pkg_info = pkg->info;
|
||||
|
||||
size_t buff_size = 1024;
|
||||
char aux[SMALL_BUFF_SIZE];
|
||||
char *description = malloc(sizeof(char) * buff_size);
|
||||
int i;
|
||||
|
||||
// special case for FILENAME
|
||||
// assuming .pkg.tar.zst; other formats are valid, this should account for that
|
||||
snprintf(aux, SMALL_BUFF_SIZE, "%%FILENAME%%\n%s-%s-%s.pkg.tar.zst", pkg_info->name, pkg_info->version,
|
||||
pkg_info->arch);
|
||||
strcat(description, aux);
|
||||
|
||||
ADD_STRING("\n\n%%NAME%%\n%s", name);
|
||||
ADD_STRING("\n\n%%BASE%%\n%s", base);
|
||||
ADD_STRING("\n\n%%VERSION%%\n%s", version);
|
||||
ADD_STRING("\n\n%%DESC%%\n%s", description);
|
||||
ADD_ARRAY("\n\n%%GROUPS%%\n%s", groups);
|
||||
ADD_STRING("\n\n%%CSIZE%%\n%ld", csize);
|
||||
ADD_STRING("\n\n%%ISIZE%%\n%ld", size);
|
||||
|
||||
char checksum[65];
|
||||
sha256sum(pkg, checksum);
|
||||
snprintf(aux, SMALL_BUFF_SIZE, "\n\n%%SHA256SUM%%\n%s", checksum);
|
||||
if (buff_size < strlen(description) + SMALL_BUFF_SIZE + 1) {
|
||||
description = realloc(description, buff_size * 2);
|
||||
buff_size *= 2;
|
||||
}
|
||||
strcat(description, aux);
|
||||
|
||||
ADD_STRING("\n\n%%URL%%\n%s", url);
|
||||
ADD_ARRAY("\n\n%%LICENSE%%\n%s", licenses);
|
||||
ADD_STRING("\n\n%%ARCH%%\n%s", arch);
|
||||
ADD_STRING("\n\n%%BUILDDATE%%\n%ld", build_date);
|
||||
ADD_STRING("\n\n%%PACKAGER%%\n%s", packager);
|
||||
ADD_ARRAY("\n\n%%REPLACES%%\n%s", replaces);
|
||||
ADD_ARRAY("\n\n%%CONFLICTS%%\n%s", conflicts);
|
||||
ADD_ARRAY("\n\n%%PROVIDES%%\n%s", provides);
|
||||
ADD_ARRAY("\n\n%%DEPENDS%%\n%s", depends);
|
||||
ADD_ARRAY("\n\n%%OPTDEPENDS%%\n%s", optdepends);
|
||||
ADD_ARRAY("\n\n%%MAKEDEPENDS%%\n%s", makedepends);
|
||||
ADD_ARRAY("\n\n%%CHECKDEPENDS%%\n%s", checkdepends);
|
||||
|
||||
snprintf(aux, SMALL_BUFF_SIZE, "\n\n");
|
||||
strcat(description, aux);
|
||||
|
||||
return description;
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
#include <stdbool.h>
|
||||
|
||||
#include "package_info.h"
|
||||
|
||||
#define PKG_INFO_STRING(key_ptr, field) if ((value_ptr = strstr(value_ptr, key_ptr)) != NULL) { \
|
||||
value_ptr += strlen(key_ptr);\
|
||||
tail_ptr = strchr(value_ptr, '\n');\
|
||||
tail_ptr[0] = '\0'; \
|
||||
pkg_info->field = strdup(value_ptr); \
|
||||
tail_ptr[0] = '\n'; \
|
||||
} value_ptr = tail_ptr;
|
||||
|
||||
#define PKG_INFO_INT(key_ptr, field) value_ptr = strstr(value_ptr, key_ptr) + strlen(key_ptr);\
|
||||
tail_ptr = strchr(value_ptr, '\n');\
|
||||
tail_ptr[0] = '\0'; \
|
||||
pkg_info->field = atoi(value_ptr); \
|
||||
tail_ptr[0] = '\n'; \
|
||||
value_ptr = tail_ptr;
|
||||
|
||||
#define PKG_INFO_ARRAY(key_ptr, field) while((value_ptr = strstr(value_ptr, key_ptr)) != NULL){ \
|
||||
value_ptr = value_ptr + strlen(key_ptr);\
|
||||
tail_ptr = strchr(value_ptr, '\n'); \
|
||||
tail_ptr[0] = '\0'; \
|
||||
if(pkg_info->field == NULL) { pkg_info->field = dynarray_init(4); } \
|
||||
dynarray_add(pkg_info->field, value_ptr); \
|
||||
tail_ptr[0] = '\n'; \
|
||||
value_ptr = tail_ptr;\
|
||||
} value_ptr = tail_ptr;
|
||||
|
||||
PkgInfo *package_info_init() {
|
||||
return calloc(1, sizeof(PkgInfo));
|
||||
}
|
||||
|
||||
void package_info_free(PkgInfo *pkg_info) {
|
||||
FREE_STRING(pkg_info->name);
|
||||
FREE_STRING(pkg_info->base);
|
||||
FREE_STRING(pkg_info->version);
|
||||
FREE_STRING(pkg_info->description);
|
||||
FREE_STRING(pkg_info->url);
|
||||
FREE_STRING(pkg_info->arch);
|
||||
FREE_STRING(pkg_info->packager);
|
||||
FREE_STRING(pkg_info->pgpsig);
|
||||
|
||||
dynarray_free(pkg_info->groups);
|
||||
dynarray_free(pkg_info->licenses);
|
||||
dynarray_free(pkg_info->replaces);
|
||||
dynarray_free(pkg_info->depends);
|
||||
dynarray_free(pkg_info->conflicts);
|
||||
dynarray_free(pkg_info->provides);
|
||||
dynarray_free(pkg_info->optdepends);
|
||||
dynarray_free(pkg_info->makedepends);
|
||||
dynarray_free(pkg_info->checkdepends);
|
||||
|
||||
free(pkg_info);
|
||||
}
|
||||
|
||||
void package_info_parse(PkgInfo *pkg_info, char *pkg_info_str) {
|
||||
char *value_ptr = pkg_info_str, *tail_ptr;
|
||||
|
||||
PKG_INFO_STRING("\npkgname = ", name);
|
||||
PKG_INFO_STRING("\npkgbase = ", base);
|
||||
PKG_INFO_STRING("\npkgver = ", version);
|
||||
PKG_INFO_STRING("\npkgdesc = ", description);
|
||||
PKG_INFO_STRING("\nurl = ", url);
|
||||
PKG_INFO_INT("\nbuilddate = ", build_date);
|
||||
PKG_INFO_STRING("\npackager = ", packager);
|
||||
PKG_INFO_INT("\nsize = ", size);
|
||||
PKG_INFO_STRING("\narch = ", arch);
|
||||
PKG_INFO_ARRAY("\nlicense = ", licenses);
|
||||
PKG_INFO_ARRAY("\nreplaces = ", replaces);
|
||||
PKG_INFO_ARRAY("\ngroup = ", groups);
|
||||
PKG_INFO_ARRAY("\nconflict = ", conflicts);
|
||||
PKG_INFO_ARRAY("\nprovides = ", provides);
|
||||
PKG_INFO_ARRAY("\ndepend = ", depends);
|
||||
PKG_INFO_ARRAY("\noptdepend = ", optdepends);
|
||||
PKG_INFO_ARRAY("\nmakedepend = ", makedepends);
|
||||
PKG_INFO_ARRAY("\ncheckdepend = ", checkdepends);
|
||||
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
#include "acutest.h"
|
||||
#include "vieter_heap_internal.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define TEST_SIZE(heap, size) \
|
||||
TEST_CHECK(vieter_heap_size(heap) == size); \
|
||||
TEST_MSG("Size: %zu, expected: %lu", vieter_heap_size(heap), (uint64_t)size)
|
||||
|
||||
void test_init() {
|
||||
vieter_heap *heap = vieter_heap_init();
|
||||
TEST_CHECK(heap != NULL);
|
||||
TEST_SIZE(heap, 0);
|
||||
vieter_heap_free(heap);
|
||||
}
|
||||
|
||||
void count_nodes(uint64_t *counter, vieter_heap_node *root) {
|
||||
(*counter)++;
|
||||
|
||||
if (root->largest_order != NULL) {
|
||||
count_nodes(counter, root->largest_order);
|
||||
}
|
||||
|
||||
// This will also traverse the various trees
|
||||
if (root->ptr.next_largest_order != NULL) {
|
||||
count_nodes(counter, root->ptr.next_largest_order);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t count_nodes_heap(vieter_heap *heap) {
|
||||
uint64_t counter = 0;
|
||||
|
||||
if (heap->tree != NULL) {
|
||||
count_nodes(&counter, heap->tree);
|
||||
}
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
void test_insert() {
|
||||
vieter_heap *heap = vieter_heap_init();
|
||||
TEST_SIZE(heap, 0);
|
||||
|
||||
void *data;
|
||||
|
||||
for (uint64_t i = 50; i > 0; i--) {
|
||||
vieter_heap_insert(heap, i, (void *)i);
|
||||
TEST_SIZE(heap, (uint64_t)51 - i);
|
||||
TEST_CHECK(count_nodes_heap(heap) == (uint64_t)51 - i);
|
||||
|
||||
data = 0;
|
||||
|
||||
TEST_CHECK(vieter_heap_peek(&data, heap) == vieter_heap_ok);
|
||||
TEST_CHECK_(data == (void *)i, "%lX == %lX", (uint64_t)data, i);
|
||||
}
|
||||
|
||||
vieter_heap_free(heap);
|
||||
}
|
||||
|
||||
void test_insert_random() {
|
||||
srand(1);
|
||||
|
||||
vieter_heap *heap = vieter_heap_init();
|
||||
TEST_SIZE(heap, 0);
|
||||
|
||||
uint64_t num = rand();
|
||||
uint64_t smallest = num;
|
||||
|
||||
void *data = NULL;
|
||||
|
||||
for (uint64_t i = 0; i < 5000; i++) {
|
||||
vieter_heap_insert(heap, num, (void *)num);
|
||||
TEST_SIZE(heap, i + 1);
|
||||
TEST_CHECK(count_nodes_heap(heap) == (uint64_t)i + 1);
|
||||
|
||||
if (num < smallest) {
|
||||
smallest = num;
|
||||
}
|
||||
|
||||
TEST_CHECK(vieter_heap_peek(&data, heap) == vieter_heap_ok);
|
||||
TEST_CHECK(data == (void *)smallest);
|
||||
|
||||
data = NULL;
|
||||
|
||||
num = rand();
|
||||
}
|
||||
|
||||
vieter_heap_free(heap);
|
||||
}
|
||||
|
||||
void test_pop() {
|
||||
const uint64_t n = 500;
|
||||
|
||||
vieter_heap *heap = vieter_heap_init();
|
||||
TEST_SIZE(heap, 0);
|
||||
|
||||
void *data;
|
||||
|
||||
for (uint64_t i = n; i > 0; i--) {
|
||||
vieter_heap_insert(heap, i, (void *)i);
|
||||
TEST_SIZE(heap, (uint64_t)n + 1 - i);
|
||||
TEST_CHECK(count_nodes_heap(heap) == (uint64_t)n + 1 - i);
|
||||
|
||||
TEST_CHECK(vieter_heap_peek(&data, heap) == vieter_heap_ok);
|
||||
TEST_CHECK(data == (void*)i);
|
||||
}
|
||||
|
||||
data = NULL;
|
||||
|
||||
for (uint64_t i = 1; i <= n; i++) {
|
||||
TEST_CHECK(vieter_heap_pop(&data, heap) == vieter_heap_ok);
|
||||
TEST_CHECK(data == (void*)i);
|
||||
TEST_SIZE(heap, (uint64_t)n - i);
|
||||
}
|
||||
|
||||
vieter_heap_free(heap);
|
||||
}
|
||||
|
||||
int uint64_t_compare(const void *a, const void *b) {
|
||||
if ((*(uint64_t *)a) < (*(uint64_t *)b)) {
|
||||
return -1;
|
||||
} else if ((*(uint64_t *)a) > (*(uint64_t *)b)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void test_pop_random() {
|
||||
const uint64_t n = 500;
|
||||
|
||||
srand(0);
|
||||
|
||||
vieter_heap *heap = vieter_heap_init();
|
||||
|
||||
uint64_t *numbers = malloc(n * sizeof(uint64_t));
|
||||
uint64_t num;
|
||||
|
||||
for (uint64_t i = 0; i < n; i++) {
|
||||
num = rand();
|
||||
vieter_heap_insert(heap, num, (void *)num);
|
||||
TEST_SIZE(heap, i + 1);
|
||||
TEST_CHECK(count_nodes_heap(heap) == i + 1);
|
||||
|
||||
numbers[i] = num;
|
||||
}
|
||||
|
||||
|
||||
qsort(numbers, n, sizeof(uint64_t), uint64_t_compare);
|
||||
|
||||
void *data = NULL;
|
||||
|
||||
for (uint64_t i = 0; i < n; i++) {
|
||||
TEST_CHECK(vieter_heap_peek(&data, heap) == vieter_heap_ok);
|
||||
TEST_CHECK_(data == (void *)numbers[i], "peek %lx == %lx", (uint64_t)data, numbers[i]);
|
||||
|
||||
data = NULL;
|
||||
|
||||
TEST_CHECK(vieter_heap_pop(&data, heap) == vieter_heap_ok);
|
||||
TEST_CHECK_(data == (void *)numbers[i], "pop %lx == %lx", (uint64_t)data, numbers[i]);
|
||||
TEST_SIZE(heap, n - i - 1);
|
||||
TEST_CHECK(count_nodes_heap(heap) == n - i - 1);
|
||||
|
||||
// Assure each size is also a valid heap after inserting
|
||||
vieter_heap_insert(heap, numbers[i], (void *)numbers[i]);
|
||||
TEST_SIZE(heap, n - i);
|
||||
TEST_CHECK(count_nodes_heap(heap) == n - i);
|
||||
|
||||
data = NULL;
|
||||
|
||||
TEST_CHECK(vieter_heap_pop(&data, heap) == vieter_heap_ok);
|
||||
TEST_CHECK_(data == (void *)numbers[i], "pop %lx == %lx", (uint64_t)data, numbers[i]);
|
||||
TEST_SIZE(heap, n - i - 1);
|
||||
TEST_CHECK(count_nodes_heap(heap) == n - i - 1);
|
||||
}
|
||||
|
||||
vieter_heap_free(heap);
|
||||
free(numbers);
|
||||
}
|
||||
|
||||
TEST_LIST = {
|
||||
{"init", test_init},
|
||||
{"insert", test_insert},
|
||||
{"insert random", test_insert_random},
|
||||
{"pop", test_pop},
|
||||
{"pop random", test_pop_random},
|
||||
{NULL, NULL}
|
||||
};
|
|
@ -0,0 +1,28 @@
|
|||
#include "acutest.h"
|
||||
#include "vieter_heap.h"
|
||||
#include "vieter_heap_tree.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
void test_merge_same_order() {
|
||||
vieter_heap_node *root_a = vieter_heap_node_init();
|
||||
root_a->key = 1;
|
||||
root_a->order = 0;
|
||||
|
||||
vieter_heap_node *root_b = vieter_heap_node_init();
|
||||
root_b->key = 2;
|
||||
root_b->order = 0;
|
||||
|
||||
vieter_heap_node *merged = vieter_heap_tree_merge_same_order(root_a, root_b);
|
||||
|
||||
TEST_CHECK(merged == root_a);
|
||||
TEST_CHECK(merged->key == 1);
|
||||
TEST_CHECK(merged->largest_order == root_b);
|
||||
TEST_CHECK(merged->ptr.next_largest_order == NULL);
|
||||
|
||||
vieter_heap_tree_free(merged);
|
||||
}
|
||||
|
||||
TEST_LIST = {
|
||||
{"merge same order", test_merge_same_order},
|
||||
{NULL, NULL}
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
# Generated by makepkg 6.0.2
|
||||
# using fakeroot version 1.30.1
|
||||
pkgname = xcursor-dmz
|
||||
pkgbase = xcursor-dmz
|
||||
pkgver = 0.4.5-2
|
||||
pkgdesc = Style neutral, scalable cursor theme
|
||||
url = https://packages.debian.org/sid/dmz-cursor-theme
|
||||
builddate = 1673751613
|
||||
packager = Unknown Packager
|
||||
size = 3469584
|
||||
arch = any
|
||||
license = MIT
|
||||
replaces = test1
|
||||
group = x11
|
||||
conflict = test2
|
||||
conflict = test3
|
||||
provides = test4
|
||||
depend = test5
|
||||
depend = test6
|
||||
optdepend = test7
|
||||
makedepend = xorg-xcursorgen
|
||||
checkdepend = test8
|
|
@ -0,0 +1,45 @@
|
|||
%FILENAME%
|
||||
xcursor-dmz-0.4.5-2-any.pkg.tar.zst
|
||||
|
||||
%NAME%
|
||||
xcursor-dmz
|
||||
|
||||
%BASE%
|
||||
xcursor-dmz
|
||||
|
||||
%VERSION%
|
||||
0.4.5-2
|
||||
|
||||
%DESC%
|
||||
Style neutral, scalable cursor theme
|
||||
|
||||
%GROUPS%
|
||||
x11
|
||||
|
||||
%CSIZE%
|
||||
328282
|
||||
|
||||
%ISIZE%
|
||||
3469584
|
||||
|
||||
%SHA256SUM%
|
||||
4f4bce9e975334ed7775ff4ddf4d2e82e411d599802f6179a122f89149f53bfb
|
||||
|
||||
%URL%
|
||||
https://packages.debian.org/sid/dmz-cursor-theme
|
||||
|
||||
%LICENSE%
|
||||
MIT
|
||||
|
||||
%ARCH%
|
||||
any
|
||||
|
||||
%BUILDDATE%
|
||||
1673751613
|
||||
|
||||
%PACKAGER%
|
||||
Unknown Packager
|
||||
|
||||
%MAKEDEPENDS%
|
||||
xorg-xcursorgen
|
||||
|
|
@ -0,0 +1,243 @@
|
|||
%FILES%
|
||||
usr/
|
||||
usr/share/
|
||||
usr/share/icons/
|
||||
usr/share/icons/DMZ-Black/
|
||||
usr/share/icons/DMZ-Black/cursor.theme
|
||||
usr/share/icons/DMZ-Black/cursors/
|
||||
usr/share/icons/DMZ-Black/cursors/00008160000006810000408080010102
|
||||
usr/share/icons/DMZ-Black/cursors/028006030e0e7ebffc7f7070c0600140
|
||||
usr/share/icons/DMZ-Black/cursors/03b6e0fcb3499374a867c041f52298f0
|
||||
usr/share/icons/DMZ-Black/cursors/08e8e1c95fe2fc01f976f1e063a24ccd
|
||||
usr/share/icons/DMZ-Black/cursors/1081e37283d90000800003c07f3ef6bf
|
||||
usr/share/icons/DMZ-Black/cursors/14fef782d02440884392942c11205230
|
||||
usr/share/icons/DMZ-Black/cursors/2870a09082c103050810ffdffffe0204
|
||||
usr/share/icons/DMZ-Black/cursors/3085a0e285430894940527032f8b26df
|
||||
usr/share/icons/DMZ-Black/cursors/3ecb610c1bf2410f44200f48c40d3599
|
||||
usr/share/icons/DMZ-Black/cursors/4498f0e0c1937ffe01fd06f973665830
|
||||
usr/share/icons/DMZ-Black/cursors/5c6cd98b3f3ebcb1f9c7f1c204630408
|
||||
usr/share/icons/DMZ-Black/cursors/6407b0e94181790501fd1e167b474872
|
||||
usr/share/icons/DMZ-Black/cursors/640fb0e74195791501fd1ed57b41487f
|
||||
usr/share/icons/DMZ-Black/cursors/9081237383d90e509aa00f00170e968f
|
||||
usr/share/icons/DMZ-Black/cursors/9d800788f1b08800ae810202380a0822
|
||||
usr/share/icons/DMZ-Black/cursors/X_cursor
|
||||
usr/share/icons/DMZ-Black/cursors/alias
|
||||
usr/share/icons/DMZ-Black/cursors/arrow
|
||||
usr/share/icons/DMZ-Black/cursors/bd_double_arrow
|
||||
usr/share/icons/DMZ-Black/cursors/bottom_left_corner
|
||||
usr/share/icons/DMZ-Black/cursors/bottom_right_corner
|
||||
usr/share/icons/DMZ-Black/cursors/bottom_side
|
||||
usr/share/icons/DMZ-Black/cursors/bottom_tee
|
||||
usr/share/icons/DMZ-Black/cursors/c7088f0f3e6c8088236ef8e1e3e70000
|
||||
usr/share/icons/DMZ-Black/cursors/circle
|
||||
usr/share/icons/DMZ-Black/cursors/col-resize
|
||||
usr/share/icons/DMZ-Black/cursors/color-picker
|
||||
usr/share/icons/DMZ-Black/cursors/copy
|
||||
usr/share/icons/DMZ-Black/cursors/cross
|
||||
usr/share/icons/DMZ-Black/cursors/cross_reverse
|
||||
usr/share/icons/DMZ-Black/cursors/crossed_circle
|
||||
usr/share/icons/DMZ-Black/cursors/crosshair
|
||||
usr/share/icons/DMZ-Black/cursors/d9ce0ab605698f320427677b458ad60b
|
||||
usr/share/icons/DMZ-Black/cursors/default
|
||||
usr/share/icons/DMZ-Black/cursors/diamond_cross
|
||||
usr/share/icons/DMZ-Black/cursors/dnd-ask
|
||||
usr/share/icons/DMZ-Black/cursors/dnd-copy
|
||||
usr/share/icons/DMZ-Black/cursors/dnd-link
|
||||
usr/share/icons/DMZ-Black/cursors/dnd-move
|
||||
usr/share/icons/DMZ-Black/cursors/dnd-none
|
||||
usr/share/icons/DMZ-Black/cursors/dot_box_mask
|
||||
usr/share/icons/DMZ-Black/cursors/dotbox
|
||||
usr/share/icons/DMZ-Black/cursors/double_arrow
|
||||
usr/share/icons/DMZ-Black/cursors/draft_large
|
||||
usr/share/icons/DMZ-Black/cursors/draft_small
|
||||
usr/share/icons/DMZ-Black/cursors/draped_box
|
||||
usr/share/icons/DMZ-Black/cursors/e-resize
|
||||
usr/share/icons/DMZ-Black/cursors/e29285e634086352946a0e7090d73106
|
||||
usr/share/icons/DMZ-Black/cursors/ew-resize
|
||||
usr/share/icons/DMZ-Black/cursors/fcf1c3c7cd4491d801f1e1c78f100000
|
||||
usr/share/icons/DMZ-Black/cursors/fd_double_arrow
|
||||
usr/share/icons/DMZ-Black/cursors/fleur
|
||||
usr/share/icons/DMZ-Black/cursors/grab
|
||||
usr/share/icons/DMZ-Black/cursors/grabbing
|
||||
usr/share/icons/DMZ-Black/cursors/h_double_arrow
|
||||
usr/share/icons/DMZ-Black/cursors/hand
|
||||
usr/share/icons/DMZ-Black/cursors/hand1
|
||||
usr/share/icons/DMZ-Black/cursors/hand2
|
||||
usr/share/icons/DMZ-Black/cursors/help
|
||||
usr/share/icons/DMZ-Black/cursors/icon
|
||||
usr/share/icons/DMZ-Black/cursors/left_ptr
|
||||
usr/share/icons/DMZ-Black/cursors/left_ptr_help
|
||||
usr/share/icons/DMZ-Black/cursors/left_ptr_watch
|
||||
usr/share/icons/DMZ-Black/cursors/left_side
|
||||
usr/share/icons/DMZ-Black/cursors/left_tee
|
||||
usr/share/icons/DMZ-Black/cursors/link
|
||||
usr/share/icons/DMZ-Black/cursors/ll_angle
|
||||
usr/share/icons/DMZ-Black/cursors/lr_angle
|
||||
usr/share/icons/DMZ-Black/cursors/move
|
||||
usr/share/icons/DMZ-Black/cursors/n-resize
|
||||
usr/share/icons/DMZ-Black/cursors/ne-resize
|
||||
usr/share/icons/DMZ-Black/cursors/nesw-resize
|
||||
usr/share/icons/DMZ-Black/cursors/not-allowed
|
||||
usr/share/icons/DMZ-Black/cursors/ns-resize
|
||||
usr/share/icons/DMZ-Black/cursors/nw-resize
|
||||
usr/share/icons/DMZ-Black/cursors/nwse-resize
|
||||
usr/share/icons/DMZ-Black/cursors/openhand
|
||||
usr/share/icons/DMZ-Black/cursors/pencil
|
||||
usr/share/icons/DMZ-Black/cursors/pirate
|
||||
usr/share/icons/DMZ-Black/cursors/plus
|
||||
usr/share/icons/DMZ-Black/cursors/pointer
|
||||
usr/share/icons/DMZ-Black/cursors/progress
|
||||
usr/share/icons/DMZ-Black/cursors/question_arrow
|
||||
usr/share/icons/DMZ-Black/cursors/right_ptr
|
||||
usr/share/icons/DMZ-Black/cursors/right_side
|
||||
usr/share/icons/DMZ-Black/cursors/right_tee
|
||||
usr/share/icons/DMZ-Black/cursors/row-resize
|
||||
usr/share/icons/DMZ-Black/cursors/s-resize
|
||||
usr/share/icons/DMZ-Black/cursors/sb_down_arrow
|
||||
usr/share/icons/DMZ-Black/cursors/sb_h_double_arrow
|
||||
usr/share/icons/DMZ-Black/cursors/sb_left_arrow
|
||||
usr/share/icons/DMZ-Black/cursors/sb_right_arrow
|
||||
usr/share/icons/DMZ-Black/cursors/sb_up_arrow
|
||||
usr/share/icons/DMZ-Black/cursors/sb_v_double_arrow
|
||||
usr/share/icons/DMZ-Black/cursors/se-resize
|
||||
usr/share/icons/DMZ-Black/cursors/size_bdiag
|
||||
usr/share/icons/DMZ-Black/cursors/size_fdiag
|
||||
usr/share/icons/DMZ-Black/cursors/size_hor
|
||||
usr/share/icons/DMZ-Black/cursors/size_ver
|
||||
usr/share/icons/DMZ-Black/cursors/sw-resize
|
||||
usr/share/icons/DMZ-Black/cursors/target
|
||||
usr/share/icons/DMZ-Black/cursors/tcross
|
||||
usr/share/icons/DMZ-Black/cursors/text
|
||||
usr/share/icons/DMZ-Black/cursors/top_left_arrow
|
||||
usr/share/icons/DMZ-Black/cursors/top_left_corner
|
||||
usr/share/icons/DMZ-Black/cursors/top_right_corner
|
||||
usr/share/icons/DMZ-Black/cursors/top_side
|
||||
usr/share/icons/DMZ-Black/cursors/top_tee
|
||||
usr/share/icons/DMZ-Black/cursors/ul_angle
|
||||
usr/share/icons/DMZ-Black/cursors/ur_angle
|
||||
usr/share/icons/DMZ-Black/cursors/v_double_arrow
|
||||
usr/share/icons/DMZ-Black/cursors/w-resize
|
||||
usr/share/icons/DMZ-Black/cursors/wait
|
||||
usr/share/icons/DMZ-Black/cursors/watch
|
||||
usr/share/icons/DMZ-Black/cursors/xterm
|
||||
usr/share/icons/DMZ-White/
|
||||
usr/share/icons/DMZ-White/cursor.theme
|
||||
usr/share/icons/DMZ-White/cursors/
|
||||
usr/share/icons/DMZ-White/cursors/00008160000006810000408080010102
|
||||
usr/share/icons/DMZ-White/cursors/028006030e0e7ebffc7f7070c0600140
|
||||
usr/share/icons/DMZ-White/cursors/03b6e0fcb3499374a867c041f52298f0
|
||||
usr/share/icons/DMZ-White/cursors/08e8e1c95fe2fc01f976f1e063a24ccd
|
||||
usr/share/icons/DMZ-White/cursors/1081e37283d90000800003c07f3ef6bf
|
||||
usr/share/icons/DMZ-White/cursors/14fef782d02440884392942c11205230
|
||||
usr/share/icons/DMZ-White/cursors/2870a09082c103050810ffdffffe0204
|
||||
usr/share/icons/DMZ-White/cursors/3085a0e285430894940527032f8b26df
|
||||
usr/share/icons/DMZ-White/cursors/3ecb610c1bf2410f44200f48c40d3599
|
||||
usr/share/icons/DMZ-White/cursors/4498f0e0c1937ffe01fd06f973665830
|
||||
usr/share/icons/DMZ-White/cursors/5c6cd98b3f3ebcb1f9c7f1c204630408
|
||||
usr/share/icons/DMZ-White/cursors/6407b0e94181790501fd1e167b474872
|
||||
usr/share/icons/DMZ-White/cursors/640fb0e74195791501fd1ed57b41487f
|
||||
usr/share/icons/DMZ-White/cursors/9081237383d90e509aa00f00170e968f
|
||||
usr/share/icons/DMZ-White/cursors/9d800788f1b08800ae810202380a0822
|
||||
usr/share/icons/DMZ-White/cursors/X_cursor
|
||||
usr/share/icons/DMZ-White/cursors/alias
|
||||
usr/share/icons/DMZ-White/cursors/arrow
|
||||
usr/share/icons/DMZ-White/cursors/bd_double_arrow
|
||||
usr/share/icons/DMZ-White/cursors/bottom_left_corner
|
||||
usr/share/icons/DMZ-White/cursors/bottom_right_corner
|
||||
usr/share/icons/DMZ-White/cursors/bottom_side
|
||||
usr/share/icons/DMZ-White/cursors/bottom_tee
|
||||
usr/share/icons/DMZ-White/cursors/c7088f0f3e6c8088236ef8e1e3e70000
|
||||
usr/share/icons/DMZ-White/cursors/circle
|
||||
usr/share/icons/DMZ-White/cursors/col-resize
|
||||
usr/share/icons/DMZ-White/cursors/color-picker
|
||||
usr/share/icons/DMZ-White/cursors/copy
|
||||
usr/share/icons/DMZ-White/cursors/cross
|
||||
usr/share/icons/DMZ-White/cursors/cross_reverse
|
||||
usr/share/icons/DMZ-White/cursors/crossed_circle
|
||||
usr/share/icons/DMZ-White/cursors/crosshair
|
||||
usr/share/icons/DMZ-White/cursors/d9ce0ab605698f320427677b458ad60b
|
||||
usr/share/icons/DMZ-White/cursors/default
|
||||
usr/share/icons/DMZ-White/cursors/diamond_cross
|
||||
usr/share/icons/DMZ-White/cursors/dnd-ask
|
||||
usr/share/icons/DMZ-White/cursors/dnd-copy
|
||||
usr/share/icons/DMZ-White/cursors/dnd-link
|
||||
usr/share/icons/DMZ-White/cursors/dnd-move
|
||||
usr/share/icons/DMZ-White/cursors/dnd-none
|
||||
usr/share/icons/DMZ-White/cursors/dot_box_mask
|
||||
usr/share/icons/DMZ-White/cursors/dotbox
|
||||
usr/share/icons/DMZ-White/cursors/double_arrow
|
||||
usr/share/icons/DMZ-White/cursors/draft_large
|
||||
usr/share/icons/DMZ-White/cursors/draft_small
|
||||
usr/share/icons/DMZ-White/cursors/draped_box
|
||||
usr/share/icons/DMZ-White/cursors/e-resize
|
||||
usr/share/icons/DMZ-White/cursors/e29285e634086352946a0e7090d73106
|
||||
usr/share/icons/DMZ-White/cursors/ew-resize
|
||||
usr/share/icons/DMZ-White/cursors/fcf1c3c7cd4491d801f1e1c78f100000
|
||||
usr/share/icons/DMZ-White/cursors/fd_double_arrow
|
||||
usr/share/icons/DMZ-White/cursors/fleur
|
||||
usr/share/icons/DMZ-White/cursors/grab
|
||||
usr/share/icons/DMZ-White/cursors/grabbing
|
||||
usr/share/icons/DMZ-White/cursors/h_double_arrow
|
||||
usr/share/icons/DMZ-White/cursors/hand
|
||||
usr/share/icons/DMZ-White/cursors/hand1
|
||||
usr/share/icons/DMZ-White/cursors/hand2
|
||||
usr/share/icons/DMZ-White/cursors/help
|
||||
usr/share/icons/DMZ-White/cursors/icon
|
||||
usr/share/icons/DMZ-White/cursors/left_ptr
|
||||
usr/share/icons/DMZ-White/cursors/left_ptr_help
|
||||
usr/share/icons/DMZ-White/cursors/left_ptr_watch
|
||||
usr/share/icons/DMZ-White/cursors/left_side
|
||||
usr/share/icons/DMZ-White/cursors/left_tee
|
||||
usr/share/icons/DMZ-White/cursors/link
|
||||
usr/share/icons/DMZ-White/cursors/ll_angle
|
||||
usr/share/icons/DMZ-White/cursors/lr_angle
|
||||
usr/share/icons/DMZ-White/cursors/move
|
||||
usr/share/icons/DMZ-White/cursors/n-resize
|
||||
usr/share/icons/DMZ-White/cursors/ne-resize
|
||||
usr/share/icons/DMZ-White/cursors/nesw-resize
|
||||
usr/share/icons/DMZ-White/cursors/not-allowed
|
||||
usr/share/icons/DMZ-White/cursors/ns-resize
|
||||
usr/share/icons/DMZ-White/cursors/nw-resize
|
||||
usr/share/icons/DMZ-White/cursors/nwse-resize
|
||||
usr/share/icons/DMZ-White/cursors/openhand
|
||||
usr/share/icons/DMZ-White/cursors/pencil
|
||||
usr/share/icons/DMZ-White/cursors/pirate
|
||||
usr/share/icons/DMZ-White/cursors/plus
|
||||
usr/share/icons/DMZ-White/cursors/pointer
|
||||
usr/share/icons/DMZ-White/cursors/progress
|
||||
usr/share/icons/DMZ-White/cursors/question_arrow
|
||||
usr/share/icons/DMZ-White/cursors/right_ptr
|
||||
usr/share/icons/DMZ-White/cursors/right_side
|
||||
usr/share/icons/DMZ-White/cursors/right_tee
|
||||
usr/share/icons/DMZ-White/cursors/row-resize
|
||||
usr/share/icons/DMZ-White/cursors/s-resize
|
||||
usr/share/icons/DMZ-White/cursors/sb_down_arrow
|
||||
usr/share/icons/DMZ-White/cursors/sb_h_double_arrow
|
||||
usr/share/icons/DMZ-White/cursors/sb_left_arrow
|
||||
usr/share/icons/DMZ-White/cursors/sb_right_arrow
|
||||
usr/share/icons/DMZ-White/cursors/sb_up_arrow
|
||||
usr/share/icons/DMZ-White/cursors/sb_v_double_arrow
|
||||
usr/share/icons/DMZ-White/cursors/se-resize
|
||||
usr/share/icons/DMZ-White/cursors/size_bdiag
|
||||
usr/share/icons/DMZ-White/cursors/size_fdiag
|
||||
usr/share/icons/DMZ-White/cursors/size_hor
|
||||
usr/share/icons/DMZ-White/cursors/size_ver
|
||||
usr/share/icons/DMZ-White/cursors/sw-resize
|
||||
usr/share/icons/DMZ-White/cursors/target
|
||||
usr/share/icons/DMZ-White/cursors/tcross
|
||||
usr/share/icons/DMZ-White/cursors/text
|
||||
usr/share/icons/DMZ-White/cursors/top_left_arrow
|
||||
usr/share/icons/DMZ-White/cursors/top_left_corner
|
||||
usr/share/icons/DMZ-White/cursors/top_right_corner
|
||||
usr/share/icons/DMZ-White/cursors/top_side
|
||||
usr/share/icons/DMZ-White/cursors/top_tee
|
||||
usr/share/icons/DMZ-White/cursors/ul_angle
|
||||
usr/share/icons/DMZ-White/cursors/ur_angle
|
||||
usr/share/icons/DMZ-White/cursors/v_double_arrow
|
||||
usr/share/icons/DMZ-White/cursors/w-resize
|
||||
usr/share/icons/DMZ-White/cursors/wait
|
||||
usr/share/icons/DMZ-White/cursors/watch
|
||||
usr/share/icons/DMZ-White/cursors/xterm
|
||||
usr/share/licenses/
|
||||
usr/share/licenses/xcursor-dmz/
|
||||
usr/share/licenses/xcursor-dmz/LICENSE
|
|
@ -0,0 +1,84 @@
|
|||
#include "acutest.h"
|
||||
#include "package.h"
|
||||
|
||||
void test_pkg_info_parse() {
|
||||
FILE *f = fopen("./test/package/.PKGINFO", "r");
|
||||
TEST_ASSERT_(f != NULL, "could not find test .PKGINFO file in ./test/package ");
|
||||
fseek(f, 0L, SEEK_END);
|
||||
size_t size = ftell(f);
|
||||
fflush(stdout);
|
||||
rewind(f);
|
||||
char *pkg_info_str = malloc(size);
|
||||
fread(pkg_info_str, 1, size, f);
|
||||
fclose(f);
|
||||
PkgInfo *pkg_info = package_info_init();
|
||||
package_info_parse(pkg_info, pkg_info_str);
|
||||
|
||||
TEST_CHECK(!strcmp(pkg_info->name, "xcursor-dmz"));
|
||||
TEST_CHECK(!strcmp(pkg_info->base, "xcursor-dmz"));
|
||||
TEST_CHECK(!strcmp(pkg_info->version, "0.4.5-2"));
|
||||
TEST_CHECK(!strcmp(pkg_info->description, "Style neutral, scalable cursor theme"));
|
||||
TEST_CHECK(!strcmp(pkg_info->url, "https://packages.debian.org/sid/dmz-cursor-theme"));
|
||||
TEST_CHECK(pkg_info->build_date == 1673751613);
|
||||
TEST_CHECK(!strcmp(pkg_info->packager, "Unknown Packager"));
|
||||
TEST_CHECK(pkg_info->size == 3469584);
|
||||
TEST_CHECK(!strcmp(pkg_info->arch, "any"));
|
||||
|
||||
TEST_CHECK(!strcmp(pkg_info->licenses->array[0], "MIT"));
|
||||
TEST_CHECK(!strcmp(pkg_info->replaces->array[0], "test1"));
|
||||
TEST_CHECK(!strcmp(pkg_info->groups->array[0], "x11"));
|
||||
TEST_CHECK(!strcmp(pkg_info->conflicts->array[0], "test2"));
|
||||
TEST_CHECK(!strcmp(pkg_info->conflicts->array[1], "test3"));
|
||||
TEST_CHECK(!strcmp(pkg_info->provides->array[0], "test4"));
|
||||
TEST_CHECK(!strcmp(pkg_info->depends->array[0], "test5"));
|
||||
TEST_CHECK(!strcmp(pkg_info->depends->array[1], "test6"));
|
||||
TEST_CHECK(!strcmp(pkg_info->optdepends->array[0], "test7"));
|
||||
TEST_CHECK(!strcmp(pkg_info->makedepends->array[0], "xorg-xcursorgen"));
|
||||
TEST_CHECK(!strcmp(pkg_info->checkdepends->array[0], "test8"));
|
||||
}
|
||||
|
||||
void test_pkg_read_archive_files() {
|
||||
Pkg *pkg = package_read_archive("./test/package/xcursor-dmz-0.4.5-2-any.pkg.tar.zst");
|
||||
TEST_ASSERT_(pkg != NULL, "failure parsing pkg archive");
|
||||
|
||||
FILE *f = fopen("./test/package/files", "r");
|
||||
TEST_ASSERT_(f != NULL, "could not find test files file in ./test/package");
|
||||
char buff[128];
|
||||
size_t i = 0;
|
||||
|
||||
while ((fgets(buff, 128, f)) != NULL || i < pkg->files->size) {
|
||||
if (buff[strlen(buff) - 1] == '\n') {
|
||||
buff[strlen(buff) - 1] = '\0';
|
||||
}
|
||||
|
||||
TEST_CHECK_(!strcmp(pkg->files->array[i], buff), "%s != %s", pkg->files->array[i], buff);
|
||||
i++;
|
||||
}
|
||||
TEST_CHECK(pkg->compression = 14);
|
||||
|
||||
}
|
||||
|
||||
void test_pkg_read_archive_desc() {
|
||||
Pkg *pkg = package_read_archive("./test/package/xcursor-dmz-0.4.5-2-any.pkg.tar.zst");
|
||||
TEST_ASSERT_(pkg != NULL, "failure parsing pkg archive");
|
||||
|
||||
char *description = package_to_description(pkg);
|
||||
|
||||
FILE *f = fopen("./test/package/desc", "r");
|
||||
TEST_ASSERT_(f != NULL, "could not find test desc file in ./test/package");
|
||||
fseek(f, 0, SEEK_END);
|
||||
size_t size = ftell(f);
|
||||
rewind(f);
|
||||
char *desc = malloc(size);
|
||||
fread(desc, 1, size, f);
|
||||
fclose(f);
|
||||
|
||||
TEST_CHECK(!strcmp(description, desc));
|
||||
}
|
||||
|
||||
TEST_LIST = {
|
||||
{"pkg_info_valid_parse", test_pkg_info_parse},
|
||||
{"pkg_read_archive_files", test_pkg_read_archive_files},
|
||||
{"pkg_read_archive_desc", test_pkg_read_archive_desc},
|
||||
{NULL, NULL}
|
||||
};
|
Binary file not shown.
Loading…
Reference in New Issue