Compare commits

3 Commits
Author SHA1 Message Date
elias 89ef04cfd4 Cleanup Makefile 2019-10-31 16:05:04 +01:00
elias aff6ab6fb2 Fix .gitignore and add missing Makefiles 2019-07-14 21:01:07 +02:00
elias 043d414df4 Add basic aisl tool implementation 2019-07-14 20:56:28 +02:00
25 changed files with 522 additions and 631 deletions
+6 -26
View File
@@ -1,26 +1,6 @@
# Binaries build/
*.tar.gz
build/* *.zip
root/* *.rar
demo/* *.gz
*.bz2
bin/*
obj/*
webstuff-*
Makefile
tmp
tmp/*
*.tar.gz
*.zip
*.rar
*.gz
*.bz2
pkg/*
include/webstuff_bak
CMakeCache.txt
CMakeFiles/*
cmake_install.cmake
libaisl.dylib
demo/demo
+31
View File
@@ -0,0 +1,31 @@
#
# Makefile
# Ilja Kartašov, 2019-03-02 17:32
#
#
OUT_DIR ?= build
.PHONY: library examples tool
all: library
library:
@cd library && make
examples: library
@cd examples && make
tool: library
@cd tool && make
clean:
$(info cleaning: build files)
@rm -Rf $(OUT_DIR)
@rm -Rf ./vgcore.*
install: library
cd library && make install
cd tool && make install
# vim:ft=make
#
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-65
View File
@@ -1,65 +0,0 @@
#
# config.mk
# Löwenware Makefile Config, 2019-03-02 17:35
#
PREFIX ?= /usr/local
PKG_CONFIG ?= pkg-config
PROJECT_NAME = aisl
# Version
PROJECT_VERSION_MAJOR = 1
PROJECT_VERSION_MINOR = 0
PROJECT_VERSION_TWEAK = 5
PROJECT_VERSION_LABEL = 0
#SRC_DIR = src
#SDK_DIR = sdk
#OUT_DIR = ./build
# Source files
PROJECT_SOURCES := \
$(SRC_DIR)/instance.c \
$(SRC_DIR)/server.c \
$(SRC_DIR)/client.c \
$(SRC_DIR)/stream.c \
$(SRC_DIR)/http.c \
$(SRC_DIR)/ssl.c \
$(SRC_DIR)/list.c \
$(SRC_DIR)/str-utils.c \
$(SRC_DIR)/buffer.c \
$(SRC_DIR)/types.c \
# includes
PROJECT_INCLUDES = -I./ \
-I./include \
`$(PKG_CONFIG) --cflags openssl` \
# libraries
PROJECT_LIBRARIES = \
`$(PKG_CONFIG) --libs openssl` \
# compilation macro options:
AISL_WITH_DEBUG ?= 0 # disable debug output
AISL_WITH_SSL ?= 1 # enable SSL support
AISL_WITH_STRINGIFIERS ?= 1 # enable *_to_string functions
# flags
PROJECT_CFLAGS = -D_POSIX_C_SOURCE=200809L
PROJECT_CFLAGS += -DAISL_WITH_DEBUG=$(AISL_WITH_DEBUG)
PROJECT_CFLAGS += -DAISL_WITH_SSL=$(AISL_WITH_SSL)
PROJECT_CFLAGS += -DAISL_WITH_STRINGIFIERS=$(AISL_WITH_STRINGIFIERS)
# PROJECT_LDFLAGS = -L
# vim:ft=make
#
-539
View File
@@ -1,539 +0,0 @@
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#ifndef AISL_WITHOUT_SSL
#include <openssl/err.h>
#endif
#include <aisl/aisl.h>
#include "debug.h"
#include "stream.h"
#include "http.h"
#include "server.h"
#include "instance.h"
#include "client.h"
#define FLAG_KEEPALIVE (1<<0)
#define FLAG_HANDSHAKE (1<<1)
#define FLAG_CAN_READ (1<<2)
#define FLAG_CAN_WRITE (1<<3)
#define BUFFER_SIZE (16*1024)
static void
aisl_client_close(AislClient client, AislStatus status)
{
if (client->fd != -1)
{
aisl_raise(
client->server->instance
, (void *)client
, AISL_EVENT_CLIENT_DISCONNECT
, status
);
close(client->fd);
shutdown(client->fd, SHUT_RDWR);
client->fd = -1;
}
}
static AislStatus
aisl_client_parse(AislClient client, char * data, int32_t size)
{
AislStatus result = AISL_SUCCESS;
AislStream s = client->stream;
ParserStatus p = HTTP_PARSER_SUCCESS;
int32_t bytes_left = size;
switch (client->http_version)
{
case AISL_HTTP_0_9:
case AISL_HTTP_1_0:
case AISL_HTTP_1_1:
/* s = client->stream; */
while ( p == HTTP_PARSER_SUCCESS )
{
switch ( aisl_stream_get_state(s) )
{
case AISL_STREAM_STATE_IDLE:
p = http_10_parse_request(data, &size, client->stream);
break;
case AISL_STREAM_STATE_WAIT_HEADER:
p = http_10_parse_header(data, &size, client->stream);
break;
case AISL_STREAM_STATE_WAIT_BODY:
p = http_10_parse_body(data, &size, client->stream);
break;
default: /* has input data, but request was already parsed */
p = HTTP_PARSER_ERROR;
continue;
}
// size now has number of parsed bytes
data += size;
bytes_left -= size;
size = bytes_left;
}
break;
case AISL_HTTP_2_0:
break;
}
switch(p)
{
case HTTP_PARSER_READY:
client->flags &= ~FLAG_CAN_READ;
client->flags |= FLAG_CAN_WRITE;
aisl_raise(
client->server->instance
, (void *) s
, AISL_EVENT_STREAM_REQUEST
, result
);
break;
case HTTP_PARSER_ERROR:
/* reply Bad Request here */
client->stream->http_response = AISL_HTTP_BAD_REQUEST;
aisl_raise(
client->server->instance
, (void *) s
, AISL_EVENT_STREAM_ERROR
, result
);
aisl_client_close(client, result);
return result;
default:
break;
}
if (size)
buffer_shift(&client->in, client->in.used - size); /* reset buffer */
return result;
}
/* In HTTP 2.0 client->stream will be NULL if stream related data was completely
* parsed. If it is not NULL, then stream expects additional data -> same like
* in mono stream HTTP 1.0
*/
static AislStatus
aisl_client_input(AislClient client)
{
int l;
char * data = &client->in.data[ client->in.used ];
int32_t size = client->in.size - client->in.used;
#ifndef AISL_WITHOUT_SSL
if (client->ssl)
{
DPRINTF("SSL_read");
if ( !(client->flags & FLAG_HANDSHAKE) )
{
if ( (l = SSL_accept(client->ssl)) != 1 )
{
l = SSL_get_error(client->ssl, l);
if (l == SSL_ERROR_WANT_READ || l == SSL_ERROR_WANT_WRITE)
return AISL_IDLE;
DPRINTF("SSL handshake fail: %s\n", ERR_error_string(l, NULL) );
aisl_client_close(client, AISL_EXTCALL_ERROR);
return AISL_EXTCALL_ERROR;
}
client->flags &= ~FLAG_HANDSHAKE;
}
l = SSL_read(client->ssl, data, size) ;
}
else
#endif
l = recv( client->fd, data, size, 0);
if (l > 0)
{
DPRINTF("%d bytes received from client", l);
data = client->in.data;
size = client->in.used + l;
client->in.used = size;
return aisl_client_parse(client, data, size);
}
else if (l<0)
{
#ifndef AISL_WITHOUT_SSL
if (client->ssl)
{
if (SSL_get_error(client->ssl, l) == SSL_ERROR_WANT_READ)
return AISL_IDLE;
}
else
#endif
{
if(errno == EWOULDBLOCK)
return AISL_IDLE;
DPRINTF("client - %s", strerror(errno));
}
}
/* both: client disconnect + on read error */
/* todo: raise client error here */
aisl_client_close(client, AISL_SYSCALL_ERROR);
return AISL_SYSCALL_ERROR;
}
static AislStatus
aisl_client_output(AislClient client)
{
int l;
char * data;
AislStream s = client->stream;
/* while stream is not flushed, we should raise event */
if( aisl_get_output_event(s) )
{
/* in case of chunked output ( subscription for AISL_STREAM_OUTPUT event )
* stream buffer will be initialized with OUTPUT_BUFFER_SIZE size, but
* buffer->size will be used to carry amount of stored bytes
* */
l = aisl_stream_get_buffer_space(s);
/*
if (bsz < OUTPUT_BUFFER_SIZE)
{
if (buffer_clear(s->buffer, OUTPUT_BUFFER_SIZE) == 0)
return false;
s->buffer->size = bsz;
bsz = OUTPUT_BUFFER_SIZE;
}
*/
if ( !(l < aisl_stream_get_buffer_size(s) / 2) )
{
aisl_raise(
client->server->instance
, (void*)s
, AISL_EVENT_STREAM_OUTPUT
, AISL_SUCCESS
);
}
}
data = aisl_stream_get_data(s, &l);
if ( !l )
return AISL_IDLE;
#ifdef AISL_WITHOUT_SSL
l = send( client->fd, data, l, 0);
#else
l = (client->ssl) ?
SSL_write(client->ssl, data, l) :
send( client->fd, data, l, 0);
#endif
if (l > 0)
{
aisl_stream_shift(s, l);
/*
if (s->state == STREAM_RESPONSE_READY && / * flushed * /
s->buffer->size == 0) / * all sent * /
*/
if ( aisl_stream_is_done(s) )
{
/* buffer_clear(s->buffer, 0); */
/* data has been sent */
if (client->flags & FLAG_KEEPALIVE)
{
aisl_stream_free(s);
client->stream = aisl_stream_new(client, client->next_id++);
if (client->stream != NULL )
return AISL_SUCCESS;
/* in case of malloc error it will not be error as long as request was
* handled and we just close the connection.
*/
}
aisl_client_close(client, AISL_SUCCESS);
}
return AISL_SUCCESS;
}
/* l < 0 */
#ifndef AISL_WITHOUT_SSL
if (client->ssl)
{
if ( SSL_get_error(client->ssl, l) == SSL_ERROR_WANT_WRITE )
return AISL_IDLE;
}
else
#endif
{
if (errno == EWOULDBLOCK)
return AISL_IDLE;
}
aisl_client_close(client, AISL_SYSCALL_ERROR);
return AISL_SYSCALL_ERROR;
}
AislClient
aisl_client_new( AislServer server,
int fd,
struct sockaddr_in * addr )
{
AislClient client;
AislStream stream;
if ( (client = calloc(1, sizeof (struct aisl_client))) != NULL )
{
DPRINTF("client alocated");
memcpy(&client->address, addr, sizeof (struct sockaddr_in));
client->server = server;
client->fd = fd;
client->next_id = 2;
client->http_version = AISL_HTTP_1_0;
client->timestamp = time(NULL);
client->flags = FLAG_KEEPALIVE | FLAG_HANDSHAKE | FLAG_CAN_READ;
if (buffer_init(&client->in, 2*BUFFER_SIZE) != -1)
{
DPRINTF("client buffer alocated");
memcpy(&client->out, &client->in, sizeof (struct buffer));
stream = aisl_stream_new(client, 0);
if (stream != NULL)
{
client->stream = stream;
DPRINTF("client stream alocated");
#ifdef AISL_WITHOUT_SSL
return client;
#else
SSL_CTX * ssl_ctx;
if ( !server->ssl )
return client;
ssl_ctx = aisl_get_ssl_ctx(server->instance, NULL);
if ((client->ssl = SSL_new(ssl_ctx)) != NULL )
{
SSL_set_fd(client->ssl, fd);
return client;
}
#endif
}
}
aisl_client_free(client);
}
return NULL;
}
void
aisl_client_free(AislClient client)
{
aisl_client_close(client, AISL_SUCCESS);
#ifndef AISL_WITHOUT_SSL
if (client->ssl)
SSL_free(client->ssl);
#endif
if (client->in.data)
free(client->in.data);
/* out buffer is a shared part of input buffer, so no need to free it */
if (client->stream)
aisl_stream_free(client->stream);
free(client);
}
AislStatus
AislClientouch(AislClient client, int32_t timeout)
{
AislStatus result = AISL_IDLE,
status = AISL_IDLE;
/* input */
if (client->flags & FLAG_CAN_READ)
{
if ( (result = aisl_client_input(client)) < 0 )
return result;
}
/* output */
if (client->flags & FLAG_CAN_WRITE)
{
if ( (status = aisl_client_output(client)) < 0 )
return status;
}
/*
if ((client->http_version==AISL_HTTP_2_0 || s->state<STREAM_REQUEST_READY) &&
(client_input(client)) ) result = true;
*/
/* output */
/*
s = list_index(client->streams, client->ostream);
if ( s->flags & (STREAM_FLAG_OUTPUT_READY | STREAM_FLAG_OUTPUT_CHUNKED) )
result = client_output(client);
*/
/* update timestamp */
if (result == AISL_IDLE)
result = status;
if (result == AISL_SUCCESS)
client->timestamp = time(NULL);
else
{
time_t now;
time(&now);
if ( !(now - client->timestamp < timeout) )
{
aisl_client_close(client, result);
}
}
return result;
}
int
aisl_client_get_socket(AislClient client)
{
return client->fd;
}
bool
aisl_client_get_keepalive(AislClient client)
{
return (client->flags & FLAG_KEEPALIVE);
}
void
aisl_client_set_keepalive(AislClient client, bool value)
{
if (value)
client->flags |= FLAG_KEEPALIVE;
else
client->flags &= ~FLAG_KEEPALIVE;
}
/* API Level ---------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
AislServer
aisl_client_get_server(AislClient client)
{
return client->server;
}
__attribute__ ((visibility ("default") ))
bool
aisl_client_is_secure(AislClient client)
{
#ifdef AISL_WITHOUT_SSL
return false;
#else
return (client->ssl == NULL) ? false : true;
#endif
}
__attribute__ ((visibility ("default") ))
bool
aisl_client_is_online(AislClient client)
{
return (client->fd == -1) ? false : true;
}
__attribute__ ((visibility ("default") ))
void
aisl_client_disconnect(AislClient client)
{
aisl_client_close(client, AISL_SUCCESS);
}
__attribute__ ((visibility ("default") ))
AislHttpVersion
aisl_client_get_http_version(AislClient client)
{
return client->http_version;
}
__attribute__ ((visibility ("default") ))
void
aisl_client_get_address( AislClient client, struct sockaddr_in * address)
{
memcpy(address, &client->address, sizeof (struct sockaddr_in));
}
+115
View File
@@ -0,0 +1,115 @@
#
# Makefile
# Ilja Kartašov, 2019-07-13 14:51
#
.POSIX:
CC ?= gcc
AR ?= ar
PKG_CONFIG ?= pkg-config
PREFIX ?= /usr/local
DESTDIR ?=
LIB_DIR ?= lib
TARGET_NAME = aisl
OUT_DIR ?= ../build
SRC_DIR ?= .
# Version
VERSION_MAJOR = 1
VERSION_MINOR = 0
VERSION_TWEAK = 5
VERSION_LABEL = 0
# Source files
SOURCE_FILES := \
$(SRC_DIR)/instance.c \
$(SRC_DIR)/server.c \
$(SRC_DIR)/client.c \
$(SRC_DIR)/stream.c \
$(SRC_DIR)/http.c \
$(SRC_DIR)/ssl.c \
$(SRC_DIR)/list.c \
$(SRC_DIR)/str-utils.c \
$(SRC_DIR)/buffer.c \
$(SRC_DIR)/types.c \
# compilation macro options:
AISL_WITH_DEBUG ?= 0 # disable debug output
AISL_WITH_SSL ?= 1 # enable SSL support
AISL_WITH_STRINGIFIERS ?= 1 # enable *_to_string functions
CFLAGS := \
-std=c99 \
-pedantic \
-Wall \
-Wmissing-prototypes \
-Wstrict-prototypes \
-Wold-style-definition \
-O2 \
-s \
-fvisibility=hidden \
\
-I../ \
-I../include \
\
-D_POSIX_C_SOURCE=200809L \
-DAISL_WITH_DEBUG=$(AISL_WITH_DEBUG) \
-DAISL_WITH_SSL=$(AISL_WITH_SSL) \
-DAISL_WITH_STRINGIFIERS=$(AISL_WITH_STRINGIFIERS) \
\
`$(PKG_CONFIG) --cflags openssl` \
$(CFLAGS) \
LDFLAGS := \
`$(PKG_CONFIG) --libs openssl` \
# flags
SOURCE_LIST := $(wildcard $(SOURCE_FILES))
SHARED_OBJS := $(addsuffix .o, $(addprefix $(OUT_DIR)/shared/, ${SOURCE_LIST}))
STATIC_OBJS := $(addsuffix .o, $(addprefix $(OUT_DIR)/static/, ${SOURCE_LIST}))
all: lib$(TARGET_NAME).so lib$(TARGET_NAME).a
$(info AISL_WITH_DEBUG=$(AISL_WITH_DEBUG))
$(info AISL_WITH_SSL=$(AISL_WITH_SSL))
$(info AISL_WITH_STRINGIFIERS=$(AISL_WITH_STRINGIFIERS))
lib$(TARGET_NAME).so: $(SHARED_OBJS)
$(info building target: $@)
@$(CC) -shared -o $(OUT_DIR)/$@ $(SHARED_OBJS) $(LDFLAGS)
$(info done: $@)
lib$(TARGET_NAME).a: $(STATIC_OBJS)
$(info building target: $@)
@$(AR) rcs $(OUT_DIR)/$@ $(STATIC_OBJS)
$(info done: $@)
$(OUT_DIR)/shared/%.o: %
$(info compiling file: $<)
@mkdir -p $(dir $@)
@$(CC) $(CFLAGS) -fpic -c $< -o $@
$(OUT_DIR)/static/%.o: %
$(info compiling file: $<)
@mkdir -p $(dir $@)
@$(CC) $(CFLAGS) -c $< -o $@
install:lib$(TARGET_NAME).so lib$(TARGET_NAME).a
$(info installing files)
@mkdir -p $(DESTDIR)$(PREFIX)/$(LIB_DIR)
@mkdir -p $(DESTDIR)$(PREFIX)/include
@cp $(OUT_DIR)/lib$(LIBRARY_NAME).so $(DESTDIR)$(PREFIX)/$(LIB_DIR)
@cp $(OUT_DIR)/lib$(LIBRARY_NAME).a $(DESTDIR)$(PREFIX)/$(LIB_DIR)
@cp -R include/aisl $(DESTDIR)$(PREFIX)/include
# vim:ft=make
#
+1 -1
Submodule sdk updated: b9e247b88f...e00ffe6f70
+88
View File
@@ -0,0 +1,88 @@
#
# Makefile
# Ilja Kartašov, 2019-07-13 14:51
#
.POSIX:
CC ?= gcc
PKG_CONFIG ?= pkg-config
PREFIX ?= /usr/local
DESTDIR ?=
BIN_DIR ?= bin
TARGET_NAME = aisl
OUT_DIR ?= ../build
SRC_DIR ?= .
SDK_DIR ?= ../sdk
CSTUFF_DIR ?= ../cStuff
# Version
VERSION_MAJOR = 0
VERSION_MINOR = 1
VERSION_TWEAK = 0
VERSION_LABEL = 0
# Source files
SOURCE_FILES := \
$(SRC_DIR)/main.c \
$(SRC_DIR)/option.c \
$(SRC_DIR)/compose.c \
\
$(SDK_DIR)/components/html.c \
\
$(CSTUFF_DIR)/list.c \
$(CSTUFF_DIR)/string.c \
# compilation macro options:
CFLAGS := \
-std=c99 \
-pedantic \
-Wall \
-Wmissing-prototypes \
-Wstrict-prototypes \
-Wold-style-definition \
-O2 \
-s \
\
-I../ \
-I$(SDK_DIR) \
\
-D_POSIX_C_SOURCE=200809L \
-DEXECUTABLE="$(TARGET_NAME)" \
-DVERSION_MAJOR=$(VERSION_MAJOR) \
-DVERSION_MINOR=$(VERSION_MINOR) \
-DVERSION_TWEAK=$(VERSION_TWEAK) \
-DVERSION_LABEL=$(VERSION_LABEL) \
\
$(CFLAGS) \
LDFLAGS :=
# flags
SOURCE_LIST := $(wildcard $(SOURCE_FILES))
OBJECT_LIST := $(addsuffix .o, $(addprefix $(OUT_DIR)/tool/, ${SOURCE_LIST}))
all: $(TARGET_NAME)
$(TARGET_NAME): $(OBJECT_LIST)
$(info building target: $@)
@$(CC) -o $(OUT_DIR)/$@ $(OBJECT_LIST) $(LDFLAGS)
$(info done: $@)
$(OUT_DIR)/tool/%.o: %
$(info compiling file: $<)
@mkdir -p $(dir $@)
@$(CC) $(CFLAGS) -c $< -o $@
install: $(TARGET_NAME)
$(info installing files)
@cp $(OUT_DIR)/$< $(DESTDIR)$(PREFIX)/$(BIN_DIR)
# vim:ft=make
#
+84
View File
@@ -0,0 +1,84 @@
/******************************************************************************
*
* Copyright (c) 2017-2019 by Löwenware Ltd
* Please, refer LICENSE file for legal information
*
******************************************************************************/
/**
* @file compose.c
* @author Ilja Kartašov <ik@lowenware.com>
* @brief
*
* @see https://lowenware.com/
*/
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <components/html.h>
#include "option.h"
#include "compose.h"
static int
compose_help(void)
{
printf("NAME\n");
printf("\taisl-compose - Compose plain text resource\n\n");
printf("SYNOPSIS\n");
printf("\taisl compose [--format=auto|html|js|css] <source> <target>\n\n");
printf("DESCRIPTION\n");
printf("\tComposes a plain text resource to its production version.");
printf("OPTIONS\n");
printf("\t--format=auto|html|js|css\n");
printf("\t Manually set format for the composer. Usefull when file "
"extension does not allow to determine type automatically.\n\n");
return 0;
}
int
compose_execute(int argc, char **argv)
{
int result;
struct cstuff_list list;
struct ax_html_options opts = {0};
if (g_options & OPTION_FLAG_HELP) {
return compose_help();
}
result = -1;
if (!(argc == 1 || argc == 2)) {
return result;
}
g_source = argv[0];
if (argc == 2) {
g_target = argv[1];
}
opts.offset = "\t";
opts.path = g_target ? g_target : ".";
opts.name = "html";
opts.minimize = true;
if (!cstuff_list_init(&list, 128)) {
if (ax_html_import(&list, g_source) == AISL_SUCCESS) {
if (ax_html_export(&list, &opts) == AISL_SUCCESS) {
result = 0;
} else {
fprintf(stderr, "Export failed\n");
}
} else {
fprintf(stderr, "Import failed: %s\n", strerror(errno));
}
cstuff_list_release(&list, (CStuffListFree)ax_html_free);
}
return result;
}
+23
View File
@@ -0,0 +1,23 @@
/******************************************************************************
*
* Copyright (c) 2017-2019 by Löwenware Ltd
* Please, refer LICENSE file for legal information
*
******************************************************************************/
/**
* @file compose.h
* @author Ilja Kartašov <ik@lowenware.com>
* @brief
*
* @see https://lowenware.com/
*/
#ifndef COMPOSE_H_006245E9_DAFB_4160_AB48_2268FA6E0769
#define COMPOSE_H_006245E9_DAFB_4160_AB48_2268FA6E0769
int
compose_execute(int argc, char **argv);
#endif /* !COMPOSE_H */
+23
View File
@@ -0,0 +1,23 @@
/******************************************************************************
*
* Copyright (c) 2017-2019 by Löwenware Ltd
* Please, refer LICENSE file for legal information
*
******************************************************************************/
/**
* @file globals.h
* @author Ilja Kartašov <ik@lowenware.com>
* @brief
*
* @see https://lowenware.com/
*/
#ifndef GLOBALS_H_ECAB54AF_855F_408C_9CC1_65B994859848
#define GLOBALS_H_ECAB54AF_855F_408C_9CC1_65B994859848
#include <stdint.h>
extern uint32_t g_options;
#endif /* !GLOBALS_H */
+40
View File
@@ -0,0 +1,40 @@
/******************************************************************************
*
* Copyright (c) 2017-2019 by Löwenware Ltd
* Please, refer LICENSE file for legal information
*
******************************************************************************/
/**
* @file main.c
* @author Ilja Kartašov <ik@lowenware.com>
* @brief
*
* @see https://lowenware.com/
*/
#include <stdio.h>
#include "option.h"
#include "compose.h"
int
main(int argc, char **argv)
{
int result;
if ((result = option_read_args(argc, argv)) != -1) {
switch (g_options & 0xFF) {
case OPTION_COMMAND_COMPOSE:
if (!compose_execute(argc - result, &argv[result]))
return 0;
break;
default:
result = -1;
break;
}
}
printf("For usage guideance run `%s --help`\n", argv[0]);
return result;
}
+72
View File
@@ -0,0 +1,72 @@
/******************************************************************************
*
* Copyright (c) 2017-2019 by Löwenware Ltd
* Please, refer LICENSE file for legal information
*
******************************************************************************/
/**
* @file option.c
* @author Ilja Kartašov <ik@lowenware.com>
* @brief
*
* @see https://lowenware.com/
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "option.h"
uint32_t g_options = 0;
const char *g_format = NULL;
const char *g_source = NULL;
const char *g_target = NULL;
static void
option_set_command(int command)
{
if (!(g_options & 0xFF)) {
g_options |= command;
}
}
int
option_read_args(int argc, char **argv)
{
int i;
char c = 0;
for (i = 1; i < argc; i++) {
switch (c) {
case 'f':
g_format = argv[i];
break;
default:
if (strcmp(argv[i], "-f") == 0) {
c = 'f';
} else if (!strncmp(argv[i], "--format=", 9)) {
g_format = &argv[i][9];
} else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
g_options |= OPTION_FLAG_HELP;
} else if (!strcmp(argv[i], "compose")) {
option_set_command(OPTION_COMMAND_COMPOSE);
} else {
return i;
}
continue;
}
c = 0;
}
if (c) {
fprintf(stderr, "No value for -%c argument", c);
return -1;
}
return i - 1;
}
+39
View File
@@ -0,0 +1,39 @@
/******************************************************************************
*
* Copyright (c) 2017-2019 by Löwenware Ltd
* Please, refer LICENSE file for legal information
*
******************************************************************************/
/**
* @file option.h
* @author Ilja Kartašov <ik@lowenware.com>
* @brief
*
* @see https://lowenware.com/
*/
#ifndef OPTION_H_FC8ABD38_1EF9_4DD2_A94A_3C4F53E0A437
#define OPTION_H_FC8ABD38_1EF9_4DD2_A94A_3C4F53E0A437
#include <stdint.h>
#define OPTION_FLAG_HELP (1 << 16)
enum {
OPTION_COMMAND_UNKNOWN
, OPTION_COMMAND_COMPOSE
};
extern uint32_t g_options;
extern const char *g_format;
extern const char *g_source;
extern const char *g_target;
int
option_read_args(int argc, char **argv);
#endif /* !OPTION_H */