Compare commits
5
Commits
06c99b1e4b
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
89ef04cfd4 | ||
|
|
aff6ab6fb2 | ||
|
|
043d414df4 | ||
|
|
ce7eda1820 | ||
|
|
006efe8692 |
+1
-21
@@ -1,26 +1,6 @@
|
|||||||
# Binaries
|
build/
|
||||||
|
|
||||||
build/*
|
|
||||||
root/*
|
|
||||||
demo/*
|
|
||||||
|
|
||||||
bin/*
|
|
||||||
obj/*
|
|
||||||
webstuff-*
|
|
||||||
Makefile
|
|
||||||
tmp
|
|
||||||
tmp/*
|
|
||||||
*.tar.gz
|
*.tar.gz
|
||||||
*.zip
|
*.zip
|
||||||
*.rar
|
*.rar
|
||||||
*.gz
|
*.gz
|
||||||
*.bz2
|
*.bz2
|
||||||
pkg/*
|
|
||||||
|
|
||||||
include/webstuff_bak
|
|
||||||
|
|
||||||
CMakeCache.txt
|
|
||||||
CMakeFiles/*
|
|
||||||
cmake_install.cmake
|
|
||||||
libaisl.dylib
|
|
||||||
demo/demo
|
|
||||||
|
|||||||
+4
-4
@@ -1,6 +1,6 @@
|
|||||||
|
[submodule "sdk"]
|
||||||
|
path = sdk
|
||||||
|
url = https://git.lowenware.com/lowenware/aisl-sdk.git
|
||||||
[submodule "cStuff"]
|
[submodule "cStuff"]
|
||||||
path = cStuff
|
path = cStuff
|
||||||
url = git@lowenware.com:lowenware/cStuff.git
|
url = https://git.lowenware.com/lowenware/cStuff.git
|
||||||
[submodule "aisl-sdk"]
|
|
||||||
path = aisl-sdk
|
|
||||||
url = git@lowenware.com:lowenware/aisl-sdk.git
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
#
|
||||||
-1
Submodule aisl-sdk deleted from b9e247b88f
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
@@ -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
|
|
||||||
#
|
|
||||||
@@ -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));
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
|
#
|
||||||
Submodule
+1
Submodule sdk added at e00ffe6f70
@@ -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
|
||||||
|
#
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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 */
|
||||||
@@ -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
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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 */
|
||||||
Reference in New Issue
Block a user