commit 637b8c02e69e11180c1c44d12ebbf971af8ebec7 Author: ngn Date: Thu Jun 20 03:34:32 2024 +0300 first commit diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..ac283ea --- /dev/null +++ b/.clang-format @@ -0,0 +1,225 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: DontAlign +AlignArrayOfStructures: Left +AlignConsecutiveAssignments: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: true +AlignConsecutiveBitFields: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveDeclarations: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveMacros: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignEscapedNewlines: Right +AlignOperands: Align +AlignTrailingComments: + Kind: Always + OverEmptyLines: 0 +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortEnumsOnASingleLine: true +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +AttributeMacros: + - __capability +BinPackArguments: false +BinPackParameters: true +BitFieldColonSpacing: Both +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterExternBlock: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakAfterAttributes: Never +BreakAfterJavaFieldAnnotations: false +BreakArrays: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: Always +BreakBeforeBraces: Attach +BreakBeforeInlineASMColon: OnlyMultiline +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: false +IndentExternBlock: AfterExternBlock +IndentGotoLabels: true +IndentPPDirectives: None +IndentRequiresClause: true +IndentWidth: 2 +IndentWrappedFunctionNames: false +InsertBraces: false +InsertNewlineAtEOF: false +InsertTrailingCommas: None +IntegerLiteralSeparator: + Binary: 0 + BinaryMinDigits: 0 + Decimal: 0 + DecimalMinDigits: 0 + Hex: 0 + HexMinDigits: 0 +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +LambdaBodyIndentation: Signature +LineEnding: DeriveLF +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PackConstructorInitializers: BinPack +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +PPIndentWidth: -1 +QualifierAlignment: Leave +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +RemoveSemicolon: false +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: LexicographicNumeric +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseTab: Never +WhitespaceSensitiveMacros: + - BOOST_PP_STRINGIZE + - CF_SWIFT_NAME + - NS_SWIFT_NAME + - PP_STRINGIZE + - STRINGIZE +... + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..02a836d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.pot +*.mo +dist diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..37f59bb --- /dev/null +++ b/Makefile @@ -0,0 +1,67 @@ +PREFIX = /usr +CC = gcc + +PO_SRCS = $(wildcard locale/*/*/*.po) +PO_OUTS = $(patsubst locale/%.po,locale/%.mo,$(PO_SRCS)) +PO_DIRS = $(wildcard locale/*/*) + +SRCS = $(wildcard src/*.c) $(wildcard src/*/*.c) +OBJS = $(patsubst src/%.c,dist/%.o,$(SRCS)) +HDRS = $(wildcard include/*.h) +CFLAGS = -O3 -march=native -fstack-protector-strong -fcf-protection=full -fstack-clash-protection +LIBS = -larchive -linih -lgpgme + +VERSION = 24.00 + +all: dist/libmp.so $(PO_OUTS) + +dist/libmp.so: $(OBJS) + mkdir -p dist + $(CC) -shared -o $@ $^ $(LIBS) $(CFLAGS) + +dist/%.o: src/%.c + mkdir -p dist + $(CC) -c -Wall -fPIC -o $@ $^ $(LIBS) $(CFLAGS) -DVERSION=\"${VERSION}\" + +locale/%.mo: locale/%.po + msgfmt $^ -o $@ + +locale/%.po: locale/libmp.pot + cp $@ $@.old + if msgmerge $@ $^ -o $@ ; then \ + rm $@.old ; \ + echo "merge success: $@" ; \ + else \ + echo "merge failed: $@" ; \ + mv $@.old $@ ; \ + fi; \ + +locale/libmp.pot: $(SRCS) + mkdir -p locale + xgettext -k_ -c $^ -o $@ + +install: + install -m755 dist/libmp.so $(DESTDIR)$(PREFIX)/lib/libmp.so + mkdir -pv $(DESTDIR)/usr/include/libmp + cp $(HDRS) $(DESTDIR)/usr/include/libmp + @for po in $(PO_DIRS) ; do \ + echo "installing locale: $$po/libmp.mo" ; \ + mkdir -pv $(DESTDIR)/usr/share/$$po ; \ + cp $$po/libmp.mo $(DESTDIR)/usr/share/$$po ; \ + done + +uninstall: + rm $(DESTDIR)$(PREFIX)/lib/libmp.so + rm -r $(DESTDIR)/usr/include/libmp + +format: + clang-format -i -style=file src/*.c src/*.c include/*.h examples/*/*.c + +examples: +ifeq (,$(wildcard dist/libmp.so)) + @echo "!!!! you should first compile libmp !!!!" + exit 1 +endif + $(MAKE) -C $@ + +.PHONY: test install uninstall format examples diff --git a/README.md b/README.md new file mode 100644 index 0000000..5ce7750 --- /dev/null +++ b/README.md @@ -0,0 +1,43 @@ +# libmp | MatterLinux package management library +The core library for [`mp`](https://git.matterlinux.xyz/Matter/mp), it has +components for transferring, installing, updating and removing packages. + +### Installation +If you are using MatterLinux, this package is most likely already installed, +as it's a core component of the system. If you are not, then you can build +it from the source and install it. + +To this you will need the following tools and libraries: +- gcc +- make +- libarchive +- libinih +- gettext +- gpgme + +After installing these dependencies, you should download the latest release. +If you are building this library for development purposes, then you may also +build from the latest commit. However latest commit may not always be compilable. + +After obtaining the source code, you can compile the library using the make +tool: +```bash +make +``` + +To install the library you can use the make tool again: +```bash +make install +``` + +### Tutorial and examples +MatterLinux wiki has a [tutorial for working with this library](https://matterlinux.xyz/wiki/libmp). +There are also some simple examples under the `examples/` directory, you can build these examples +using make: +```bash +make examples +``` +To run the examples, specify the library path: +```bash +LD_LIBRARY_PATH=./dist ./dist/example_version +``` diff --git a/examples/Makefile b/examples/Makefile new file mode 100644 index 0000000..45e4e19 --- /dev/null +++ b/examples/Makefile @@ -0,0 +1,7 @@ +CC = gcc + +all: ../dist/example_pool + +../dist/example_pool: pool/*.c ../dist/libmp.so + mkdir -pv ../dist + $(CC) -L../dist $< -lmp -o $@ diff --git a/examples/pool/main.c b/examples/pool/main.c new file mode 100644 index 0000000..ad19345 --- /dev/null +++ b/examples/pool/main.c @@ -0,0 +1,28 @@ +#include "../../include/all.h" +#include +#include + +int main(int argc, char *argv[]) { + int ret = EXIT_FAILURE; + + if(argc != 2){ + printf("usage: %s \n", argv[0]); + return ret; + } + + lm_ctx_t ctx; + lm_ctx_init(&ctx); + + ctx.debug = true; + + if(!lm_ctx_pool_add(&ctx, "test", argv[1])){ + printf("failed to add pool: %s (%d)\n", lm_strerror(), lm_error()); + goto end; + } + + ret = EXIT_SUCCESS; + +end: + lm_ctx_free(&ctx); + return ret; +} diff --git a/include/all.h b/include/all.h new file mode 100644 index 0000000..fd083a6 --- /dev/null +++ b/include/all.h @@ -0,0 +1,4 @@ +#include "types.h" +#include "pool.h" +#include "error.h" +#include "libmp.h" diff --git a/include/error.h b/include/error.h new file mode 100644 index 0000000..88ef08e --- /dev/null +++ b/include/error.h @@ -0,0 +1,25 @@ +#pragma once + +typedef enum lm_error { + LM_ERR_NoError = 0, + LM_ERR_URLBadChar = 1, + LM_ERR_URLBadProtocol = 2, + LM_ERR_URLTooLarge = 3, + LM_ERR_URLHostLarge = 4, + LM_ERR_URLPathLarge = 5, + LM_ERR_URLBadHost = 6, + LM_ERR_URLBadPath = 7, + LM_ERR_URLPortUnknown = 8, + LM_ERR_URLBadPort = 9, + LM_ERR_PoolNoSupport = 10, + LM_ERR_URLEnd = 11, +} lm_error_t; + +typedef struct lm_error_desc { + lm_error_t code; + char *desc; +} lm_error_desc_t; + +void lm_error_set(lm_error_t code); +lm_error_t lm_error(); +char *lm_strerror(); diff --git a/include/libmp.h b/include/libmp.h new file mode 100644 index 0000000..7fff84e --- /dev/null +++ b/include/libmp.h @@ -0,0 +1,5 @@ +#pragma once +#include "types.h" + +void lm_ctx_init(lm_ctx_t *ctx); +void lm_ctx_free(lm_ctx_t *ctx); diff --git a/include/pool.h b/include/pool.h new file mode 100644 index 0000000..d06de1e --- /dev/null +++ b/include/pool.h @@ -0,0 +1,8 @@ +#pragma once +#include +#include "types.h" + +bool lm_ctx_pool_add(lm_ctx_t *ctx, char *name, char *url); +bool lm_ctx_pool_del(lm_ctx_t *ctx, char *name); +void lm_ctx_pool_clear(lm_ctx_t *ctx); +void lm_ctx_pool_test(lm_ctx_t *ctx); diff --git a/include/types.h b/include/types.h new file mode 100644 index 0000000..83e83de --- /dev/null +++ b/include/types.h @@ -0,0 +1,20 @@ +#pragma once +#include "url.h" +#include + +typedef struct lm_pool { + struct lm_pool *next; + lm_url_t url; + bool available; + char *name; +} lm_pool_t; + +typedef struct lm_ctx { + lm_pool_t *pools; // pool list + + char *root; // root path for package installtion + char *temp; // temp path + char *data; // package database path + bool debug; // is debug output enabled? +} lm_ctx_t; + diff --git a/include/url.h b/include/url.h new file mode 100644 index 0000000..45d404e --- /dev/null +++ b/include/url.h @@ -0,0 +1,17 @@ +#pragma once +#include +#include + +#define URL_PROTOCOL_MAX 20 +#define URL_PATH_MAX 2000 +#define URL_HOST_MAX 260 + +typedef struct lm_url { + uint16_t port; + char protocol[URL_PROTOCOL_MAX+1]; + char *host; + char *path; +} lm_url_t; + +bool lm_url_parse(lm_url_t *url, char *str); +void lm_url_free(lm_url_t *url); diff --git a/include/util.h b/include/util.h new file mode 100644 index 0000000..fe7b8a2 --- /dev/null +++ b/include/util.h @@ -0,0 +1,12 @@ +#pragma once +#include +#include +#include "types.h" + +#define _(x) gettext(x) + +void pdebug(lm_ctx_t *ctx, const char *func, const char *fmt, ...); +bool contains(char *str, char s); +bool eq(char *s1, char *s2); +bool is_letter(char c); +bool is_digit(char c); diff --git a/locale/tr/LC_MESSAGES/libmp.po b/locale/tr/LC_MESSAGES/libmp.po new file mode 100644 index 0000000..b69aad7 --- /dev/null +++ b/locale/tr/LC_MESSAGES/libmp.po @@ -0,0 +1,67 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-06-20 03:33+0300\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: tr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/error.c:13 +msgid "no error" +msgstr "no error" + +#: src/error.c:14 +#, fuzzy +msgid "URL contains an invalid character" +msgstr "URL contains an invalid char" + +#: src/error.c:15 +msgid "URL does not have a valid protocol field" +msgstr "URL does not have a valid protocol field" + +#: src/error.c:16 +msgid "URL is too large" +msgstr "URL is too large" + +#: src/error.c:17 +msgid "URL hostname is too large" +msgstr "URL hostname is too large" + +#: src/error.c:18 +msgid "URL path is too large" +msgstr "URL path is too large" + +#: src/error.c:19 +msgid "URL does not have a valid hostname" +msgstr "URL does not have a valid hostname" + +#: src/error.c:20 +msgid "URL does not have a valid path" +msgstr "URL does not have a valid path" + +#: src/error.c:21 +msgid "URL does not contain a hostname with a valid port number" +msgstr "URL does not contain a hostname with a valid port number" + +#: src/error.c:22 +msgid "URL protocol port number is unknown" +msgstr "URL protocol port number is unknown" + +#: src/error.c:23 +msgid "URL is incomplete" +msgstr "URL is incomplete" + +#: src/error.c:24 +msgid "pool does not support the specified protocol" +msgstr "pool does not support the specified protocol" diff --git a/src/error.c b/src/error.c new file mode 100644 index 0000000..13b9ee7 --- /dev/null +++ b/src/error.c @@ -0,0 +1,36 @@ +#include "../include/error.h" +#include "../include/util.h" +#include + +lm_error_t error = LM_ERR_NoError; + +void lm_error_set(lm_error_t code){ + error = code; +} + +char *lm_strerror(){ + lm_error_desc_t errors[] = { + {.code=LM_ERR_NoError, .desc=_("no error")}, + {.code=LM_ERR_URLBadChar, .desc=_("URL contains an invalid character")}, + {.code=LM_ERR_URLBadProtocol, .desc=_("URL does not have a valid protocol field")}, + {.code=LM_ERR_URLTooLarge, .desc=_("URL is too large")}, + {.code=LM_ERR_URLHostLarge, .desc=_("URL hostname is too large")}, + {.code=LM_ERR_URLPathLarge, .desc=_("URL path is too large")}, + {.code=LM_ERR_URLBadHost, .desc=_("URL does not have a valid hostname")}, + {.code=LM_ERR_URLBadPath, .desc=_("URL does not have a valid path")}, + {.code=LM_ERR_URLBadPort, .desc=_("URL does not contain a hostname with a valid port number")}, + {.code=LM_ERR_URLPortUnknown, .desc=_("URL protocol port number is unknown")}, + {.code=LM_ERR_URLEnd, .desc=_("URL is incomplete")}, + {.code=LM_ERR_PoolNoSupport, .desc=_("pool does not support the specified protocol")}, + }; + + for(int i = 0; i < sizeof(errors)/sizeof(lm_error_desc_t); i++){ + if(errors[i].code == error) + return errors[i].desc; + } + return NULL; +} + +lm_error_t lm_error(){ + return error; +} diff --git a/src/libmp.c b/src/libmp.c new file mode 100644 index 0000000..604b766 --- /dev/null +++ b/src/libmp.c @@ -0,0 +1,45 @@ +// clang-format off + +/* + + * libmp | MatterLinux package management library + * MatterLinux 2023-2024 (https://matterlinux.xyz) + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + +*/ + +// clang-format on + +#include "../include/libmp.h" +#include "../include/pool.h" +#include +#include +#include + +void lm_ctx_init(lm_ctx_t *ctx){ + setlocale(LC_ALL, ""); + textdomain("libmp"); + + ctx->pools = NULL; + ctx->data = NULL; + ctx->root = NULL; + ctx->temp = NULL; + ctx->debug = false; +} + +void lm_ctx_free(lm_ctx_t *ctx){ + lm_ctx_pool_clear(ctx); + return; +} diff --git a/src/pool.c b/src/pool.c new file mode 100644 index 0000000..5e7e42c --- /dev/null +++ b/src/pool.c @@ -0,0 +1,89 @@ +#include "../include/error.h" +#include "../include/util.h" +#include "../include/pool.h" +#include +#include + +void lm_pool_free(lm_pool_t *pool){ + lm_url_free(&pool->url); + free(pool); +} + +lm_pool_t *lm_pool_new(char *name, char *url){ + lm_pool_t *pool = malloc(sizeof(lm_pool_t)); + if(!lm_url_parse(&pool->url, url)){ + free(pool); + return NULL; + } + + if(!eq(pool->url.protocol, "mptp")){ + lm_error_set(LM_ERR_PoolNoSupport); + lm_pool_free(pool); + return NULL; + } + + pool->name = name; + return pool; +} + +bool lm_ctx_pool_add(lm_ctx_t *ctx, char *name, char *url){ + lm_pool_t *pool = lm_pool_new(name, url); + if(NULL == pool) + return false; + + pdebug(ctx, __func__, "pool name is %s", pool->name); + pdebug(ctx, __func__, "pool URL is %s://%s%s", pool->url.protocol, pool->url.host, pool->url.path); + + if(NULL == ctx->pools){ + ctx->pools = pool; + return true; + } + + lm_pool_t *cur = ctx->pools; + while(NULL != cur) { + if(NULL == cur->next){ + cur->next = pool; + return true; + } + cur = cur->next; + } + + return false; +} + +bool lm_ctx_pool_del(lm_ctx_t *ctx, char *name){ + lm_pool_t *cur = ctx->pools, *prev = NULL; + while(NULL != cur) { + if(!eq(cur->name, name)){ + cur = cur->next; + continue; + } + + if(NULL == prev){ + ctx->pools = cur->next; + lm_pool_free(cur); + return true; + } + + prev->next = cur->next; + lm_pool_free(cur); + return true; + } + + return false; +} + +void lm_ctx_pool_clear(lm_ctx_t *ctx){ + lm_pool_t *cur = ctx->pools, *prev = NULL; + while(NULL != cur) { + prev = cur; + cur = cur->next; + lm_pool_free(prev); + } + + ctx->pools = NULL; +} + +void lm_ctx_pool_test(lm_ctx_t *ctx){ + return; +} diff --git a/src/url.c b/src/url.c new file mode 100644 index 0000000..ca0b3af --- /dev/null +++ b/src/url.c @@ -0,0 +1,203 @@ +#include "../include/error.h" +#include "../include/util.h" +#include "../include/url.h" +#include +#include +#include +#include + +char valid_path[] = "-._~:/?#[]@!$&'()*+,;%="; + +typedef enum lm_state { + URL_PROTOCOL_0 = 0, + URL_SPLIT_1 = 1, + URL_HOST_2 = 2, + URL_PATH_3 = 3, +} lm_state_t; + +uint16_t lm_url_default(char *protocol){ + if(eq(protocol, "ftp")) + return 21; + else if(eq(protocol, "ftps")) + return 990; + else if(eq(protocol, "http")) + return 80; + else if(eq(protocol, "https")) + return 443; + else if(eq(protocol, "mptp")) + return 5858; + return 0; +} + +bool lm_url_parse(lm_url_t *url, char *str){ + // clear out every variable + bzero(url->protocol, sizeof(url->protocol)); + url->host = NULL; + url->path = NULL; + url->port = 0; + + // stores the string size + size_t strl = 0, index = 0, pos = 0; + + // make sure the URL string size is not too large + // extra 4 for "://" and ":" + if((strl = strlen(str)) > URL_PROTOCOL_MAX+URL_PATH_MAX+URL_HOST_MAX+4){ + lm_error_set(LM_ERR_URLTooLarge); + return false; + } + + lm_state_t state = URL_PROTOCOL_0; + char buffer[strl+1]; // temporary buffer + bool ret = false; // return value + + // clear out the temporary buffer + bzero(buffer, strl+1); + + while ((buffer[index] = *(str+pos)) != 0) { + switch (state) { + case URL_PROTOCOL_0: + if(index > URL_PROTOCOL_MAX){ + lm_error_set(LM_ERR_URLBadProtocol); + goto end; + } + + if (!is_letter(buffer[index]) && !is_digit(buffer[index]) && buffer[index] != ':'){ + lm_error_set(LM_ERR_URLBadChar); + goto end; + } + + if(buffer[index] != ':') + break; + + if(0 == index){ + lm_error_set(LM_ERR_URLBadProtocol); + goto end; + } + + buffer[index] = 0; + memcpy(url->protocol, buffer, index+1); + goto next; + + case URL_SPLIT_1: + if(index > 1){ + lm_error_set(LM_ERR_URLBadProtocol); + goto end; + } + + if (buffer[index] != '/'){ + lm_error_set(LM_ERR_URLBadChar); + goto end; + } + + if(index != 1) + break; + + if(buffer[index-1] != '/' || buffer[index] != '/'){ + lm_error_set(LM_ERR_URLBadProtocol); + goto end; + } + + goto next; + + case URL_HOST_2: + if(index > URL_HOST_MAX){ + lm_error_set(LM_ERR_URLHostLarge); + goto end; + } + + if (!is_letter(buffer[index]) && !is_digit(buffer[index]) && buffer[index] != '.' && buffer[index] != ':' && buffer[index] != '/'){ + lm_error_set(LM_ERR_URLBadChar); + goto end; + } + + if(buffer[index] != '/') + break; + + if(index == 0){ + lm_error_set(LM_ERR_URLBadHost); + goto end; + } + + buffer[index] = 0; + url->host = malloc((index+1)*sizeof(char)); + memcpy(url->host, buffer, index+1); + goto next; + + case URL_PATH_3: + if(index > URL_PATH_MAX){ + lm_error_set(LM_ERR_URLPathLarge); + goto end; + } + + if (!is_letter(buffer[index]) && !is_digit(buffer[index]) && !contains(valid_path, buffer[index])){ + lm_error_set(LM_ERR_URLBadChar); + goto end; + } + + break; + + default: + assert(false); + } + + index++; + pos++; + continue; + + next: + bzero(buffer, strl+1); + state++; + index = 0; + pos++; + } + + switch (state) { + case URL_HOST_2: + if(index == 0){ + lm_error_set(LM_ERR_URLBadHost); + goto end; + } + + if(index > URL_HOST_MAX){ + lm_error_set(LM_ERR_URLHostLarge); + goto end; + } + + url->host = malloc((index+1)*sizeof(char)); + memcpy(url->host, buffer, index+1); + + url->path = malloc(2*sizeof(char)); + url->path[0] = '/'; + url->path[1] = 0; + break; + + case URL_PATH_3: + url->path = malloc((index+2)*sizeof(char)); + url->path[0] = '/'; + memcpy(url->path+1, buffer, index+1); + break; + + default: + lm_error_set(LM_ERR_URLEnd); + goto end; + } + + ret = true; + +end: + if(!ret && NULL != url->host) + free(url->host); + + if(!ret && NULL != url->path) + free(url->path); + + return ret; +} + +void lm_url_free(lm_url_t *url){ + if(NULL != url->host) + free(url->host); + + if(NULL != url->path) + free(url->path); +} diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..4d92969 --- /dev/null +++ b/src/util.c @@ -0,0 +1,45 @@ +#include "../include/util.h" +#include "../include/types.h" +#include +#include +#include +#include + +void pdebug(lm_ctx_t *ctx, const char *func, const char *fmt, ...){ + if(!ctx->debug) + return; + + va_list args; + va_start(args, fmt); + + printf("[DEBUG] %s: ", func); + vprintf(fmt, args); + printf("\n"); + + va_end(args); +} + +bool eq(char *s1, char *s2) { + if (NULL == s1 || NULL == s2) + return false; + + if (strlen(s1) != strlen(s2)) + return false; + + return strcmp(s1, s2) == 0; +} + +bool is_letter(char c) { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); +} + +bool is_digit(char c) { + return c >= '0' && c <= '9'; +} + +bool contains(char *str, char s) { + for (char *c = str; *c != 0; c++) + if (*c == s) + return true; + return false; +}