forked from KolibriOS/kolibrios
[obj2def] Initial commit
git-svn-id: svn://kolibrios.org@9532 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
parent
07168fc588
commit
18ae50738d
5
programs/develop/obj2def/README.md
Normal file
5
programs/develop/obj2def/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# clink
|
||||
|
||||
Very simple (yet?) COFF to COFF linker. Merges several COFF files into one. Only works for dependency-less objects yet (designed exclusively for linking objects into KolibriOS COFF library).
|
||||
|
||||
[Development process](https://www.youtube.com/playlist?list=PLVMOfciBdLI6BPovPgfVZ9bNuwbXetRc9) (in Russian)
|
21
programs/develop/obj2def/cdict/LICENSE
Normal file
21
programs/develop/obj2def/cdict/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Magomed Kostoev
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
88
programs/develop/obj2def/cdict/README.md
Normal file
88
programs/develop/obj2def/cdict/README.md
Normal file
@ -0,0 +1,88 @@
|
||||
# CDict - a simple dictionary implementation in C
|
||||
## Ready to use!
|
||||
|
||||
It may be used out of the box with key and value of type `CStr` (which is `char *` - zero-terminated string). Once it instantiated in some file using `CDICT_INST` definition:
|
||||
|
||||
```C
|
||||
#define CDICT_INST
|
||||
#include "cdict.h"
|
||||
```
|
||||
|
||||
It may be then declared just using `#include`:
|
||||
|
||||
```C
|
||||
#include "cdict.h"
|
||||
|
||||
int main() {
|
||||
CDict_CStr_CStr dict;
|
||||
if (!cdict_CStr_CStr_init(&dict)) {
|
||||
printf("CDict returned error #%d", dict.error_code);
|
||||
return 0;
|
||||
}
|
||||
cdict_CStr_CStr_add_vv(&dict, "key_a", "value_a", CDICT_REPLACE_EXIST);
|
||||
printf("[key_a] = \"%s\"\n", cdict_CStr_CStr_get_v(&dict, "key_a"));
|
||||
}
|
||||
```
|
||||
|
||||
## Easy to configure!
|
||||
|
||||
If you want to create a dictionary for other key types you should provide your own keys hashing and comparsion functions, in such case the instantiation of the library will look like this:
|
||||
|
||||
```C
|
||||
#define CDICT_INST
|
||||
#define CDICT_KEY_T MyType
|
||||
#define CDICT_HASH_FN(pkey) my_hash(pkey)
|
||||
#define CDICT_CMP_FN(pkey0, pkey1) my_cmp(pkey0, pkey1)
|
||||
#include "cdict.h"
|
||||
|
||||
int my_cmp(MyType *pkey0, MyType *pkey1) {
|
||||
// Return `whatever_negative` if `key0 < key1`, `0` if `key0 == key1` and `whatever_positive` if `key0 > key1`
|
||||
}
|
||||
|
||||
unsigned long my_hash(MyType *key) {
|
||||
// Return the hash of the key
|
||||
}
|
||||
```
|
||||
|
||||
Then to use the new dictionary you only need to define key type before the header inclusion:
|
||||
|
||||
```C
|
||||
#define CDICT_KEY_T MyType
|
||||
#include "cdict.h"
|
||||
|
||||
// ...
|
||||
CDict_MyType_CStr dict;
|
||||
cdict_MyType_CStr_init(&dict);
|
||||
// ...
|
||||
```
|
||||
|
||||
If you want to specify the type of values - just define the type:
|
||||
|
||||
```C
|
||||
#define CDICT_VAL_T MyValueType
|
||||
```
|
||||
|
||||
And so on.
|
||||
|
||||
## Dependency-free!
|
||||
|
||||
Every single used dependency may be redefined:
|
||||
|
||||
```C
|
||||
#define CDICT_ASSERT_FN(x) my_assert(x);
|
||||
```
|
||||
|
||||
## Flexible!
|
||||
|
||||
May define user data to be used in overriden functions (for example - custom allocators):
|
||||
|
||||
```C
|
||||
#define CDICT_USER_DATA_T UserData
|
||||
#define CDICT_HASHTAB_ITEM_ALLOC_FN(cdict, size) item_alloc(cdict, size)
|
||||
#define CDICT_HASHTAB_ITEM_FREE_FN(cdict, ptr) item_free(cdict, ptr)
|
||||
#define CDICT_HASHTAB_ALLOC_FN(cdict, size) hashtab_alloc(cdict, size)
|
||||
```
|
||||
|
||||
## Checkout
|
||||
|
||||
[The library](cdict.h).
|
350
programs/develop/obj2def/cdict/cdict.h
Normal file
350
programs/develop/obj2def/cdict/cdict.h
Normal file
@ -0,0 +1,350 @@
|
||||
// Copyright (c) 2020 Magomed Kostoev
|
||||
//
|
||||
// You may use, distribute and modify this code under the terms of the MIT license.
|
||||
//
|
||||
// You should have received a copy of the MIT license with this file. If not, please visit
|
||||
// https://opensource.org/licenses/MIT or boppan.org/MIT for full license details.
|
||||
|
||||
// cdict.h - simple dictionaty implementation in C.
|
||||
//
|
||||
// Uses hash table with fixed (but configurable) size. Functions named using given type names:
|
||||
// cdict_<CDICT_KEY_T>_<CDICT_VAL_T>_<name>.
|
||||
//
|
||||
// See configuration below (in public "Input macros" section), also:
|
||||
// CDICT_INST: Instantiate the functions if defined.
|
||||
//
|
||||
// Minimal definitions for declaration: CDICT_KEY_T, CDICT_VAL_T
|
||||
// Minimal definitions for instantiation: CDICT_INST, CDICT_KEY_T, CDICT_VAL_T, CDICT_HASH_FN,
|
||||
// CDICT_CMP_FN
|
||||
//
|
||||
// WARNING: All used definitions will be undefined on header exit.
|
||||
//
|
||||
// Dependencies:
|
||||
// <stddef.h> or another source of size_t
|
||||
// <stdlib.h> or another source of malloc, and calloc
|
||||
// <assert.h> or another source of assert
|
||||
|
||||
//
|
||||
// Internal macros for external declarations
|
||||
//
|
||||
|
||||
#define CDICT_CAT2_IMPL(x, y) x ## _ ## y
|
||||
#define CDICT_CAT2(x, y) CDICT_CAT2_IMPL(x, y)
|
||||
|
||||
/// Creates method name according to CDICT_KEY_T and CDICT_VAL_T
|
||||
#define CDICT_FUN(name) CDICT_CAT2(cdict, CDICT_CAT2(CDICT_KEY_T, CDICT_CAT2(CDICT_VAL_T, name)))
|
||||
|
||||
#define cdict_init CDICT_FUN(init)
|
||||
#define cdict_init_ud CDICT_FUN(init_ud)
|
||||
#define cdict_init_pud CDICT_FUN(init_pud)
|
||||
#define cdict_add_pp CDICT_FUN(add_pp)
|
||||
#define cdict_add_vv CDICT_FUN(add_vv)
|
||||
#define cdict_get_p CDICT_FUN(get_p)
|
||||
#define cdict_get_v CDICT_FUN(get_v)
|
||||
#define cdict_error_message CDICT_FUN(error_message)
|
||||
|
||||
#define cdict_hash CDICT_FUN(hash)
|
||||
#define cdict_keycmp CDICT_FUN(keycmp)
|
||||
#define cdict_chain_begin CDICT_FUN(begin)
|
||||
#define cdict_chain_next CDICT_FUN(next)
|
||||
|
||||
#define CDictItem CDICT_CAT2(CDictItem, CDICT_CAT2(CDICT_KEY_T, CDICT_VAL_T))
|
||||
#define CDictItem_s CDICT_CAT2(CDictItem_s, CDICT_CAT2(CDICT_KEY_T, CDICT_VAL_T))
|
||||
#define CDict CDICT_CAT2(CDict, CDICT_CAT2(CDICT_KEY_T, CDICT_VAL_T))
|
||||
|
||||
//
|
||||
// Input macros
|
||||
//
|
||||
|
||||
/// Type of the dictionary's keys, named type only - used in functions names, default: CStr
|
||||
#ifndef CDICT_KEY_T
|
||||
typedef char *CStr;
|
||||
#define CDICT_CSTR_IS_THERE
|
||||
#define CDICT_KEY_T CStr
|
||||
#endif
|
||||
|
||||
/// Type of the dictionary's values, named type only - used in functions names, default: CStr
|
||||
#ifndef CDICT_VAL_T
|
||||
#ifndef CDICT_CSTR_IS_THERE
|
||||
typedef char *CStr;
|
||||
#endif
|
||||
#define CDICT_VAL_T CStr
|
||||
#endif
|
||||
|
||||
/// Type of user data
|
||||
#ifndef CDICT_USER_DATA_T
|
||||
#define CDICT_USER_DATA_T void *
|
||||
#endif
|
||||
|
||||
//
|
||||
// Public interface
|
||||
//
|
||||
|
||||
#define CDICT_NO_CHECK 0
|
||||
#define CDICT_REPLACE_EXIST 1
|
||||
#define CDICT_LEAVE_EXIST 2
|
||||
|
||||
#define CDICT_ERR_SUCCESS 0
|
||||
#define CDICT_ERR_OUT_OF_MEMORY 1
|
||||
#define CDICT_ERR_THIS_IS_NULL 2
|
||||
#define CDICT_ERR_HASH_TABLE_IS_NULL 3
|
||||
#define CDICT_ERR_PKEY0_IS_NULL 4
|
||||
#define CDICT_ERR_PKEY1_IS_NULL 5
|
||||
#define CDICT_ERR_PKEY_IS_NULL 6
|
||||
#define CDICT_ERR_PVAL_IS_NULL 7
|
||||
|
||||
typedef struct CDictItem_s {
|
||||
struct CDictItem_s *next_collision;
|
||||
CDICT_KEY_T key;
|
||||
CDICT_VAL_T val;
|
||||
} CDictItem;
|
||||
|
||||
typedef struct {
|
||||
CDictItem **hash_table;
|
||||
CDICT_USER_DATA_T user_data;
|
||||
int error_code;
|
||||
} CDict;
|
||||
|
||||
/// Initializes dictionary structure
|
||||
int cdict_init(CDict *s);
|
||||
|
||||
/// Initializes dictionary structure with non-standard user data
|
||||
int cdict_init_ud(CDict *s, CDICT_USER_DATA_T user_data);
|
||||
|
||||
/// Initializes dictionary structure with non-standard user data
|
||||
int cdict_init_pud(CDict *s, CDICT_USER_DATA_T *user_data);
|
||||
|
||||
/// Inserts a value by key (receives pointers to val and key)
|
||||
CDictItem *cdict_add_pp(CDict *s, CDICT_KEY_T *pkey, CDICT_VAL_T *pval, int if_exists);
|
||||
|
||||
/// Inserts a value by key (receives values of val and key)
|
||||
CDictItem *cdict_add_vv(CDict *s, CDICT_KEY_T key, CDICT_VAL_T val, int if_exists);
|
||||
|
||||
/// Gives a value by key (receives a pointer to key)
|
||||
CDICT_VAL_T cdict_get_p(CDict *s, CDICT_KEY_T *pkey);
|
||||
|
||||
/// Gives a vaule by key (receives a value of key)
|
||||
CDICT_VAL_T cdict_get_v(CDict *s, CDICT_KEY_T key);
|
||||
|
||||
#ifdef CDICT_INST
|
||||
|
||||
//
|
||||
// Input macros (instantiation edition)
|
||||
//
|
||||
|
||||
/// The value returned on some error
|
||||
#ifndef CDICT_VAL_DEFAULT
|
||||
#define CDICT_VAL_DEFAULT (CDICT_VAL_T){ 0 }
|
||||
#endif
|
||||
|
||||
/// Hashing function for the key type
|
||||
#ifndef CDICT_HASH_FN
|
||||
#include <string.h>
|
||||
#define CDICT_HASH_FN(pkey) strlen(*pkey) ^ (*pkey)[0]
|
||||
#else
|
||||
#define CDICT_HASH_FN_OVERRIDEN
|
||||
#endif
|
||||
|
||||
/// Ammount of pointers to elements in hash table
|
||||
#ifndef CDICT_HASHTAB_SZ
|
||||
#define CDICT_HASHTAB_SZ 1024
|
||||
#endif
|
||||
|
||||
/// Hash table allocator MUST return zeroed buffer
|
||||
#ifndef CDICT_HASHTAB_ALLOC_FN
|
||||
#include <stdlib.h>
|
||||
#define CDICT_HASHTAB_ALLOC_FN(cdict, size) calloc(1, size)
|
||||
#else
|
||||
#define CDICT_HASHTAB_ALLOCATORS_OVERRIDDEN
|
||||
#endif
|
||||
|
||||
/// New hash table items allocator (should be just a function call)
|
||||
#ifndef CDICT_HASHTAB_ITEM_ALLOC_FN
|
||||
#include <stdlib.h>
|
||||
#define CDICT_HASHTAB_ITEM_ALLOC_FN(cdict, size) malloc(size)
|
||||
#define CDICT_HASHTAB_ITEM_FREE_FN(cdict, ptr) free(ptr)
|
||||
#else
|
||||
#ifndef CDICT_HASHTAB_ITEM_FREE_FN
|
||||
#error "CDICT_HASHTAB_ITEM_FREE_FN should be defiend along with CDICT_HASHTAB_ITEM_ALLOC_FN"
|
||||
#endif
|
||||
#define CDICT_HASHTAB_ITEM_ALLOCATORS_OVERRIDDEN
|
||||
#endif
|
||||
|
||||
#ifdef CDICT_HASHTAB_ITEM_ALLOCATORS_OVERRIDDEN
|
||||
#error "FUCK!"
|
||||
#endif
|
||||
|
||||
/// Replacement for assert from <assert.h>
|
||||
#ifndef CDICT_ASSERT_FN
|
||||
#include <assert.h>
|
||||
#define CDICT_ASSERT_FN(x) if (!x) { printf(__FILE__":%d: Disasserted", __LINE__); } assert(x)
|
||||
#endif
|
||||
|
||||
/// Function for comparsion of keys, return should be the same as memcmp
|
||||
#ifndef CDICT_CMP_FN
|
||||
#include <string.h>
|
||||
#define CDICT_CMP_FN(pkey0, pkey1) strcmp(*pkey0, *pkey1)
|
||||
#else
|
||||
#define CDICT_CMP_FN_OVERRIDDEN
|
||||
#endif
|
||||
|
||||
//
|
||||
// Internal macros (instantiation edition)
|
||||
//
|
||||
|
||||
#define CDICT_ASSERT(x) ({ CDICT_ASSERT_FN(x); x; })
|
||||
// Should write the error code into strucure, but should not rewrite it's already set
|
||||
#define CDICT_IF_NULL_SET_ERR_RETURN(x, ec, res) if (x == NULL) { \
|
||||
if (s->error_code == CDICT_ERR_SUCCESS) s->error_code = ec; \
|
||||
return res; \
|
||||
}
|
||||
#define CDICT_IF_NULL_RETURN(x, res) if (x == NULL) return res
|
||||
|
||||
//
|
||||
// Predeclarations
|
||||
//
|
||||
|
||||
#ifdef CDICT_HASHTAB_ITEM_ALLOCATORS_OVERRIDDEN
|
||||
void *CDICT_HASHTAB_ITEM_ALLOC_FN(CDict *s, size_t size);
|
||||
void CDICT_HASHTAB_ITEM_FREE_FN(CDict *s, CDictItem *ptr);
|
||||
#endif
|
||||
|
||||
#ifdef CDICT_HASHTAB_ALLOCATORS_OVERRIDDEN
|
||||
void *CDICT_HASHTAB_ALLOC_FN(CDict *s, size_t size);
|
||||
#endif
|
||||
|
||||
#ifdef CDICT_HASH_FN_OVERRIDEN
|
||||
unsigned long CDICT_HASH_FN(CDICT_KEY_T *pkey);
|
||||
#endif
|
||||
|
||||
#ifdef CDICT_CMP_FN_OVERRIDDEN
|
||||
int CDICT_CMP_FN(CDICT_KEY_T *pkey0, CDICT_KEY_T *pkey1);
|
||||
#endif
|
||||
|
||||
//
|
||||
// The code
|
||||
//
|
||||
|
||||
static size_t cdict_hash(CDICT_KEY_T *pkey) {
|
||||
return CDICT_HASH_FN(CDICT_ASSERT(pkey)) & (CDICT_HASHTAB_SZ - 1);
|
||||
}
|
||||
|
||||
static int cdict_keycmp(CDICT_KEY_T *pkey0, CDICT_KEY_T *pkey1) {
|
||||
return CDICT_CMP_FN(CDICT_ASSERT(pkey0), CDICT_ASSERT(pkey1));
|
||||
}
|
||||
|
||||
static CDictItem **cdict_chain_begin(CDict *s, CDICT_KEY_T *pkey) {
|
||||
CDICT_ASSERT(s);
|
||||
size_t hash = cdict_hash(CDICT_ASSERT(pkey));
|
||||
CDICT_IF_NULL_SET_ERR_RETURN(s->hash_table, CDICT_ERR_HASH_TABLE_IS_NULL, NULL);
|
||||
return &s->hash_table[hash];
|
||||
}
|
||||
|
||||
static CDictItem **cdict_chain_next(CDictItem **ppit) {
|
||||
CDICT_ASSERT(ppit);
|
||||
CDICT_ASSERT(*ppit);
|
||||
return &(*ppit)->next_collision;
|
||||
}
|
||||
|
||||
int cdict_init(CDict *s) {
|
||||
return cdict_init_pud(s, NULL);
|
||||
}
|
||||
|
||||
int cdict_init_ud(CDict *s, CDICT_USER_DATA_T user_data) {
|
||||
return cdict_init_pud(s, &user_data);
|
||||
}
|
||||
|
||||
int cdict_init_pud(CDict *s, CDICT_USER_DATA_T *user_data) {
|
||||
CDICT_IF_NULL_RETURN(s, 0);
|
||||
s->user_data = user_data ? *user_data : (CDICT_USER_DATA_T){ 0 };
|
||||
s->error_code = CDICT_ERR_SUCCESS;
|
||||
s->hash_table = CDICT_HASHTAB_ALLOC_FN(s, sizeof(*s->hash_table) * CDICT_HASHTAB_SZ);
|
||||
CDICT_IF_NULL_SET_ERR_RETURN(s->hash_table, CDICT_ERR_OUT_OF_MEMORY, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
CDictItem *cdict_add_pp(CDict *s, CDICT_KEY_T *pkey, CDICT_VAL_T *pval, int if_exists) {
|
||||
CDICT_IF_NULL_RETURN(s, NULL);
|
||||
CDICT_IF_NULL_SET_ERR_RETURN(pkey, CDICT_ERR_PKEY_IS_NULL, NULL);
|
||||
CDICT_IF_NULL_SET_ERR_RETURN(pval, CDICT_ERR_PVAL_IS_NULL, NULL);
|
||||
CDictItem *next_collision = NULL;
|
||||
CDictItem **ppit = cdict_chain_begin(s, pkey);
|
||||
CDICT_IF_NULL_RETURN(ppit, NULL);
|
||||
while (*ppit) {
|
||||
int exists = if_exists == CDICT_NO_CHECK ? 0 : !cdict_keycmp(pkey, &(*ppit)->key);
|
||||
if (exists) {
|
||||
if (if_exists == CDICT_LEAVE_EXIST) {
|
||||
return *ppit;
|
||||
} else if (if_exists == CDICT_REPLACE_EXIST) {
|
||||
next_collision = (*ppit)->next_collision;
|
||||
CDICT_HASHTAB_ITEM_FREE_FN(s, *ppit);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ppit = cdict_chain_next(ppit);
|
||||
}
|
||||
*ppit = CDICT_HASHTAB_ITEM_ALLOC_FN(s, sizeof(**ppit));
|
||||
CDictItem *pit = *ppit;
|
||||
pit->key = *pkey;
|
||||
pit->val = *pval;
|
||||
pit->next_collision = next_collision;
|
||||
return pit;
|
||||
}
|
||||
|
||||
CDictItem *cdict_add_vv(CDict *s, CDICT_KEY_T key, CDICT_VAL_T val, int if_exists) {
|
||||
return cdict_add_pp(s, &key, &val, if_exists);
|
||||
}
|
||||
|
||||
CDICT_VAL_T cdict_get_p(CDict *s, CDICT_KEY_T *pkey) {
|
||||
CDICT_IF_NULL_RETURN(s, CDICT_VAL_DEFAULT);
|
||||
CDICT_IF_NULL_SET_ERR_RETURN(pkey, CDICT_ERR_PKEY_IS_NULL, CDICT_VAL_DEFAULT);
|
||||
CDictItem **ppit = cdict_chain_begin(s, pkey);
|
||||
CDICT_IF_NULL_RETURN(ppit, CDICT_VAL_DEFAULT);
|
||||
while (*ppit) {
|
||||
if (!cdict_keycmp(pkey, &(*ppit)->key)) {
|
||||
return (*ppit)->val;
|
||||
}
|
||||
ppit = cdict_chain_next(ppit);
|
||||
}
|
||||
return CDICT_VAL_DEFAULT;
|
||||
}
|
||||
|
||||
CDICT_VAL_T cdict_get_v(CDict *s, CDICT_KEY_T key) {
|
||||
return cdict_get_p(s, &key);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#undef CDICT_CAT2_IMPL
|
||||
#undef CDICT_CAT2
|
||||
#undef CDICT_FUN
|
||||
|
||||
#undef cdict_init
|
||||
#undef cdict_init_ud
|
||||
#undef cdict_init_pud
|
||||
#undef cdict_add_pp
|
||||
#undef cdict_add_vv
|
||||
#undef cdict_get_p
|
||||
#undef cdict_get_v
|
||||
|
||||
#undef CDICT_KEY_T
|
||||
#undef CDICT_VAL_T
|
||||
#undef CDICT_USER_DATA_T
|
||||
|
||||
#ifdef CDICT_INST
|
||||
#undef CDICT_INST
|
||||
#undef CDICT_HASH_FN
|
||||
#undef CDICT_HASHTAB_SZ
|
||||
#undef CDICT_HASHTAB_ALLOC_FN
|
||||
#undef CDICT_HASHTAB_ITEM_ALLOC_FN
|
||||
#undef CDICT_HASHTAB_ITEM_FREE_FN
|
||||
#undef CDICT_ASSERT_FN
|
||||
#undef CDICT_CMP_FN
|
||||
#undef CDICT_ASSERT
|
||||
#undef CDICT_IF_NULL_RETURN
|
||||
#undef CDICT_IF_NULL_SET_ERR_RETURN
|
||||
#undef CDICT_HASHTAB_ITEM_ALLOCATORS_OVERRIDDEN
|
||||
#undef CDICT_HASHTAB_ALLOCATORS_OVERRIDDEN
|
||||
#undef CDICT_HASH_FN_OVERRIDEN
|
||||
#undef CDICT_CMP_FN_OVERRIDDEN
|
||||
#endif
|
21
programs/develop/obj2def/cvec/LICENSE
Normal file
21
programs/develop/obj2def/cvec/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Magomed Kostoev
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
88
programs/develop/obj2def/cvec/README.md
Normal file
88
programs/develop/obj2def/cvec/README.md
Normal file
@ -0,0 +1,88 @@
|
||||
# cvec - partial `std::vector` implementation in C.
|
||||
## Partial implementation of `std::vector`
|
||||
|
||||
Member functions table:
|
||||
|
||||
| Status | Name | Function or reason if not implemented |
|
||||
| :---: | --- | --- |
|
||||
| :heavy_check_mark: | `(constructor)` | `new` |
|
||||
| :heavy_check_mark: | `(destructor)` | `free` |
|
||||
| :heavy_check_mark: | `operator=` | `assign_other` |
|
||||
| :heavy_check_mark: | `assign` | `assign_fill`, `assign_range` |
|
||||
| :heavy_minus_sign: | `get_allocator` | No `allocator` objects in the language |
|
||||
| :heavy_check_mark: | `at` | `at` |
|
||||
| :heavy_check_mark: | `operator[]` | `[]` |
|
||||
| :heavy_check_mark: | `front` | `front`, `front_p` |
|
||||
| :heavy_check_mark: | `back` | `back`, `back_p` |
|
||||
| :heavy_check_mark: | `data` | `data` |
|
||||
| :heavy_check_mark: | `begin` | `begin` |
|
||||
| :heavy_check_mark: | `cbegin` | `cbegin` |
|
||||
| :heavy_check_mark: | `end` | `end` |
|
||||
| :heavy_check_mark: | `cend` | `cend` |
|
||||
| :heavy_minus_sign: | `rbegin` | No reverse iterators in the language |
|
||||
| :heavy_minus_sign: | `crbegin` | No reverse iterators in the language |
|
||||
| :heavy_minus_sign: | `rend` | No reverse iterators in the language |
|
||||
| :heavy_minus_sign: | `crend` | No reverse iterators in the language |
|
||||
| :heavy_check_mark: | `empty` | `empty` |
|
||||
| :heavy_check_mark: | `size` | `size` |
|
||||
| :heavy_check_mark: | `max_size` | `max_size` |
|
||||
| :heavy_check_mark: | `reserve` | `reserve` |
|
||||
| :heavy_check_mark: | `capacity` | `capacity` |
|
||||
| :heavy_check_mark: | `shrink_to_fit` | `shrink_to_fit` |
|
||||
| :heavy_check_mark: | `clear` | `clear` |
|
||||
| :heavy_check_mark: | `insert` | `insert`, `insert_it` |
|
||||
| :heavy_minus_sign: | `emplace` | I know no way to preserve the original signature |
|
||||
| :heavy_check_mark: | `erase` | `erase` |
|
||||
| :heavy_check_mark: | `push_back` | `push_back` |
|
||||
| :heavy_minus_sign: | `emplace_back` | I know no way to preserve the original signature |
|
||||
| :heavy_check_mark: | `pop_back` | `pop_back` |
|
||||
| :heavy_check_mark: | `resize` | `resize` |
|
||||
| :heavy_minus_sign: | `swap` | Would have n complexity in this implementation |
|
||||
|
||||
## Easy to use
|
||||
|
||||
To use the std::vector implementation for specified type they should be declared as follows:
|
||||
|
||||
```C
|
||||
#define CVEC_TYPE TypeOfVectorElement
|
||||
#include "cvec.h"
|
||||
|
||||
// ...
|
||||
|
||||
TypeOfVectorElement *vec = cvec_TypeOfVectorElement_new(128);
|
||||
|
||||
cvec_TypeOfVectorElement_push_back(&vec, value);
|
||||
```
|
||||
|
||||
Also somewhere in the project the functinos should be instantiated as follows:
|
||||
|
||||
```C
|
||||
#define CVEC_TYPE TypeOfVectorElement
|
||||
#define CVEC_INST
|
||||
#include "cvec.h"
|
||||
```
|
||||
|
||||
## Allows using of custom allocators.
|
||||
|
||||
```C
|
||||
#define CVEC_TYPE pchar
|
||||
#define CVEC_INST
|
||||
#define CVEC_MALLOC custom_malloc
|
||||
#define CVEC_REALLOC custom_realloc
|
||||
#define CVEC_FREE custom_free
|
||||
#include "cvec.h"
|
||||
```
|
||||
|
||||
## Allows handling of exceptional cases.
|
||||
|
||||
```C
|
||||
#define CVEC_TYPE pchar
|
||||
#define CVEC_INST
|
||||
// Set Out Of Bounds handler
|
||||
#define CVEC_OOBH(funcname, vec, index) printf("Out of bounds in %s (vec = %p, i = %d)", funcname, vec, index); abort();
|
||||
#include "cvec.h"
|
||||
```
|
||||
|
||||
## Has no fixed dependencies
|
||||
|
||||
Every function it uses may be overridden. More information about dependencies in [cvec.h](cvec.h).
|
498
programs/develop/obj2def/cvec/cvec.h
Normal file
498
programs/develop/obj2def/cvec/cvec.h
Normal file
@ -0,0 +1,498 @@
|
||||
// Copyright (c) 2015 Evan Teran
|
||||
// Copyright (c) 2020 Magomed Kostoev
|
||||
//
|
||||
// You may use, distribute and modify this code under the terms of the MIT license.
|
||||
//
|
||||
// You should have received a copy of the MIT license with this file. If not, please visit
|
||||
// https://opensource.org/licenses/MIT for full license details.
|
||||
|
||||
// cvec.h - std::vector (ish) implementation in C. Based on https://github.com/eteran/c-vector/.
|
||||
//
|
||||
// Unlike a real std::vector this one is implemented as a fat array, so metadata is placed inside
|
||||
// an allocated buffer itself.
|
||||
//
|
||||
// Configuration (definitions):
|
||||
// CVEC_TYPE: Type of the vector's elements, after instantiation these functions will be visible
|
||||
// as cvec_<CVEC_TYPE>_funcname, so no stars and subscripting marks allowed - named
|
||||
// types only
|
||||
// CVEC_INST: Instantiate the functions if defined
|
||||
// CVEC_LOGG: Multiply capacity by CVEC_LOGG each expansion if defined (should be >= 1)
|
||||
// CVEC_ASSERT: Replacement for assert from <assert.h>
|
||||
// CVEC_MALLOC: Replacement for malloc from <stdlib.h>
|
||||
// CVEC_REALLOC: Replacement for realloc from <stdlib.h>
|
||||
// CVEC_FREE: Replacement for free from <stdlib.h>
|
||||
// CVEC_OOBH: Out-of-bounds handler (gets __func__, vector data address and index of overflow)
|
||||
// CVEC_OOBVAL: Default value to return on out of bounds access
|
||||
//
|
||||
// Minimal definitions for declaration: CVEC_TYPE
|
||||
// Minimal definitions for instantiation: CVEC_TYPE, CVEC_INST, CVEC_OOBVAL if the type object
|
||||
// can't be represented by 0 value.
|
||||
//
|
||||
// WARNING: All used definitions will be undefined on header exit.
|
||||
//
|
||||
// Dependencies:
|
||||
// <stddef.h> or another source of size_t and ptrdiff_t
|
||||
// <stdint.h> or another source of SIZE_MAX
|
||||
// <stdlib.h> or another source of malloc, calloc and realloc
|
||||
// <assert.h> or another source of assert
|
||||
|
||||
//
|
||||
// Input macros
|
||||
//
|
||||
|
||||
#ifndef CVEC_LOGG
|
||||
# define CVEC_LOGG 1.5
|
||||
#endif
|
||||
#ifndef CVEC_ASSERT
|
||||
# define CVEC_ASSERT(x) assert(x)
|
||||
#endif
|
||||
#ifndef CVEC_MALLOC
|
||||
# define CVEC_MALLOC(size) malloc(size)
|
||||
#endif
|
||||
#ifndef CVEC_REALLOC
|
||||
# define CVEC_REALLOC(ptr, size) realloc(ptr, size)
|
||||
#endif
|
||||
#ifndef CVEC_FREE
|
||||
# define CVEC_FREE(size) free(size)
|
||||
#endif
|
||||
#ifndef CVEC_OOBH
|
||||
# define CVEC_OOBH(funcname, vec, index)
|
||||
#endif
|
||||
#ifndef CVEC_OOBVAL
|
||||
# define CVEC_OOBVAL { 0 }
|
||||
#endif
|
||||
|
||||
//
|
||||
// Internal macros
|
||||
//
|
||||
|
||||
#define CVEC_CONCAT2_IMPL(x, y) cvec_ ## x ## _ ## y
|
||||
#define CVEC_CONCAT2(x, y) CVEC_CONCAT2_IMPL(x, y)
|
||||
|
||||
/// Creates method name according to CVEC_TYPE
|
||||
#define CVEC_FUN(name) CVEC_CONCAT2(CVEC_TYPE, name)
|
||||
|
||||
#define cvec_x_new CVEC_FUN(new)
|
||||
#define cvec_x_capacity CVEC_FUN(capacity)
|
||||
#define cvec_x_size CVEC_FUN(size)
|
||||
#define cvec_x_empty CVEC_FUN(empty)
|
||||
#define cvec_x_pop_back CVEC_FUN(pop_back)
|
||||
#define cvec_x_erase CVEC_FUN(erase)
|
||||
#define cvec_x_free CVEC_FUN(free)
|
||||
#define cvec_x_begin CVEC_FUN(begin)
|
||||
#define cvec_x_cbegin CVEC_FUN(cbegin)
|
||||
#define cvec_x_end CVEC_FUN(end)
|
||||
#define cvec_x_cend CVEC_FUN(cend)
|
||||
#define cvec_x_push_back CVEC_FUN(push_back)
|
||||
#define cvec_x_at CVEC_FUN(at)
|
||||
#define cvec_x_reserve CVEC_FUN(reserve)
|
||||
#define cvec_x_shrink_to_fit CVEC_FUN(shrink_to_fit)
|
||||
#define cvec_x_assign_fill CVEC_FUN(assign_fill)
|
||||
#define cvec_x_assign_range CVEC_FUN(assign_range)
|
||||
#define cvec_x_assign_other CVEC_FUN(assign_other)
|
||||
#define cvec_x_data CVEC_FUN(data)
|
||||
#define cvec_x_resize CVEC_FUN(resize)
|
||||
#define cvec_x_resize_v CVEC_FUN(resize_v)
|
||||
#define cvec_x_clear CVEC_FUN(clear)
|
||||
#define cvec_x_front CVEC_FUN(front)
|
||||
#define cvec_x_front_p CVEC_FUN(front_p)
|
||||
#define cvec_x_back CVEC_FUN(back)
|
||||
#define cvec_x_back_p CVEC_FUN(back_p)
|
||||
#define cvec_x_max_size CVEC_FUN(max_size)
|
||||
#define cvec_x_insert CVEC_FUN(insert)
|
||||
#define cvec_x_insert_it CVEC_FUN(insert_it)
|
||||
|
||||
#define cvec_x_grow CVEC_FUN(grow)
|
||||
#define cvec_x_set_capacity CVEC_FUN(set_capacity)
|
||||
#define cvec_x_set_size CVEC_FUN(set_size)
|
||||
|
||||
//
|
||||
// External declarations
|
||||
//
|
||||
|
||||
/// Allocates new vector of specified capacity.
|
||||
CVEC_TYPE *cvec_x_new(size_t count);
|
||||
|
||||
/// Gets the current capacity of the vector.
|
||||
size_t cvec_x_capacity(CVEC_TYPE **vec);
|
||||
|
||||
/// Gets the current size of the vector.
|
||||
size_t cvec_x_size(CVEC_TYPE **vec);
|
||||
|
||||
/// Returns non-zero if the vector is empty.
|
||||
int cvec_x_empty(CVEC_TYPE **vec);
|
||||
|
||||
/// Removes the last element from the vector.
|
||||
void cvec_x_pop_back(CVEC_TYPE **vec);
|
||||
|
||||
/// Removes the element at index i from the vector.
|
||||
void cvec_x_erase(CVEC_TYPE **vec, size_t i);
|
||||
|
||||
/// Frees all memory associated with the vector.
|
||||
void cvec_x_free(CVEC_TYPE **vec);
|
||||
|
||||
/// Returns an iterator to first element of the vector.
|
||||
CVEC_TYPE *cvec_x_begin(CVEC_TYPE **vec);
|
||||
|
||||
/// Returns a const iterator to first element of the vector
|
||||
const CVEC_TYPE *cvec_x_cbegin(CVEC_TYPE **vec);
|
||||
|
||||
/// Returns an iterator to one past the last element of the vector.
|
||||
CVEC_TYPE *cvec_x_end(CVEC_TYPE **vec);
|
||||
|
||||
/// Returns a const iterator to one past the last element of the vector.
|
||||
const CVEC_TYPE *cvec_x_cend(CVEC_TYPE **vec);
|
||||
|
||||
/// Adds an element to the end of the vector.
|
||||
void cvec_x_push_back(CVEC_TYPE **vec, CVEC_TYPE value);
|
||||
|
||||
/// Gets element with bounds checking. On out of bounds calls CVEC_OOBH and returns CVEC_OOBVAL.
|
||||
CVEC_TYPE cvec_x_at(CVEC_TYPE **vec, size_t i);
|
||||
|
||||
/// Increases the capacity of the vector to a value that's equal to new_cap.
|
||||
void cvec_x_reserve(CVEC_TYPE **vec, size_t new_cap);
|
||||
|
||||
/// Requests the removal of unused capacity.
|
||||
void cvec_x_shrink_to_fit(CVEC_TYPE **vec);
|
||||
|
||||
/// Replaces the contents with count copies of value value.
|
||||
void cvec_x_assign_fill(CVEC_TYPE **vec, size_t count, CVEC_TYPE value);
|
||||
|
||||
/// Replaces the contents with data from range [first, last).
|
||||
void cvec_x_assign_range(CVEC_TYPE **vec, CVEC_TYPE *first, CVEC_TYPE *last);
|
||||
|
||||
/// Replaces the contents with contetns of other.
|
||||
void cvec_x_assign_other(CVEC_TYPE **vec, CVEC_TYPE **other);
|
||||
|
||||
/// Gives direct access to buffer.
|
||||
CVEC_TYPE *cvec_x_data(CVEC_TYPE **vec);
|
||||
|
||||
/// Resizes the container to contain count elements.
|
||||
void cvec_x_resize(CVEC_TYPE **vec, size_t new_size);
|
||||
|
||||
/// Resizes the container to contain count elements, initializes new elements by value.
|
||||
void cvec_x_resize_v(CVEC_TYPE **vec, size_t new_size, CVEC_TYPE value);
|
||||
|
||||
/// Erases all elements from the container.
|
||||
void cvec_x_clear(CVEC_TYPE **vec);
|
||||
|
||||
/// Returns the first element of the vector.
|
||||
CVEC_TYPE cvec_x_front(CVEC_TYPE **vec);
|
||||
|
||||
/// Returns a pointer to the first element of the vector.
|
||||
CVEC_TYPE *cvec_x_front_p(CVEC_TYPE **vec);
|
||||
|
||||
/// Returns the last element of the vector.
|
||||
CVEC_TYPE cvec_x_back(CVEC_TYPE **vec);
|
||||
|
||||
/// Returns a pointer to the last element of the vector.
|
||||
CVEC_TYPE *cvec_x_back_p(CVEC_TYPE **vec);
|
||||
|
||||
/// Returns maximal size of the vector.
|
||||
size_t cvec_x_max_size(CVEC_TYPE **vec);
|
||||
|
||||
/// Inserts a value into vector by index.
|
||||
CVEC_TYPE *cvec_x_insert(CVEC_TYPE **vec, size_t index, CVEC_TYPE value);
|
||||
|
||||
/// Inserts a value into vector by iterator (pointer in vector).
|
||||
CVEC_TYPE *cvec_x_insert_it(CVEC_TYPE **vec, CVEC_TYPE *it, CVEC_TYPE value);
|
||||
|
||||
//
|
||||
// Function definitions
|
||||
//
|
||||
|
||||
#ifdef CVEC_INST
|
||||
|
||||
/// Ensures that the vector is at least <count> elements big.
|
||||
static void cvec_x_grow(CVEC_TYPE **vec, size_t count);
|
||||
|
||||
/// Sets the capacity variable of the vector.
|
||||
static void cvec_x_set_capacity(CVEC_TYPE **vec, size_t size);
|
||||
|
||||
/// Sets the size variable of the vector.
|
||||
static void cvec_x_set_size(CVEC_TYPE **vec, size_t size);
|
||||
|
||||
//
|
||||
// Public functions
|
||||
//
|
||||
|
||||
CVEC_TYPE *cvec_x_new(size_t count) {
|
||||
const size_t cv_sz = count * sizeof(CVEC_TYPE) + sizeof(size_t) * 2;
|
||||
size_t *cv_p = CVEC_MALLOC(cv_sz);
|
||||
CVEC_ASSERT(cv_p);
|
||||
CVEC_TYPE *vec = (void *)(&cv_p[2]);
|
||||
cvec_x_set_capacity(&vec, count);
|
||||
cvec_x_set_size(&vec, 0);
|
||||
return vec;
|
||||
}
|
||||
|
||||
size_t cvec_x_capacity(CVEC_TYPE **vec) {
|
||||
CVEC_ASSERT(vec);
|
||||
return *vec ? ((size_t *)*vec)[-1] : (size_t)0;
|
||||
}
|
||||
|
||||
size_t cvec_x_size(CVEC_TYPE **vec) {
|
||||
CVEC_ASSERT(vec);
|
||||
return *vec ? ((size_t *)*vec)[-2] : (size_t)0;
|
||||
}
|
||||
|
||||
int cvec_x_empty(CVEC_TYPE **vec) {
|
||||
return cvec_x_size(vec) == 0;
|
||||
}
|
||||
|
||||
void cvec_x_pop_back(CVEC_TYPE **vec) {
|
||||
cvec_x_set_size(vec, cvec_x_size(vec) - 1);
|
||||
}
|
||||
|
||||
void cvec_x_erase(CVEC_TYPE **vec, size_t i) {
|
||||
CVEC_ASSERT(vec);
|
||||
if (*vec) {
|
||||
const size_t cv_sz = cvec_x_size(vec);
|
||||
if (i < cv_sz) {
|
||||
cvec_x_set_size(vec, cv_sz - 1);
|
||||
for (size_t cv_x = i; cv_x < (cv_sz - 1); ++cv_x) {
|
||||
(*vec)[cv_x] = (*vec)[cv_x + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cvec_x_free(CVEC_TYPE **vec) {
|
||||
CVEC_ASSERT(vec);
|
||||
if (*vec) {
|
||||
size_t *p1 = &((size_t *)*vec)[-2];
|
||||
CVEC_FREE(p1);
|
||||
}
|
||||
}
|
||||
|
||||
CVEC_TYPE *cvec_x_begin(CVEC_TYPE **vec) {
|
||||
CVEC_ASSERT(vec);
|
||||
return *vec;
|
||||
}
|
||||
|
||||
const CVEC_TYPE *cvec_x_cbegin(CVEC_TYPE **vec) {
|
||||
return cvec_x_begin(vec);
|
||||
}
|
||||
|
||||
CVEC_TYPE *cvec_x_end(CVEC_TYPE **vec) {
|
||||
CVEC_ASSERT(vec);
|
||||
return *vec ? &((*vec)[cvec_x_size(vec)]) : NULL;
|
||||
}
|
||||
|
||||
const CVEC_TYPE *cvec_x_cend(CVEC_TYPE **vec) {
|
||||
return cvec_x_end(vec);
|
||||
}
|
||||
|
||||
void cvec_x_push_back(CVEC_TYPE **vec, CVEC_TYPE value) {
|
||||
CVEC_ASSERT(vec);
|
||||
size_t cv_cap = cvec_x_capacity(vec);
|
||||
if (cv_cap <= cvec_x_size(vec)) {
|
||||
cvec_x_grow(vec, cv_cap * CVEC_LOGG + 1);
|
||||
}
|
||||
(*vec)[cvec_x_size(vec)] = value;
|
||||
cvec_x_set_size(vec, cvec_x_size(vec) + 1);
|
||||
}
|
||||
|
||||
CVEC_TYPE cvec_x_at(CVEC_TYPE **vec, size_t i) {
|
||||
CVEC_ASSERT(vec);
|
||||
if (i >= cvec_x_size(vec) || i < 0) {
|
||||
CVEC_OOBH(__func__, vec, i);
|
||||
CVEC_TYPE ret = CVEC_OOBVAL;
|
||||
return ret;
|
||||
}
|
||||
return (*vec)[i];
|
||||
}
|
||||
|
||||
void cvec_x_reserve(CVEC_TYPE **vec, size_t new_cap) {
|
||||
if (new_cap <= cvec_x_capacity(vec)) {
|
||||
return;
|
||||
}
|
||||
cvec_x_grow(vec, new_cap);
|
||||
}
|
||||
|
||||
void cvec_x_shrink_to_fit(CVEC_TYPE **vec) {
|
||||
if (cvec_x_capacity(vec) > cvec_x_size(vec)) {
|
||||
cvec_x_grow(vec, cvec_x_size(vec));
|
||||
}
|
||||
}
|
||||
|
||||
void cvec_x_assign_fill(CVEC_TYPE **vec, size_t count, CVEC_TYPE value) {
|
||||
CVEC_ASSERT(vec);
|
||||
cvec_x_reserve(vec, count);
|
||||
cvec_x_set_size(vec, count); // If the buffer was bigger than new_cap, set size ourselves
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
(*vec)[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void cvec_x_assign_range(CVEC_TYPE **vec, CVEC_TYPE *first, CVEC_TYPE *last) {
|
||||
CVEC_ASSERT(vec);
|
||||
size_t new_size = ((ptrdiff_t)(last - first)) / sizeof(*first);
|
||||
cvec_x_reserve(vec, new_size);
|
||||
cvec_x_set_size(vec, new_size);
|
||||
size_t i = 0;
|
||||
for (CVEC_TYPE *it = first; it < last; it++, i++) {
|
||||
(*vec)[i] = *it;
|
||||
}
|
||||
}
|
||||
|
||||
void cvec_x_assign_other(CVEC_TYPE **vec, CVEC_TYPE **other) {
|
||||
cvec_x_assign_range(vec, cvec_x_begin(other), cvec_x_end(other));
|
||||
}
|
||||
|
||||
CVEC_TYPE *cvec_x_data(CVEC_TYPE **vec) {
|
||||
CVEC_ASSERT(vec);
|
||||
return (*vec);
|
||||
}
|
||||
|
||||
void cvec_x_resize(CVEC_TYPE **vec, size_t count) {
|
||||
CVEC_TYPE value = { 0 };
|
||||
cvec_x_resize_v(vec, count, value);
|
||||
}
|
||||
|
||||
void cvec_x_resize_v(CVEC_TYPE **vec, size_t count, CVEC_TYPE value) {
|
||||
CVEC_ASSERT(vec);
|
||||
size_t old_size = cvec_x_size(vec);
|
||||
cvec_x_set_size(vec, count);
|
||||
if (cvec_x_capacity(vec) < count) {
|
||||
cvec_x_reserve(vec, count);
|
||||
for (CVEC_TYPE *it = (*vec) + old_size; it < cvec_x_end(vec); it++) {
|
||||
*it = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cvec_x_clear(CVEC_TYPE **vec) {
|
||||
cvec_x_set_size(vec, 0);
|
||||
}
|
||||
|
||||
CVEC_TYPE cvec_x_front(CVEC_TYPE **vec) {
|
||||
CVEC_ASSERT(vec);
|
||||
return (*vec)[0];
|
||||
}
|
||||
|
||||
CVEC_TYPE *cvec_x_front_p(CVEC_TYPE **vec) {
|
||||
CVEC_ASSERT(vec);
|
||||
return (*vec);
|
||||
}
|
||||
|
||||
CVEC_TYPE cvec_x_back(CVEC_TYPE **vec) {
|
||||
return cvec_x_end(vec)[-1];
|
||||
}
|
||||
|
||||
CVEC_TYPE *cvec_x_back_p(CVEC_TYPE **vec) {
|
||||
return cvec_x_end(vec) - 1;
|
||||
}
|
||||
|
||||
size_t cvec_x_max_size(CVEC_TYPE **vec) {
|
||||
return SIZE_MAX / sizeof(**vec);
|
||||
}
|
||||
|
||||
CVEC_TYPE *cvec_x_insert(CVEC_TYPE **vec, size_t index, CVEC_TYPE value) {
|
||||
CVEC_ASSERT(vec);
|
||||
if (index > cvec_x_size(vec) || index < 0) {
|
||||
return NULL; // TODO: What?
|
||||
}
|
||||
size_t new_size = cvec_x_size(vec) + 1;
|
||||
cvec_x_reserve(vec, new_size);
|
||||
cvec_x_set_size(vec, new_size);
|
||||
CVEC_TYPE *ret = *vec + index;
|
||||
for (CVEC_TYPE *it = cvec_x_back_p(vec); it > ret; it--) {
|
||||
*it = it[-1];
|
||||
}
|
||||
*ret = value;
|
||||
return ret;
|
||||
}
|
||||
|
||||
CVEC_TYPE *cvec_x_insert_it(CVEC_TYPE **vec, CVEC_TYPE *it, CVEC_TYPE value) {
|
||||
CVEC_ASSERT(vec);
|
||||
size_t index = (it - *vec) / sizeof(**vec);
|
||||
return cvec_x_insert(vec, index, value);
|
||||
}
|
||||
|
||||
//
|
||||
// Private functions
|
||||
//
|
||||
|
||||
static void cvec_x_set_capacity(CVEC_TYPE **vec, size_t size) {
|
||||
CVEC_ASSERT(vec);
|
||||
if (*vec) {
|
||||
((size_t *)*vec)[-1] = size;
|
||||
}
|
||||
}
|
||||
|
||||
static void cvec_x_set_size(CVEC_TYPE **vec, size_t size) {
|
||||
CVEC_ASSERT(vec);
|
||||
if (*vec) {
|
||||
((size_t *)*vec)[-2] = size;
|
||||
}
|
||||
}
|
||||
|
||||
static void cvec_x_grow(CVEC_TYPE **vec, size_t count) {
|
||||
CVEC_ASSERT(vec);
|
||||
const size_t cv_sz = count * sizeof(**vec) + sizeof(size_t) * 2;
|
||||
size_t *cv_p1 = &((size_t *)*vec)[-2];
|
||||
size_t *cv_p2 = CVEC_REALLOC(cv_p1, (cv_sz));
|
||||
CVEC_ASSERT(cv_p2);
|
||||
*vec = (void *)(&cv_p2[2]);
|
||||
cvec_x_set_capacity(vec, count);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#undef CVEC_TYPE
|
||||
|
||||
#ifdef CVEC_INST
|
||||
# undef CVEC_INST
|
||||
# ifdef CVEC_LOGG
|
||||
# undef CVEC_LOGG
|
||||
# endif
|
||||
# ifdef CVEC_OOBH
|
||||
# undef CVEC_OOBH
|
||||
# endif
|
||||
# ifdef CVEC_OOBVAL
|
||||
# undef CVEC_OOBVAL
|
||||
# endif
|
||||
# undef CVEC_ASSERT
|
||||
# undef CVEC_MALLOC
|
||||
# undef CVEC_REALLOC
|
||||
# undef CVEC_FREE
|
||||
#endif
|
||||
|
||||
#undef CVEC_CONCAT2_IMPL
|
||||
#undef CVEC_CONCAT2
|
||||
|
||||
#undef CVEC_FUN
|
||||
|
||||
#undef cvec_x_new
|
||||
#undef cvec_x_capacity
|
||||
#undef cvec_x_size
|
||||
#undef cvec_x_empty
|
||||
#undef cvec_x_pop_back
|
||||
#undef cvec_x_erase
|
||||
#undef cvec_x_free
|
||||
#undef cvec_x_begin
|
||||
#undef cvec_x_cbegin
|
||||
#undef cvec_x_end
|
||||
#undef cvec_x_cend
|
||||
#undef cvec_x_push_back
|
||||
#undef cvec_x_at
|
||||
#undef cvec_x_reserve
|
||||
#undef cvec_x_shrink_to_fit
|
||||
#undef cvec_x_assign_fill
|
||||
#undef cvec_x_assign_range
|
||||
#undef cvec_x_assign_other
|
||||
#undef cvec_x_data
|
||||
#undef cvec_x_resize
|
||||
#undef cvec_x_resize_v
|
||||
#undef cvec_x_clear
|
||||
#undef cvec_x_front
|
||||
#undef cvec_x_front_p
|
||||
#undef cvec_x_back
|
||||
#undef cvec_x_back_p
|
||||
#undef cvec_x_max_size
|
||||
#undef cvec_x_insert
|
||||
#undef cvec_x_insert_it
|
||||
#undef cvec_x_grow
|
||||
#undef cvec_x_set_capacity
|
||||
#undef cvec_x_set_size
|
21
programs/develop/obj2def/epep/LICENSE
Normal file
21
programs/develop/obj2def/epep/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Magomed Kostoev
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
26
programs/develop/obj2def/epep/README.md
Normal file
26
programs/develop/obj2def/epep/README.md
Normal file
@ -0,0 +1,26 @@
|
||||
# epep - Embeddable PE Parser
|
||||
## Features
|
||||
|
||||
- PE header (including Data Directories as a part Optional Header)
|
||||
- Section Headers
|
||||
- COFF Symbols
|
||||
- COFF Relocations
|
||||
- COFF Linenumbers
|
||||
- Imports
|
||||
- Exports
|
||||
- Base relocations (DLL)
|
||||
|
||||
## How to use
|
||||
|
||||
To declare functions from the library include it:
|
||||
|
||||
```C
|
||||
#include "epep.h"
|
||||
```
|
||||
|
||||
The functions they shoud be instantiated somewhere in the project like so:
|
||||
|
||||
```C
|
||||
#define EPEP_INST
|
||||
#include "epep.h"
|
||||
```
|
1022
programs/develop/obj2def/epep/epep.h
Normal file
1022
programs/develop/obj2def/epep/epep.h
Normal file
File diff suppressed because it is too large
Load Diff
265
programs/develop/obj2def/main.c
Normal file
265
programs/develop/obj2def/main.c
Normal file
@ -0,0 +1,265 @@
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#define EPEP_INST
|
||||
#include "epep/epep.h"
|
||||
|
||||
const char *epep_errors[] = {
|
||||
"EPEP_ERR_SUCCESS",
|
||||
"EPEP_ERR_DATA_DIRECTORY_INDEX_IS_INVALID",
|
||||
"EPEP_ERR_SECTION_HEADER_INDEX_IS_INVALID",
|
||||
"EPEP_ERR_SYMBOL_INDEX_IS_INVALID",
|
||||
"EPEP_ERR_NOT_AN_OBJECT",
|
||||
"EPEP_ERR_ADDRESS_IS_OUT_OF_SECTION_RAW_DATA",
|
||||
"EPEP_ERR_OUTPUT_CAPACITY_IS_ZERO",
|
||||
"EPEP_ERR_OUTPUT_IS_NULL",
|
||||
"EPEP_ERR_ADDRESS_IS_OUT_OF_ANY_SECTION",
|
||||
"EPEP_ERR_EXPORT_ADDRESS_TABLE_ENTRY_NAME_NOT_FOUND",
|
||||
"EPEP_ERR_NO_BASE_RELOCATION_TABLE",
|
||||
"EPEP_ERR_BASE_RELOCATION_IS_ALREADY_END",
|
||||
"EPEP_ERR_INVALID_DATA_DIRECTORY_OFFSET",
|
||||
"EPEP_ERR_INVALID_SECTION_HEADER_OFFSET",
|
||||
"EPEP_ERR_INVALID_SECTION_DATA_OFFSET",
|
||||
"EPEP_ERR_INVALID_STRING_TABLE_SIZE_OFFSET",
|
||||
"EPEP_ERR_INVALID_SYMBOL_OFFSET",
|
||||
"EPEP_ERR_INVALID_IMPORT_DIRECTORY_OFFSET",
|
||||
"EPEP_ERR_INVALID_IMPORT_DIRECTORY_NAME_OFFSET",
|
||||
"EPEP_ERR_INVALID_LOOKUP_OFFSET",
|
||||
"EPEP_ERR_INVALID_LOOKUP_NAME_OFFSET",
|
||||
"EPEP_ERR_INVALID_EXPORT_TABLE_OFFSET",
|
||||
"EPEP_ERR_INVALID_DLL_NAME_OFFSET",
|
||||
"EPEP_ERR_INVALID_EXPORT_NAME_POINTER_OFFSET",
|
||||
"EPEP_ERR_INVALID_ORDINAL_TABLE_OFFSET",
|
||||
"EPEP_ERR_INVALID_EXPORT_NAME_OFFSET",
|
||||
"EPEP_ERR_INVALID_EXPORT_ADDRESS_OFFSET",
|
||||
"EPEP_ERR_INVALID_FORWARDER_OFFSET",
|
||||
"EPEP_ERR_INVALID_BASE_RELOCATION_BLOCK_OFFSET",
|
||||
"EPEP_ERR_INVALID_NEXT_BASE_RELOCATION_BLOCK_OFFSET",
|
||||
"EPEP_ERR_INVALID_BASE_RELOCATION_BLOCK_BASE_RELOCATION_OFFSET",
|
||||
"EPEP_ERR_INVALID_SECTION_RELOCATION_OFFSET",
|
||||
"EPEP_ERR_INVALID_LINENUMBER_OFFSET",
|
||||
};
|
||||
|
||||
#define ERROR_EPEP(epep) printf("Error: epep returned %u (%s) at "__FILE__":%u", \
|
||||
(epep)->error_code, epep_errors[(epep)->error_code], __LINE__); exit(-1)
|
||||
|
||||
static int emit_logs;
|
||||
static void log_info(const char *fmt, ...) {
|
||||
if (emit_logs) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t get32(const char *buf, size_t offset) {
|
||||
return ((uint32_t)(uint8_t)buf[offset + 0] << 0)
|
||||
| ((uint32_t)(uint8_t)buf[offset + 1] << 8)
|
||||
| ((uint32_t)(uint8_t)buf[offset + 2] << 16)
|
||||
| ((uint32_t)(uint8_t)buf[offset + 3] << 24);
|
||||
}
|
||||
|
||||
EpepCoffRelocation get_relocation_for_section_and_offset(Epep *epep, EpepSectionHeader *sh, size_t offset) {
|
||||
EpepCoffRelocation rel = { 0 };
|
||||
for (size_t i = 0; i < sh->NumberOfRelocations; i++) {
|
||||
if (!epep_get_section_relocation_by_index(epep, sh, &rel, i)) {
|
||||
ERROR_EPEP(epep);
|
||||
}
|
||||
if (rel.VirtualAddress == offset) {
|
||||
return rel;
|
||||
}
|
||||
}
|
||||
printf("Error: Can't find relocation of pointer to name of symbol");
|
||||
exit(-1);
|
||||
return rel;
|
||||
}
|
||||
|
||||
char *read_string(Epep *epep, size_t section_index, size_t offset) {
|
||||
EpepSectionHeader sh = { 0 };
|
||||
if (!epep_get_section_header_by_index(epep, &sh, section_index)) {
|
||||
ERROR_EPEP(epep);
|
||||
}
|
||||
char *section = calloc(1, sh.SizeOfRawData);
|
||||
if (!epep_get_section_contents(epep, &sh, section)) {
|
||||
ERROR_EPEP(epep);
|
||||
}
|
||||
char *result = strdup(§ion[offset]);
|
||||
free(section);
|
||||
return result;
|
||||
}
|
||||
|
||||
int gendef(const char *obj_path, const char *outname) {
|
||||
FILE *out = fopen(outname, "wb");
|
||||
Epep epep;
|
||||
{
|
||||
FILE *fp = fopen(obj_path, "rb");
|
||||
if (!fp) {
|
||||
printf("Error: Can't open \"%s\"", obj_path);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (!epep_init(&epep, fp)) {
|
||||
ERROR_EPEP(&epep);
|
||||
}
|
||||
}
|
||||
|
||||
size_t strtab_size = 0;
|
||||
if (!epep_get_string_table_size(&epep, &strtab_size)) {
|
||||
ERROR_EPEP(&epep);
|
||||
}
|
||||
|
||||
char *strtab = malloc(strtab_size);
|
||||
if (!epep_get_string_table(&epep, strtab)) {
|
||||
ERROR_EPEP(&epep);
|
||||
}
|
||||
|
||||
for (size_t sym_i = 0; sym_i < epep.coffFileHeader.NumberOfSymbols; sym_i++) {
|
||||
EpepCoffSymbol sym = { 0 };
|
||||
|
||||
if (!epep_get_symbol_by_index(&epep, &sym, sym_i)) {
|
||||
ERROR_EPEP(&epep);
|
||||
}
|
||||
|
||||
size_t name_max = 1024;
|
||||
char name[name_max];
|
||||
|
||||
if (sym.symbol.Zeroes == 0) {
|
||||
strcpy(name, &strtab[sym.symbol.Offset]);
|
||||
} else {
|
||||
memcpy(name, sym.symbol.ShortName, 8);
|
||||
name[8] = '\0';
|
||||
}
|
||||
|
||||
if (!strcmp(name, "_EXPORTS") || !strcmp(name, "EXPORTS")) {
|
||||
fprintf(out, "LIBRARY %s\n\nEXPORTS\n", obj_path);
|
||||
|
||||
size_t export_table_offset_in_section = sym.symbol.Value;
|
||||
size_t section_index = sym.symbol.SectionNumber - 1;
|
||||
EpepSectionHeader sh = { 0 };
|
||||
if (!epep_get_section_header_by_index(&epep, &sh, section_index)) {
|
||||
ERROR_EPEP(&epep);
|
||||
}
|
||||
size_t section_offset = sh.PointerToRawData;
|
||||
size_t export_table_offset = section_offset + export_table_offset_in_section;
|
||||
|
||||
char *section = calloc(1, sh.SizeOfRawData);
|
||||
if (!epep_get_section_contents(&epep, &sh, section)) {
|
||||
ERROR_EPEP(&epep);
|
||||
}
|
||||
|
||||
for (size_t offset = export_table_offset_in_section;; offset += 8) {
|
||||
size_t name_offset = get32(section, offset);
|
||||
size_t data_offset = get32(section, offset + 4);
|
||||
|
||||
if (name_offset == 0 || data_offset == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
EpepCoffRelocation rel = get_relocation_for_section_and_offset(&epep, &sh, offset);
|
||||
EpepCoffSymbol name_sym = { 0 };
|
||||
if (!epep_get_symbol_by_index(&epep, &name_sym, rel.SymbolTableIndex)) {
|
||||
ERROR_EPEP(&epep);
|
||||
}
|
||||
size_t name_offset_in_section = name_sym.symbol.Value + name_offset;
|
||||
char *name = read_string(&epep, name_sym.symbol.SectionNumber - 1, name_offset_in_section);
|
||||
fprintf(out, "%s\n", name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
sym_i += sym.symbol.NumberOfAuxSymbols;
|
||||
}
|
||||
}
|
||||
|
||||
int arg_got_flag(int argc, char **argv, ...) {
|
||||
char *arg_names[8];
|
||||
int arg_name_c = 0;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, argv);
|
||||
for (char *arg_name = va_arg(ap, char *); arg_name; arg_name = va_arg(ap, char *)) {
|
||||
if (arg_name_c >= 8) {
|
||||
printf("Internal error: Too many parameter aliases passed to %s", __func__);
|
||||
exit(-1);
|
||||
}
|
||||
arg_names[arg_name_c++] = arg_name;
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
// If an argumetns was handled already then it's NULL here
|
||||
if (argv[i] == NULL) {
|
||||
continue;
|
||||
}
|
||||
for (int arg_name_i = 0; arg_name_i < arg_name_c; arg_name_i++) {
|
||||
char *arg_name = arg_names[arg_name_i];
|
||||
if (!strcmp(argv[i], arg_name)) {
|
||||
argv[i] = NULL; // Do not handle this argument as a input name
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *arg_got_param(int argc, char **argv, char *arg) {
|
||||
int i = arg_got_flag(argc, argv, arg, 0);
|
||||
if (i == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (i + 1 >= argc) {
|
||||
printf("Warning: %s parameter expects a value (like %s <value>)", arg, arg);
|
||||
return NULL;
|
||||
}
|
||||
char *result = argv[i + 1];
|
||||
argv[i + 1] = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
int usage(char *name, char *remark) {
|
||||
if (remark) {
|
||||
printf("Error: %s\n\n", remark);
|
||||
}
|
||||
printf("Usage: %s [option]... [object file name]...\n", name);
|
||||
printf(" Generate DEF files from COFF objects\n");
|
||||
printf("\n");
|
||||
printf("Options:\n");
|
||||
printf(" -v, --verbose Emit information logs\n");
|
||||
printf(" -h, --help Output this help and exit\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (arg_got_flag(argc, argv, "-h", "-help", "--help", 0)) {
|
||||
return usage(argv[0], NULL);
|
||||
}
|
||||
|
||||
emit_logs = arg_got_flag(argc, argv, "-v", "-verbose", "--verbose", 0);
|
||||
|
||||
// After handling arguments there only leaven unhandled ones
|
||||
// They should be names if inputs. But if there's no input - exit
|
||||
int input_file_count = 0;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (argv[i] != NULL) {
|
||||
input_file_count++;
|
||||
}
|
||||
}
|
||||
if (input_file_count == 0) {
|
||||
return usage(argv[0], "No input file names supplied");
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < argc; i++) {
|
||||
char outname[256] = { 0 };
|
||||
sprintf(outname, "%.*s.def", strlen(argv[i]) - strlen(".obj"), argv[i]);
|
||||
if (argv[i] != NULL) {
|
||||
gendef(argv[i], outname);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user