mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 23:04:08 +10:00
Packaged toy as a dll
This commit is contained in:
6
makefile
6
makefile
@@ -3,6 +3,12 @@ export OUTDIR = out
|
||||
all: $(OUTDIR)
|
||||
$(MAKE) -C source
|
||||
|
||||
library: clean $(OUTDIR)
|
||||
$(MAKE) -C source library
|
||||
|
||||
static: clean $(OUTDIR)
|
||||
$(MAKE) -C source static
|
||||
|
||||
test: clean $(OUTDIR)
|
||||
$(MAKE) -C test
|
||||
|
||||
|
||||
@@ -2,6 +2,20 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
//test variable sizes based on platform
|
||||
#define STATIC_ASSERT(test_for_true) static_assert((test_for_true), "(" #test_for_true ") failed")
|
||||
|
||||
STATIC_ASSERT(sizeof(char) == 1);
|
||||
STATIC_ASSERT(sizeof(short) == 2);
|
||||
STATIC_ASSERT(sizeof(int) == 4);
|
||||
STATIC_ASSERT(sizeof(float) == 4);
|
||||
STATIC_ASSERT(sizeof(unsigned char) == 1);
|
||||
STATIC_ASSERT(sizeof(unsigned short) == 2);
|
||||
STATIC_ASSERT(sizeof(unsigned int) == 4);
|
||||
|
||||
#ifndef TOY_EXPORT
|
||||
|
||||
//declare the singleton
|
||||
Command command;
|
||||
@@ -106,4 +120,6 @@ void copyrightCommand(int argc, const char* argv[]) {
|
||||
printf("1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.\n\n");
|
||||
printf("2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\n\n");
|
||||
printf("3. This notice may not be removed or altered from any source distribution.\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -9,6 +9,26 @@
|
||||
#define TOY_VERSION_PATCH 0
|
||||
#define TOY_VERSION_BUILD __DATE__ " " __TIME__
|
||||
|
||||
//platform exports/imports
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
|
||||
#if defined(TOY_EXPORT)
|
||||
#define TOY_API __declspec(dllexport)
|
||||
#else
|
||||
#define TOY_API __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
#elif defined(linux)
|
||||
|
||||
#define TOY_API extern
|
||||
|
||||
#else
|
||||
|
||||
#define TOY_API
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef TOY_EXPORT
|
||||
//for processing the command line arguments
|
||||
typedef struct {
|
||||
bool error;
|
||||
@@ -29,6 +49,7 @@ void initCommand(int argc, const char* argv[]);
|
||||
void usageCommand(int argc, const char* argv[]);
|
||||
void helpCommand(int argc, const char* argv[]);
|
||||
void copyrightCommand(int argc, const char* argv[]);
|
||||
#endif
|
||||
|
||||
//NOTE: assigning to a byte from a short loses data
|
||||
#define AS_USHORT(value) (*(unsigned short*)(&(value)))
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "opcodes.h"
|
||||
|
||||
#include "node.h"
|
||||
#include "literal_array.h"
|
||||
|
||||
@@ -13,9 +13,9 @@ typedef struct Compiler {
|
||||
int count;
|
||||
} Compiler;
|
||||
|
||||
void initCompiler(Compiler* compiler);
|
||||
void writeCompiler(Compiler* compiler, Node* node);
|
||||
void freeCompiler(Compiler* compiler);
|
||||
TOY_API void initCompiler(Compiler* compiler);
|
||||
TOY_API void writeCompiler(Compiler* compiler, Node* node);
|
||||
TOY_API void freeCompiler(Compiler* compiler);
|
||||
|
||||
//embed the header with version information, data section, code section, etc.
|
||||
unsigned char* collateCompiler(Compiler* compiler, int* size);
|
||||
//embed the header, data section, code section, function section, etc.
|
||||
TOY_API unsigned char* collateCompiler(Compiler* compiler, int* size);
|
||||
|
||||
@@ -2032,9 +2032,11 @@ static void readInterpreterSections(Interpreter* interpreter) {
|
||||
//data section
|
||||
const unsigned short literalCount = readShort(interpreter->bytecode, &interpreter->count);
|
||||
|
||||
#ifndef TOY_EXPORT
|
||||
if (command.verbose) {
|
||||
printf(NOTICE "Reading %d literals\n" RESET, literalCount);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < literalCount; i++) {
|
||||
const unsigned char literalType = readByte(interpreter->bytecode, &interpreter->count);
|
||||
@@ -2044,9 +2046,11 @@ static void readInterpreterSections(Interpreter* interpreter) {
|
||||
//read the null
|
||||
pushLiteralArray(&interpreter->literalCache, TO_NULL_LITERAL);
|
||||
|
||||
#ifndef TOY_EXPORT
|
||||
if (command.verbose) {
|
||||
printf("(null)\n");
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case LITERAL_BOOLEAN: {
|
||||
@@ -2056,9 +2060,11 @@ static void readInterpreterSections(Interpreter* interpreter) {
|
||||
pushLiteralArray(&interpreter->literalCache, literal);
|
||||
freeLiteral(literal);
|
||||
|
||||
#ifndef TOY_EXPORT
|
||||
if (command.verbose) {
|
||||
printf("(boolean %s)\n", b ? "true" : "false");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2068,9 +2074,11 @@ static void readInterpreterSections(Interpreter* interpreter) {
|
||||
pushLiteralArray(&interpreter->literalCache, literal);
|
||||
freeLiteral(literal);
|
||||
|
||||
#ifndef TOY_EXPORT
|
||||
if (command.verbose) {
|
||||
printf("(integer %d)\n", d);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2080,9 +2088,11 @@ static void readInterpreterSections(Interpreter* interpreter) {
|
||||
pushLiteralArray(&interpreter->literalCache, literal);
|
||||
freeLiteral(literal);
|
||||
|
||||
#ifndef TOY_EXPORT
|
||||
if (command.verbose) {
|
||||
printf("(float %f)\n", f);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2093,9 +2103,11 @@ static void readInterpreterSections(Interpreter* interpreter) {
|
||||
pushLiteralArray(&interpreter->literalCache, literal);
|
||||
freeLiteral(literal);
|
||||
|
||||
#ifndef TOY_EXPORT
|
||||
if (command.verbose) {
|
||||
printf("(string \"%s\")\n", s);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2111,12 +2123,14 @@ static void readInterpreterSections(Interpreter* interpreter) {
|
||||
pushLiteralArray(array, interpreter->literalCache.literals[index]);
|
||||
}
|
||||
|
||||
#ifndef TOY_EXPORT
|
||||
if (command.verbose) {
|
||||
printf("(array ");
|
||||
Literal literal = TO_ARRAY_LITERAL(array);
|
||||
printLiteral(literal);
|
||||
printf(")\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
//finally, push the array proper
|
||||
Literal literal = TO_ARRAY_LITERAL(array);
|
||||
@@ -2140,12 +2154,14 @@ static void readInterpreterSections(Interpreter* interpreter) {
|
||||
setLiteralDictionary(dictionary, interpreter->literalCache.literals[key], interpreter->literalCache.literals[val]);
|
||||
}
|
||||
|
||||
#ifndef TOY_EXPORT
|
||||
if (command.verbose) {
|
||||
printf("(dictionary ");
|
||||
Literal literal = TO_DICTIONARY_LITERAL(dictionary);
|
||||
printLiteral(literal);
|
||||
printf(")\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
//finally, push the dictionary proper
|
||||
Literal literal = TO_DICTIONARY_LITERAL(dictionary);
|
||||
@@ -2167,9 +2183,11 @@ static void readInterpreterSections(Interpreter* interpreter) {
|
||||
//push to the literal cache
|
||||
pushLiteralArray(&interpreter->literalCache, literal);
|
||||
|
||||
#ifndef TOY_EXPORT
|
||||
if (command.verbose) {
|
||||
printf("(function)\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2181,9 +2199,11 @@ static void readInterpreterSections(Interpreter* interpreter) {
|
||||
|
||||
pushLiteralArray(&interpreter->literalCache, identifier);
|
||||
|
||||
#ifndef TOY_EXPORT
|
||||
if (command.verbose) {
|
||||
printf("(identifier %s (hash: %x))\n", AS_IDENTIFIER(identifier), identifier.as.identifier.hash);
|
||||
}
|
||||
#endif
|
||||
|
||||
freeLiteral(identifier);
|
||||
}
|
||||
@@ -2199,13 +2219,13 @@ static void readInterpreterSections(Interpreter* interpreter) {
|
||||
//save the type
|
||||
pushLiteralArray(&interpreter->literalCache, typeLiteral);
|
||||
|
||||
#ifndef TOY_EXPORT
|
||||
if (command.verbose) {
|
||||
printf("(type ");
|
||||
printLiteral(typeLiteral);
|
||||
printf(")\n");
|
||||
}
|
||||
|
||||
// freeLiteral(typeLiteral);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2234,11 +2254,13 @@ static void readInterpreterSections(Interpreter* interpreter) {
|
||||
//save the type
|
||||
pushLiteralArray(&interpreter->literalCache, typeLiteral); //copied
|
||||
|
||||
#ifndef TOY_EXPORT
|
||||
if (command.verbose) {
|
||||
printf("(type ");
|
||||
printLiteral(typeLiteral);
|
||||
printf(")\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
freeLiteral(typeLiteral);
|
||||
}
|
||||
@@ -2336,11 +2358,13 @@ void runInterpreter(Interpreter* interpreter, unsigned char* bytecode, int lengt
|
||||
|
||||
const char* build = readString(interpreter->bytecode, &interpreter->count);
|
||||
|
||||
#ifndef TOY_EXPORT
|
||||
if (command.verbose) {
|
||||
if (strncmp(build, TOY_VERSION_BUILD, strlen(TOY_VERSION_BUILD))) {
|
||||
printf(WARN "Warning: interpreter/bytecode build mismatch\n" RESET);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
consumeByte(interpreter, OP_SECTION_END, interpreter->bytecode, &interpreter->count);
|
||||
|
||||
@@ -2348,9 +2372,11 @@ void runInterpreter(Interpreter* interpreter, unsigned char* bytecode, int lengt
|
||||
readInterpreterSections(interpreter);
|
||||
|
||||
//code section
|
||||
#ifndef TOY_EXPORT
|
||||
if (command.verbose) {
|
||||
printf(NOTICE "executing bytecode\n" RESET);
|
||||
}
|
||||
#endif
|
||||
|
||||
//execute the interpreter
|
||||
execInterpreter(interpreter);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "literal.h"
|
||||
#include "literal_array.h"
|
||||
#include "literal_dictionary.h"
|
||||
@@ -33,17 +34,17 @@ typedef struct Interpreter {
|
||||
|
||||
//native function API
|
||||
typedef int (*NativeFn)(Interpreter* interpreter, LiteralArray* arguments);
|
||||
bool injectNativeFn(Interpreter* interpreter, char* name, NativeFn func);
|
||||
TOY_API bool injectNativeFn(Interpreter* interpreter, char* name, NativeFn func);
|
||||
//TODO: injectNativeHook
|
||||
|
||||
//utilities for the host program
|
||||
bool parseIdentifierToValue(Interpreter* interpreter, Literal* literalPtr);
|
||||
void setInterpreterPrint(Interpreter* interpreter, PrintFn printOutput);
|
||||
void setInterpreterAssert(Interpreter* interpreter, PrintFn assertOutput);
|
||||
void setInterpreterError(Interpreter* interpreter, PrintFn errorOutput);
|
||||
TOY_API bool parseIdentifierToValue(Interpreter* interpreter, Literal* literalPtr);
|
||||
TOY_API void setInterpreterPrint(Interpreter* interpreter, PrintFn printOutput);
|
||||
TOY_API void setInterpreterAssert(Interpreter* interpreter, PrintFn assertOutput);
|
||||
TOY_API void setInterpreterError(Interpreter* interpreter, PrintFn errorOutput);
|
||||
|
||||
//main access
|
||||
void initInterpreter(Interpreter* interpreter); //start of program
|
||||
void runInterpreter(Interpreter* interpreter, unsigned char* bytecode, int length); //run the code
|
||||
void resetInterpreter(Interpreter* interpreter); //use this to reset the interpreter's environment between runs
|
||||
void freeInterpreter(Interpreter* interpreter); //end of program
|
||||
TOY_API void initInterpreter(Interpreter* interpreter); //start of program
|
||||
TOY_API void runInterpreter(Interpreter* interpreter, unsigned char* bytecode, int length); //run the code
|
||||
TOY_API void resetInterpreter(Interpreter* interpreter); //use this to reset the interpreter's environment between runs
|
||||
TOY_API void freeInterpreter(Interpreter* interpreter); //end of program
|
||||
|
||||
@@ -109,10 +109,12 @@ static Token makeErrorToken(Lexer* lexer, char* msg) {
|
||||
token.length = strlen(msg);
|
||||
token.line = lexer->line;
|
||||
|
||||
#ifndef TOY_EXPORT
|
||||
if (command.verbose) {
|
||||
printf("err:");
|
||||
printToken(&token);
|
||||
}
|
||||
#endif
|
||||
|
||||
return token;
|
||||
}
|
||||
@@ -125,11 +127,13 @@ static Token makeToken(Lexer* lexer, TokenType type) {
|
||||
token.lexeme = &lexer->source[lexer->current - token.length];
|
||||
token.line = lexer->line;
|
||||
|
||||
#ifndef TOY_EXPORT
|
||||
//BUG #10: this shows TOKEN_EOF twice due to the overarching structure of the program - can't be fixed
|
||||
if (command.verbose) {
|
||||
printf("tok:");
|
||||
printToken(&token);
|
||||
}
|
||||
#endif
|
||||
|
||||
return token;
|
||||
}
|
||||
@@ -152,6 +156,7 @@ static Token makeIntegerOrFloat(Lexer* lexer) {
|
||||
token.length = lexer->current - lexer->start;
|
||||
token.line = lexer->line;
|
||||
|
||||
#ifndef TOY_EXPORT
|
||||
if (command.verbose) {
|
||||
if (type == TOKEN_LITERAL_INTEGER) {
|
||||
printf("int:");
|
||||
@@ -160,6 +165,7 @@ static Token makeIntegerOrFloat(Lexer* lexer) {
|
||||
}
|
||||
printToken(&token);
|
||||
}
|
||||
#endif
|
||||
|
||||
return token;
|
||||
}
|
||||
@@ -182,10 +188,12 @@ static Token makeString(Lexer* lexer, char terminator) {
|
||||
token.length = lexer->current - lexer->start - 2;
|
||||
token.line = lexer->line;
|
||||
|
||||
#ifndef TOY_EXPORT
|
||||
if (command.verbose) {
|
||||
printf("str:");
|
||||
printToken(&token);
|
||||
}
|
||||
#endif
|
||||
|
||||
return token;
|
||||
}
|
||||
@@ -207,10 +215,12 @@ static Token makeKeywordOrIdentifier(Lexer* lexer) {
|
||||
token.length = lexer->current - lexer->start;
|
||||
token.line = lexer->line;
|
||||
|
||||
#ifndef TOY_EXPORT
|
||||
if (command.verbose) {
|
||||
printf("kwd:");
|
||||
printToken(&token);
|
||||
}
|
||||
#endif
|
||||
|
||||
return token;
|
||||
}
|
||||
@@ -224,10 +234,12 @@ static Token makeKeywordOrIdentifier(Lexer* lexer) {
|
||||
token.length = lexer->current - lexer->start;
|
||||
token.line = lexer->line;
|
||||
|
||||
#ifndef TOY_EXPORT
|
||||
if (command.verbose) {
|
||||
printf("idf:");
|
||||
printToken(&token);
|
||||
}
|
||||
#endif
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ typedef struct {
|
||||
int line;
|
||||
} Token;
|
||||
|
||||
void initLexer(Lexer* lexer, char* source);
|
||||
TOY_API void initLexer(Lexer* lexer, char* source);
|
||||
Token scanLexer(Lexer* lexer);
|
||||
|
||||
//for debugging
|
||||
|
||||
@@ -94,7 +94,7 @@ typedef struct {
|
||||
#define TO_IDENTIFIER_LITERAL(value, l) _toIdentifierLiteral(value, l)
|
||||
#define TO_TYPE_LITERAL(value, c) ((Literal){ LITERAL_TYPE, { .type.typeOf = value, .type.constant = c, .type.subtypes = NULL, .type.capacity = 0, .type.count = 0 }})
|
||||
|
||||
void freeLiteral(Literal literal);
|
||||
TOY_API void freeLiteral(Literal literal);
|
||||
|
||||
#define IS_TRUTHY(x) _isTruthy(x)
|
||||
|
||||
@@ -103,17 +103,16 @@ void freeLiteral(Literal literal);
|
||||
#define TYPE_PUSH_SUBTYPE(lit, subtype) _typePushSubtype(lit, subtype)
|
||||
|
||||
//BUGFIX: macros are not functions
|
||||
bool _isTruthy(Literal x);
|
||||
Literal _toStringLiteral(char* str, int length);
|
||||
Literal _toIdentifierLiteral(char* str, int length);
|
||||
Literal* _typePushSubtype(Literal* lit, Literal subtype);
|
||||
TOY_API bool _isTruthy(Literal x);
|
||||
TOY_API Literal _toStringLiteral(char* str, int length);
|
||||
TOY_API Literal _toIdentifierLiteral(char* str, int length);
|
||||
TOY_API Literal* _typePushSubtype(Literal* lit, Literal subtype);
|
||||
|
||||
//utils
|
||||
Literal copyLiteral(Literal original);
|
||||
char* copyString(char* original, int length);
|
||||
bool literalsAreEqual(Literal lhs, Literal rhs);
|
||||
int hashLiteral(Literal lit);
|
||||
|
||||
void printLiteral(Literal literal);
|
||||
void printLiteralCustom(Literal literal, void (printFn)(const char*));
|
||||
TOY_API Literal copyLiteral(Literal original);
|
||||
TOY_API char* copyString(char* original, int length);
|
||||
TOY_API bool literalsAreEqual(Literal lhs, Literal rhs);
|
||||
TOY_API int hashLiteral(Literal lit);
|
||||
|
||||
TOY_API void printLiteral(Literal literal);
|
||||
TOY_API void printLiteralCustom(Literal literal, void (printFn)(const char*));
|
||||
|
||||
@@ -5,13 +5,24 @@ CFLAGS +=$(addprefix -I,$(IDIR)) -g -Wall -W -pedantic -Wno-unused-parameter -Wn
|
||||
LIBS +=
|
||||
|
||||
ODIR = obj
|
||||
SRC = $(wildcard *.c)
|
||||
SRC = $(filter-out $(wildcard *main.c),$(wildcard *.c))
|
||||
OBJ = $(addprefix $(ODIR)/,$(SRC:.c=.o))
|
||||
|
||||
OUT = ../$(OUTDIR)/toy
|
||||
OUTNAME = toy
|
||||
OUT = ../$(OUTDIR)/$(OUTNAME).dll
|
||||
LIBLINE =-Wl,--out-implib=../$(OUTDIR)/lib$(OUTNAME).dll.a -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--whole-archive $(OBJ) -Wl,--no-whole-archive
|
||||
|
||||
all: $(OBJ)
|
||||
$(CC) -o $(OUT) $^ $(CFLAGS) $(LIBS)
|
||||
REPLSRC = $(wildcard repl_main.c)
|
||||
REPLOUT = $(OUTNAME)repl.exe
|
||||
|
||||
all: library $(addprefix $(ODIR)/,$(REPLSRC:.c=.o))
|
||||
$(CC) -DTOY_IMPORT $(CFLAGS) -o ../$(OUTDIR)/$(REPLOUT) $(addprefix $(ODIR)/,$(REPLSRC:.c=.o)) $(LIBS) -L$(realpath $(shell pwd)/../$(OUTDIR)) -l$(OUTNAME)
|
||||
|
||||
library: $(OBJ)
|
||||
$(CC) -DTOY_EXPORT $(CFLAGS) -shared -o $(OUT) $(LIBLINE)
|
||||
|
||||
static: $(OBJ) $(addprefix $(ODIR)/,$(REPLSRC:.c=.o))
|
||||
$(CC) $(CFLAGS) -o ../$(OUTDIR)/$(REPLOUT) $(addprefix $(ODIR)/,$(REPLSRC:.c=.o)) $(OBJ) $(LIBS)
|
||||
|
||||
$(OBJ): | $(ODIR)
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "literal.h"
|
||||
#include "opcodes.h"
|
||||
#include "token_types.h"
|
||||
@@ -153,7 +154,8 @@ union _node {
|
||||
NodeIndex index;
|
||||
};
|
||||
|
||||
void freeNode(Node* node);
|
||||
TOY_API void freeNode(Node* node);
|
||||
|
||||
void emitNodeLiteral(Node** nodeHandle, Literal literal);
|
||||
void emitNodeUnary(Node** nodeHandle, Opcode opcode, Node* child);
|
||||
void emitNodeBinary(Node** nodeHandle, Node* rhs, Opcode opcode); //handled node becomes lhs
|
||||
|
||||
@@ -59,9 +59,11 @@ static void consume(Parser* parser, TokenType tokenType, const char* msg) {
|
||||
}
|
||||
|
||||
static void synchronize(Parser* parser) {
|
||||
#ifndef TOY_EXPORT
|
||||
if (command.verbose) {
|
||||
fprintf(stderr, ERROR "synchronizing\n" RESET);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (parser->current.type != TOKEN_EOF) {
|
||||
switch(parser->current.type) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "parser.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "lexer.h"
|
||||
#include "node.h"
|
||||
|
||||
@@ -16,6 +15,6 @@ typedef struct {
|
||||
Token previous;
|
||||
} Parser;
|
||||
|
||||
void initParser(Parser* parser, Lexer* lexer);
|
||||
void freeParser(Parser* parser);
|
||||
Node* scanParser(Parser* parser);
|
||||
TOY_API void initParser(Parser* parser, Lexer* lexer);
|
||||
TOY_API void freeParser(Parser* parser);
|
||||
TOY_API Node* scanParser(Parser* parser);
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
#include "compiler.h"
|
||||
#include "interpreter.h"
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
Reference in New Issue
Block a user