init
This commit is contained in:
commit
32ef62bd20
11 changed files with 2354 additions and 0 deletions
20
.clang-format
Normal file
20
.clang-format
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
Language: Cpp
|
||||
UseTab: Always
|
||||
TabWidth: 8
|
||||
AlignConsecutiveAssignments:
|
||||
Enabled: true
|
||||
AlignConsecutiveDeclarations:
|
||||
Enabled: true
|
||||
IndentWidth: 8
|
||||
PointerAlignment: Left
|
||||
ColumnLimit: 0
|
||||
AllowShortIfStatementsOnASingleLine: Always
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
SpaceBeforeParens: Never
|
||||
AlignEscapedNewlines: DontAlign
|
||||
SortIncludes: false
|
||||
AllowShortEnumsOnASingleLine: false
|
||||
#IndentPPDirectives: AfterHash
|
||||
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
*.o
|
||||
*.so
|
||||
*.dll
|
||||
*.core
|
||||
/example
|
||||
24
LICENSE
Normal file
24
LICENSE
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
Copyright (c) 2025, Pyrite development team
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of the <organization> nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
28
Makefile
Normal file
28
Makefile
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
CC = gcc
|
||||
CFLAGS = -I include -fPIC
|
||||
LDFLAGS = -shared
|
||||
LIBS =
|
||||
|
||||
OBJS = src/core.o src/file.o src/unicode.o src/stb_ds.o
|
||||
|
||||
SO = .so
|
||||
|
||||
.PHONY: all format clean
|
||||
.SUFFIXES: .c .o
|
||||
|
||||
all: libxmllib$(SO)
|
||||
|
||||
format:
|
||||
clang-format --verbose -i `find src include -name "*.c" -or -name "*.h"`
|
||||
|
||||
example: example.c libxmllib$(SO)
|
||||
$(CC) -o $@ example.c -I include -Wl,-R. -L. -lxmllib
|
||||
|
||||
libxmllib$(SO): $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
|
||||
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f src/*.o *.so *.dll
|
||||
31
example.c
Normal file
31
example.c
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#include <xmllib.h>
|
||||
|
||||
void recursive(xmllib_node_t* node, int indent){
|
||||
int i;
|
||||
xmllib_node_t* n;
|
||||
for(i = 0; i < indent; i++) printf(" ");
|
||||
printf("%s\n", node->name);
|
||||
|
||||
n = node->first_child;
|
||||
while(n != NULL){
|
||||
recursive(n, indent + 2);
|
||||
n = n->next;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv){
|
||||
int i;
|
||||
|
||||
for(i = 1; i < argc; i++){
|
||||
xmllib_t* h = xmllib_open_file(argv[i]);
|
||||
if(h != NULL){
|
||||
printf("%s:\n", argv[i]);
|
||||
if(xmllib_parse(h)){
|
||||
if(h->root != NULL) recursive(h->root, 2);
|
||||
}else{
|
||||
printf(" Parse error\n");
|
||||
}
|
||||
xmllib_close(h);
|
||||
}
|
||||
}
|
||||
}
|
||||
1895
external/stb_ds.h
vendored
Normal file
1895
external/stb_ds.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
76
include/xmllib.h
Normal file
76
include/xmllib.h
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
#ifndef __XMLLIB_H__
|
||||
#define __XMLLIB_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#define XLDECL extern
|
||||
|
||||
typedef struct xmllib_driver xmllib_driver_t;
|
||||
typedef struct xmllib xmllib_t;
|
||||
typedef struct xmllib_node xmllib_node_t;
|
||||
|
||||
struct xmllib_driver {
|
||||
int (*open)(xmllib_t* handle);
|
||||
int (*read)(xmllib_t* handle, void* data, int size);
|
||||
void (*close)(xmllib_t* handle);
|
||||
};
|
||||
|
||||
enum XMLLIB_NODE_TYPE {
|
||||
XMLLIB_NODE_COMMENT = 0,
|
||||
XMLLIB_NODE_NODE,
|
||||
XMLLIB_NODE_PROCESS,
|
||||
XMLLIB_NODE_DOCTYPE
|
||||
};
|
||||
|
||||
struct xmllib_node {
|
||||
int type;
|
||||
char* name;
|
||||
char* text;
|
||||
|
||||
xmllib_node_t* root;
|
||||
xmllib_node_t* parent;
|
||||
|
||||
xmllib_node_t* first_child;
|
||||
|
||||
xmllib_node_t* prev;
|
||||
xmllib_node_t* next;
|
||||
};
|
||||
|
||||
struct xmllib {
|
||||
xmllib_driver_t* driver;
|
||||
void* drv_opaque;
|
||||
void* drv_arg;
|
||||
xmllib_node_t* root;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* core.c */
|
||||
XLDECL xmllib_t* xmllib_open(xmllib_driver_t* driver, void* arg);
|
||||
|
||||
XLDECL int xmllib_parse(xmllib_t* handle);
|
||||
|
||||
XLDECL void xmllib_close(xmllib_t* handle);
|
||||
|
||||
/* file.c */
|
||||
XLDECL xmllib_driver_t* xmllib_driver_file;
|
||||
|
||||
XLDECL xmllib_t* xmllib_open_file(const char* filename);
|
||||
|
||||
/* unicode.c */
|
||||
XLDECL int xmllib_unicode_count(unsigned char c);
|
||||
|
||||
XLDECL int xmllib_unicode_8_to_32(const char* input, int* output);
|
||||
|
||||
XLDECL int xmllib_unicode_32_to_8(const int input, char* output);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
168
src/core.c
Normal file
168
src/core.c
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
#include <xmllib.h>
|
||||
|
||||
#include "../external/stb_ds.h"
|
||||
|
||||
xmllib_t* xmllib_open(xmllib_driver_t* driver, void* arg) {
|
||||
xmllib_t* handle = malloc(sizeof(*handle));
|
||||
memset(handle, 0, sizeof(*handle));
|
||||
|
||||
handle->driver = driver;
|
||||
handle->drv_arg = arg;
|
||||
|
||||
if(!handle->driver->open(handle)) {
|
||||
free(handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
enum STATES {
|
||||
STATE_INITIAL = 0,
|
||||
STATE_TAG,
|
||||
STATE_STRING,
|
||||
STATE_SPECIAL,
|
||||
STATE_COMMENT,
|
||||
STATE_DOCTYPE,
|
||||
};
|
||||
|
||||
#define TAKE_AS_NODE(x) \
|
||||
{ \
|
||||
char* old = node; \
|
||||
char buf[4]; \
|
||||
int new = xmllib_unicode_32_to_8((x), buf); \
|
||||
\
|
||||
node = malloc(strlen(old) + new + 1); \
|
||||
strcpy(node, old); \
|
||||
memcpy(node + strlen(old), buf, new); \
|
||||
node[strlen(old) + new] = 0; \
|
||||
node_count++; \
|
||||
}
|
||||
|
||||
#define CLEANUP \
|
||||
{ \
|
||||
if(node != NULL) free(node); \
|
||||
arrfree(state); \
|
||||
}
|
||||
|
||||
#define ERROR \
|
||||
{ \
|
||||
printf("%d\n", __LINE__); \
|
||||
CLEANUP; \
|
||||
longjmp(err, 1); \
|
||||
}
|
||||
|
||||
#define STATE state[arrlen(state) - 1]
|
||||
|
||||
int xmllib_parse(xmllib_t* handle) {
|
||||
jmp_buf err;
|
||||
int* state = NULL;
|
||||
char* node = NULL;
|
||||
int node_count = 0;
|
||||
int nest_level = 0;
|
||||
|
||||
if(setjmp(err)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
arrput(state, STATE_INITIAL);
|
||||
|
||||
while(1) {
|
||||
char in[4];
|
||||
int c;
|
||||
int cp;
|
||||
|
||||
if(handle->driver->read(handle, &in[0], 1) < 1) ERROR;
|
||||
|
||||
c = xmllib_unicode_count(in[0]);
|
||||
if((c > 1) && handle->driver->read(handle, &in[1], c - 1) < (c - 1)) longjmp(err, 1);
|
||||
|
||||
xmllib_unicode_8_to_32(in, &cp);
|
||||
|
||||
if(cp == '<' && STATE != STATE_COMMENT && STATE != STATE_DOCTYPE) {
|
||||
if(STATE == STATE_INITIAL) {
|
||||
arrput(state, STATE_TAG);
|
||||
|
||||
node = malloc(1);
|
||||
node[0] = 0;
|
||||
node_count = 0;
|
||||
} else if(STATE == STATE_STRING) {
|
||||
TAKE_AS_NODE(cp);
|
||||
} else {
|
||||
ERROR;
|
||||
}
|
||||
} else if(cp == '>') {
|
||||
if(STATE == STATE_TAG || STATE == STATE_DOCTYPE || STATE == STATE_COMMENT) {
|
||||
if((STATE != STATE_COMMENT || node[strlen(node) - 1] == '-') && (STATE != STATE_DOCTYPE || node[strlen(node) - 1] == ']')) {
|
||||
arrpop(state);
|
||||
|
||||
if(STATE == STATE_INITIAL) {
|
||||
/* parsed tag */
|
||||
|
||||
if(node[0] == '!') {
|
||||
/* special tag */
|
||||
if(strlen(node) > 1 && node[1] == '-') {
|
||||
/* comment */
|
||||
} else {
|
||||
/* doctype or something - we ignore this for now */
|
||||
}
|
||||
} else if(node[0] == '?') {
|
||||
/* process */
|
||||
} else {
|
||||
/* normal tag */
|
||||
if(node[0] == '/') {
|
||||
/* close tag */
|
||||
|
||||
nest_level--;
|
||||
} else if(node[strlen(node) - 1] == '/') {
|
||||
/* self-closing tag */
|
||||
|
||||
nest_level++;
|
||||
}
|
||||
|
||||
if(nest_level < 0) ERROR;
|
||||
if(nest_level == 0) break;
|
||||
}
|
||||
|
||||
free(node);
|
||||
node = NULL;
|
||||
}
|
||||
} else {
|
||||
TAKE_AS_NODE(cp);
|
||||
}
|
||||
} else if(STATE == STATE_STRING) {
|
||||
TAKE_AS_NODE(cp);
|
||||
} else {
|
||||
ERROR;
|
||||
}
|
||||
} else if(cp == '"' && STATE != STATE_COMMENT && STATE != STATE_DOCTYPE) {
|
||||
if(STATE == STATE_TAG) {
|
||||
arrput(state, STATE_STRING);
|
||||
} else if(STATE == STATE_STRING) {
|
||||
arrpop(state);
|
||||
}
|
||||
TAKE_AS_NODE(cp);
|
||||
} else if(STATE == STATE_TAG || STATE == STATE_STRING || STATE == STATE_SPECIAL || STATE == STATE_COMMENT || STATE == STATE_DOCTYPE) {
|
||||
if(node_count == 0 && cp == '!') {
|
||||
arrpop(state);
|
||||
arrput(state, STATE_SPECIAL);
|
||||
} else if(node_count == 1 && STATE == STATE_SPECIAL && cp == '-') {
|
||||
arrpop(state);
|
||||
arrput(state, STATE_COMMENT);
|
||||
} else if(node_count == 1 && STATE == STATE_SPECIAL) {
|
||||
arrpop(state);
|
||||
arrput(state, STATE_DOCTYPE);
|
||||
}
|
||||
TAKE_AS_NODE(cp);
|
||||
}
|
||||
}
|
||||
|
||||
CLEANUP;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void xmllib_close(xmllib_t* handle) {
|
||||
handle->driver->close(handle);
|
||||
free(handle);
|
||||
}
|
||||
26
src/file.c
Normal file
26
src/file.c
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#include <xmllib.h>
|
||||
|
||||
static int xmllib_driver_file_open(xmllib_t* handle) {
|
||||
if((handle->drv_opaque = fopen(handle->drv_arg, "rb")) == NULL) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int xmllib_driver_file_read(xmllib_t* handle, void* data, int size) {
|
||||
return fread(data, 1, size, handle->drv_opaque);
|
||||
}
|
||||
|
||||
static void xmllib_driver_file_close(xmllib_t* handle) {
|
||||
fclose(handle->drv_opaque);
|
||||
}
|
||||
|
||||
xmllib_driver_t xmllib_driver_file_rec = {
|
||||
xmllib_driver_file_open,
|
||||
xmllib_driver_file_read,
|
||||
xmllib_driver_file_close,
|
||||
};
|
||||
xmllib_driver_t* xmllib_driver_file = &xmllib_driver_file_rec;
|
||||
|
||||
xmllib_t* xmllib_open_file(const char* filename) {
|
||||
return xmllib_open(xmllib_driver_file, (void*)filename);
|
||||
}
|
||||
2
src/stb_ds.c
Normal file
2
src/stb_ds.c
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#define STB_DS_IMPLEMENTATION
|
||||
#include "../external/stb_ds.h"
|
||||
79
src/unicode.c
Normal file
79
src/unicode.c
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
#include <xmllib.h>
|
||||
|
||||
#define CAST_I32(x) ((int)(x))
|
||||
|
||||
int xmllib_unicode_count(unsigned char c) {
|
||||
if(c < 0x80) {
|
||||
return 1;
|
||||
}
|
||||
if(0xc2 <= c && c < 0xe0) {
|
||||
return 2;
|
||||
}
|
||||
if(0xe0 <= c && c < 0xf0) {
|
||||
return 3;
|
||||
}
|
||||
if(0xf0 <= c && c < 0xf8) {
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unicode_later(unsigned char c) {
|
||||
return 0x80 <= c && c < 0xc0;
|
||||
}
|
||||
|
||||
int xmllib_unicode_8_to_32(const char* input, int* output) {
|
||||
const unsigned char* inbuf = (const unsigned char*)input;
|
||||
int b = xmllib_unicode_count(inbuf[0]);
|
||||
if(b == 0) return 0;
|
||||
|
||||
if(b == 1) *output = inbuf[0];
|
||||
if(b == 2) {
|
||||
if(!unicode_later(inbuf[1])) return 0;
|
||||
if((inbuf[0] & 0x1e) == 0) return 0;
|
||||
|
||||
*output = CAST_I32(inbuf[0] & 0x1f) << 6;
|
||||
*output |= CAST_I32(inbuf[1] & 0x3f);
|
||||
}
|
||||
if(b == 3) {
|
||||
if(!unicode_later(inbuf[1]) || !unicode_later(inbuf[2])) return 0;
|
||||
if((inbuf[0] & 0x0f) == 0 && (inbuf[1] & 0x20) == 0) return 0;
|
||||
|
||||
*output = CAST_I32(inbuf[0] & 0x0f) << 12;
|
||||
*output |= CAST_I32(inbuf[1] & 0x3f) << 6;
|
||||
*output |= CAST_I32(inbuf[2] & 0x3f);
|
||||
}
|
||||
if(b == 4) {
|
||||
if(!unicode_later(inbuf[1]) || !unicode_later(inbuf[2]) || !unicode_later(inbuf[3])) return 0;
|
||||
if((inbuf[0] & 0x07) == 0 && (inbuf[1] & 0x30) == 0) return 0;
|
||||
|
||||
*output = CAST_I32(inbuf[0] & 0x07) << 18;
|
||||
*output |= CAST_I32(inbuf[1] & 0x3f) << 12;
|
||||
*output |= CAST_I32(inbuf[2] & 0x3f) << 6;
|
||||
*output |= CAST_I32(inbuf[3] & 0x3f);
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
int xmllib_unicode_32_to_8(const int input, char* output) {
|
||||
if(input < 128) {
|
||||
output[0] = input;
|
||||
return 1;
|
||||
} else if(input < 2048) {
|
||||
output[0] = 0xc0 | (input >> 6);
|
||||
output[1] = 0x80 | (input & 0x3f);
|
||||
return 2;
|
||||
} else if(input < 65536) {
|
||||
output[0] = 0xe0 | (input >> 12);
|
||||
output[1] = 0x80 | ((input >> 6) & 0x3f);
|
||||
output[2] = 0x80 | (input & 0x3f);
|
||||
return 3;
|
||||
} else {
|
||||
output[0] = 0xf0 | (input >> 18);
|
||||
output[1] = 0x80 | ((input >> 12) & 0x3f);
|
||||
output[2] = 0x80 | ((input >> 6) & 0x3f);
|
||||
output[3] = 0x80 | (input & 0x3f);
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue