feat(http-post-update): initial commit

This commit is contained in:
dancingCycle 2023-03-24 15:54:17 +01:00
parent cf67adffef
commit cfd9dfef5a
9 changed files with 786 additions and 0 deletions

1
http-post-update/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
cfg-sib00_rgncycle.txt

8
http-post-update/cfg.txt Normal file
View File

@ -0,0 +1,8 @@
pq =
{
db = "database";
host = "localhost";
port = 5432;
secret = "secret";
user = "user";
}

View File

@ -0,0 +1,84 @@
/*to use exit*/
#include <stdlib.h>
/*to use *print**/
#include <stdio.h>
/*to user file2char*/
#include "file2char.h"
int convert_file2char(char const* path, char **buf){
/*declarations*/
FILE *fp;
long lSize;
/*TODO Check path for validity!*/
/*fopen()
*filename
*mode
*return: set errno value in error case
*/
fp=fopen(path,"r");
if(fp){
fprintf(stdout,"file opened.\n");
/*set offset to file end*/
/*fseek()
*stream
*offset
*origin
*/
fseek(fp,0L,SEEK_END);
if (ferror(fp)){
printf ("Error seeking file\n");
}
/*get file size*/
lSize = ftell( fp );
fprintf(stdout,"lSize: %ld.\n",lSize);
/*set offset to file start*/
fseek(fp,0,SEEK_SET);
if (ferror(fp)){
printf ("Error seeking file\n");
}
/*allocate memory for entire content + null termination*/
*buf=(char *)malloc((lSize+1)*sizeof(char));
if(!*buf){
fclose(fp);
fputs("Error allocating memory",stderr);
exit(EXIT_FAILURE);
}
fprintf(stdout,"mem allocated.\n");
/*copy file into buffer*/
/*fread()
*ptr
*size
*count
*stream
*/
if( 1!=fread(*buf,lSize,1,fp)){
fclose(fp);
free(*buf);
fputs("Error reading entire file",stderr);
exit(EXIT_FAILURE);
}
fprintf(stdout,"file read.\n");
/*close file*/
if(EOF==fclose(fp)){
free(*buf);
exit(EXIT_FAILURE);
}
fprintf(stdout,"file closed.\n");
(*buf)[lSize] = '\0';
fprintf(stdout,"mem null terminated.\n");
}else{
perror(path);
exit(EXIT_FAILURE);
}
/*done*/
return 0;
}

View File

@ -0,0 +1,16 @@
/*We can use CPP tricks to avoid parsing the same header file more than once*/
#ifndef FILE2CHAR_H
#define FILE2CHAR_H
/*
* convert_file2char reads the file identified by 'path' into a character buffer
* pointed at by 'buf'.
* On success, 0 is returned.
* On failure, exit(EXIT_FAILURE) is returned.
*
* WARNING: convert_file2char malloc()s memory to '*buf' which must be freed by
* the caller.
*/
int convert_file2char(char const* path, char **buf);
#endif /* FILE2CHAR_H */

521
http-post-update/main.c Normal file
View File

@ -0,0 +1,521 @@
/*to create API*/
#include <ulfius.h>
/*to connect to Postgresql*/
#include <libpq-fe.h>
/* to use JSON in response body*/
#include <jansson.h>
/*to use strcat*/
#include <string.h>
/*to use inet_ntoa*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/*to use *print**/
#include <stdio.h>
/*to use struct pq_confo*/
#include "pqconfo.h"
/*to use file2char*/
#include "file2char.h"
#define PREFIX "/test"
#define ROUTE_HELLO "/hello"
#define ROUTE_ENTITIES "/entities"
#define PREFIX "/test"
/**
* callback functions declaration
*/
int callback_get_hello (const struct _u_request * request, struct _u_response * response, void * user_data);
int callback_default (const struct _u_request * request, struct _u_response * response, void * user_data);
int callback_create_entity (const struct _u_request * request, struct _u_response * response, void * user_data);
int callback_get_entities (const struct _u_request * request, struct _u_response * response, void * user_data);
int callback_get_entity (const struct _u_request * request, struct _u_response * response, void * user_data);
int callback_update_entity (const struct _u_request * request, struct _u_response * response, void * user_data);
int callback_delete_entity (const struct _u_request * request, struct _u_response * response, void * user_data);
int callback_all_test_foo (const struct _u_request * request, struct _u_response * response, void * user_data);
/**
* decode a u_map into a string
*/
char * print_map(const struct _u_map * map) {
/*declaration*/
char * line, * to_return = NULL;
const char **keys, * value;
int len, i;
if (map != NULL) {
keys = u_map_enum_keys(map);
for (i=0; keys[i] != NULL; i++) {
value = u_map_get(map, keys[i]);
len = snprintf(NULL, 0, "key is %s, value is %s", keys[i], value);
line = malloc((size_t)(len+1));
snprintf(line, (size_t)(len+1), "key is %s, value is %s", keys[i], value);
if (to_return != NULL) {
len = (int)(strlen(to_return) + strlen(line) + 1);
to_return = realloc(to_return, (size_t)(len+1));
if (strlen(to_return) > 0) {
//concatenate strings
strcat(to_return, "\n");
}
} else {
to_return = malloc((strlen(line) + 1));
to_return[0] = 0;
}
strcat(to_return, line);
free(line);
}
return to_return;
} else {
return NULL;
}
}
int main(int argc, char *argv[]) {
/*declaration*/
struct _u_instance instance;
int frameworkRet, apiPort, apiPortRet, cx;
/*TODO How is const defined?*/
const int pqConInfoSize = 100;
char pqConInfo[pqConInfoSize];
int pqConfoRet;
const struct pq_confo * pqConfo;
printf("main() Started...\n");
if (argc != 3) {
fprintf(stderr, "Usage: ./main <API port> <path to config file>\n");
return 1;
}
printf("main() argv[1]: %s\n", argv[1]);
printf("main() argv[2]: %s\n", argv[2]);
/*get Postgresql connection info from config*/
/*TODO Validate argv!*/
pqConfoRet=get_pq_confo(argv[2],&pqConfo);
if(pqConfoRet){
fprintf(stderr, "Postgresql connection information are NOT valid\n");
return 2;
}else{
fprintf(stdout,"pqConfoRet: %d\n",pqConfoRet);
}
/*create pq connection info*/
cx = snprintf(pqConInfo,pqConInfoSize,"postgresql://%s:%s@%s:%d/%s",pqConfo->user,pqConfo->secret,pqConfo->host,pqConfo->port,pqConfo->db);
if(0>cx && cx>=pqConInfoSize){
fprintf(stderr,"main() error creating pqConInfo\n");
/*free Postgresql connection info*/
pqConfoRet=free_pq_confo(&pqConfo);
if(pqConfoRet){
fprintf(stderr, "Postgresql connection information are NOT free\n");
return 3;
}
return 4;
}
/*free Postgresql connection info*/
pqConfoRet=free_pq_confo(&pqConfo);
if(pqConfoRet){
fprintf(stderr, "Postgresql connection information are NOT free\n");
return 5;
}
/*store command line argument in variable*/
/*validate user input*/
/*omit injection*/
/*stream:argv*/
apiPortRet = sscanf(argv[1], "%d", &apiPort);
/*valid user input:1 successfully filled item*/
if (apiPortRet != 1) {
fprintf(stderr, "The argument must be an integer\n");
return 6;
}
if (apiPort < 0) {
fprintf(stderr, "Error passing a negative port\n");
exit(1);
}
printf("main() port: %d\n", apiPort);
/*TODO Is mem leaked when connection to pq failes?*/
if (ulfius_init_instance(&instance, apiPort, NULL, NULL) != U_OK) {
printf("main() Error ulfius_init_instance, abort");
return 7;
}
/*connect to database*/
//TODO This is a synchronous call! Shall we block the rest?
PGconn *conn = PQconnectdb(pqConInfo);
if (PQstatus(conn) == CONNECTION_BAD) {
fprintf(stderr, "Connection to database failed: %s\n",
PQerrorMessage(conn));
PQfinish(conn);
return 8;
}else if(PQstatus(conn)==CONNECTION_OK){
printf("main() connected to database\n");
}else{
printf("main() connection status NOT known\n");
}
//TODO Why?
u_map_put(instance.default_headers, "Access-Control-Allow-Origin", "*");
// Maximum body size sent by the client is 1 Kb
instance.max_post_body_size = 1024;
// Endpoint list declaration
ulfius_add_endpoint_by_val(&instance, "GET", ROUTE_HELLO, NULL, 0, &callback_get_hello, NULL);
//user_data: pass pq connection information to callback
ulfius_add_endpoint_by_val(&instance, "POST", ROUTE_ENTITIES, "/create", 0, &callback_create_entity, (void *)conn);
//user_data: pass pq connection information to callback
ulfius_add_endpoint_by_val(&instance, "GET", ROUTE_ENTITIES, "/info", 0, &callback_get_entities, (void *)conn);
//user_data: pass pq connection information to callback
ulfius_add_endpoint_by_val(&instance, "GET", ROUTE_ENTITIES, "/:id/info", 0, &callback_get_entity, (void *)conn);
//user_data: pass pq connection information to callback
ulfius_add_endpoint_by_val(&instance, "POST", ROUTE_ENTITIES, "/:id/update", 0, &callback_update_entity, (void *)conn);
//user_data: pass pq connection information to callback
ulfius_add_endpoint_by_val(&instance, "DELETE", ROUTE_ENTITIES, "/:id/delete", 0, &callback_delete_entity, (void *)conn);
ulfius_add_endpoint_by_val(&instance, "GET", PREFIX, "/param/:foo", 0, &callback_all_test_foo, "user data 1");
ulfius_add_endpoint_by_val(&instance, "POST", PREFIX, "/param/:foo", 0, &callback_all_test_foo, "user data 2");
ulfius_add_endpoint_by_val(&instance, "PUT", PREFIX, "/param/:foo", 0, &callback_all_test_foo, "user data 3");
ulfius_add_endpoint_by_val(&instance, "DELETE", PREFIX, "/param/:foo", 0, &callback_all_test_foo, "user data 4");
// default_endpoint declaration
ulfius_set_default_endpoint(&instance, &callback_default, NULL);
// Start the framework
// Open an http connection
frameworkRet = ulfius_start_framework(&instance);
if (frameworkRet == U_OK) {
printf("main() Start framework on port %d\n", instance.port);
/*wait*/
while(1){
sleep(3600);
}
} else {
printf("main() Error starting framework; frameworkRet: %d\n",frameworkRet);
}
printf("main() End framework\n");
/*clean up API*/
ulfius_stop_framework(&instance);
ulfius_clean_instance(&instance);
/*clean up Postgresql connection*/
PQfinish(conn);
printf("main() Done.\n");
return 0;
}
/**
* Callback function that put a "Hello World!" string in the response
*/
int callback_get_hello (const struct _u_request * request, struct _u_response * response, void * user_data) {
ulfius_set_string_body_response(response, 200, "Hello World!");
return U_CALLBACK_CONTINUE;
}
/**
* Default callback function called if no endpoint has a match
*/
int callback_default (const struct _u_request * request, struct _u_response * response, void * user_data) {
ulfius_set_string_body_response(response, 404, "Page not found, do what you want");
return U_CALLBACK_CONTINUE;
}
/**
* Callback function for route /entities to reply the entity at question
*/
int callback_get_entity (const struct _u_request * request, struct _u_response * response, void * user_data) {
/*declarations*/
char *url_params;
char *response_body;
int r;
const char **keys;
const char *value;
char *line;
int len;
int i;
PGconn *conn;
char *prepStmEntities;
PGresult *pqRes;
int nbRecords,nbFields;
json_t *arrayRecords, *arrayFields, *stringField;
printf("callback_get_entity() Started...\n");
url_params = print_map(request->map_url);
r=asprintf(
&response_body,
"parameters from the url are \n%s\n\n",
url_params);
//printf("callback_get_entity() %d characters generated\n",r);
if(request->map_url != NULL){
keys=u_map_enum_keys(request->map_url);
if(keys[0] == NULL){
//TODO error
printf("callback_get_entity() param NOT available\n");
//TODO Why this casting?
(void)(request);
(void)(user_data);
ulfius_set_string_body_response(response, 500, "This is the /entity/:id/info route: Param error!");
}else{
value = u_map_get(request->map_url, keys[0]);
//printf("callback_get_entity() key is %s, value is %s\n", keys[0], value);
conn = (PGconn *)user_data;
/*define prepared statement*/
len=snprintf(NULL,0,"SELECT * FROM entities WHERE id=%s;",value);
prepStmEntities=malloc((size_t)(len+1));
//TODO Release prepStmEntities!
snprintf(prepStmEntities,(size_t)(len+1),"SELECT * FROM entities WHERE id=%s;",value);
//printf("callback_get_entity() prepStmEntities: %s\n",prepStmEntities);
/*create prepared statement*/
/*conn:connection*/
/*stm:statement*/
/*0:number of passed parameters*/
/*NULL: server figures out parameter type*/
/*paramValues:pointer of an array of strings containing parameters*/
/*NULL:relevant for binary parameters*/
/*NULL:relevant for binary parameters*/
/*0:obtain result in text format*/
//TODO How to pass params?
pqRes = PQexecParams(conn, prepStmEntities, 0, NULL, NULL, NULL, NULL, 0);
if(PQresultStatus(pqRes) != PGRES_TUPLES_OK) {
/*handle error*/
printf("callback_get_entity() No data retrieved\n");
/*clean up result*/
PQclear(pqRes);
//TODO Why this casting?
(void)(request);
(void)(user_data);
ulfius_set_string_body_response(response, 500, "This is the /entity/:id/info route: Dba error!");
}else{
/*evaluate result*/
nbRecords = PQntuples(pqRes);
//printf("callback_get_entity() nbRecords: %d\n",nbRecords);
nbFields = PQnfields(pqRes);
arrayRecords=json_array();
for(int i=0;i<nbRecords;i++){
arrayFields=json_array();
for(int j=0;j<nbFields;j++){
stringField = json_string(PQgetvalue(pqRes,i,j));
json_array_append(arrayFields, stringField);
json_decref(stringField);
}
json_array_append(arrayRecords, arrayFields);
json_decref(arrayFields);
}
/*clean up result*/
PQclear(pqRes);
/*set response body*/
ulfius_set_json_body_response(response, 200, arrayRecords);
/*clean up JSON*/
json_decref(arrayRecords);
//TODO Why this casting?
(void)(request);
(void)(user_data);
}
}
}
/*clean up remainings*/
free(url_params);
free(response_body);
printf("callback_get_entity() Done.\n");
return U_CALLBACK_CONTINUE;
}
/**
* Callback function for route /entities to reply all entities
*/
int callback_get_entities (const struct _u_request * request, struct _u_response * response, void * user_data) {
/*declarations*/
PGconn *conn;
char *prepStmEntities;
PGresult *pqRes;
int nbRecords,nbFields;
json_t *arrayRecords, *arrayFields, *stringField;
printf("callback_get_entities() Started...\n");
conn = (PGconn *)user_data;
/*define prepared statement*/
prepStmEntities = "SELECT * FROM entities;";
/*create prepared statement*/
/*conn:connection*/
/*stm:statement*/
/*1:number of passed parameters*/
/*NULL: server figures out parameter type*/
/*paramValues:pointer of an array of strings containing parameters*/
/*NULL:relevant for binary parameters*/
/*NULL:relevant for binary parameters*/
/*0:obtain result in text format*/
pqRes = PQexecParams(conn, prepStmEntities, 0, NULL, NULL, NULL, NULL, 0);
if (PQresultStatus(pqRes) != PGRES_TUPLES_OK) {
printf("callback_get_entities() No data retrieved\n");
/*clean up result*/
PQclear(pqRes);
//TODO Why this casting?
(void)(request);
(void)(user_data);
ulfius_set_string_body_response(response, 500, "This is the /entities route: Dba error!");
printf("callback_get_entities() Done.\n");
return U_CALLBACK_CONTINUE;
}
/*evaluate result*/
nbRecords = PQntuples(pqRes);
nbFields = PQnfields(pqRes);
arrayRecords=json_array();
for(int i=0;i<nbRecords;i++){
arrayFields=json_array();
for(int j=0;j<nbFields;j++){
/*not password, verification_token_id, created_account*/
if(j!=6&&j!=8&&j!=10){
stringField = json_string(PQgetvalue(pqRes,i,j));
json_array_append(arrayFields, stringField);
json_decref(stringField);
}
}
json_array_append(arrayRecords, arrayFields);
json_decref(arrayFields);
}
/*clean up result*/
PQclear(pqRes);
/*set response body*/
ulfius_set_json_body_response(response, 200, arrayRecords);
/*clean up JSON*/
json_decref(arrayRecords);
//TODO Why this casting?
(void)(request);
(void)(user_data);
printf("callback_get_entities() Done.\n");
return U_CALLBACK_CONTINUE;
}
int callback_delete_entity (const struct _u_request * request, struct _u_response * response, void * user_data) {};
int callback_update_entity (const struct _u_request * request, struct _u_response * response, void * user_data) {};
int callback_create_entity (const struct _u_request * request, struct _u_response * response, void * user_data) {
/*declarations*/
int r;
const char **keys=NULL;
const char *value=NULL;
char *line=NULL;
int len;
int i;
PGconn *conn=NULL;
char *prepStmEntities=NULL;
PGresult *pqRes=NULL;
printf("callback_create_entity() Started...\n");
if(request->map_post_body != NULL){
keys=u_map_enum_keys(request->map_post_body);
if(keys[0] == NULL){
//TODO error
printf("callback_create_entity() param NOT available\n");
//TODO Why this casting?
(void)(request);
(void)(user_data);
ulfius_set_string_body_response(response, 500, "This is the /entity/create route: HTTP POST data error!");
}else{
value = u_map_get(request->map_post_body, keys[0]);
if(value==NULL){
//TODO error
printf("callback_create_entity() key NOT available in request map\n");
//TODO Why this casting?
(void)(request);
(void)(user_data);
ulfius_set_string_body_response(response, 500, "This is the /entity/create route: HTTP POST key error!");
}else{
printf("callback_create_entity() key is %s, value is %s\n", keys[0], value);
conn = (PGconn *)user_data;
/*define prepared statement*/
len=snprintf(NULL,0,
"INSERT INTO entities (name) VALUES ('%s') RETURNING *;"
,value);
prepStmEntities=malloc((size_t)(len+1));
//TODO Release prepStmEntities!
snprintf(prepStmEntities,(size_t)(len+1),
"INSERT INTO entities (name) VALUES ('%s') RETURNING *;"
,value);
printf("callback_create_entity() prepStmEntities: %s\n",prepStmEntities);
/*create prepared statement*/
/*conn:connection*/
/*stm:statement*/
/*0:number of passed parameters*/
/*NULL: server figures out parameter type*/
/*paramValues:pointer of an array of strings containing parameters*/
/*NULL:relevant for binary parameters*/
/*NULL:relevant for binary parameters*/
/*0:obtain result in text format*/
//TODO How to pass params?
pqRes = PQexecParams(conn, prepStmEntities, 0, NULL, NULL, NULL, NULL, 0);
if(PQresultStatus(pqRes) != PGRES_TUPLES_OK) {
/*handle error*/
printf("callback_create_entity() No data retrieved\n");
ulfius_set_string_body_response(response, 500, "This is the /entity/create route: Dba error!");
/*clean up result*/
PQclear(pqRes);
//TODO Why this casting?
}else{
/*evaluate result*/
int nbRecords=PQntuples(pqRes);
printf("callback_get_entity() nbRecords: %d\n",nbRecords);
/*clean up result*/
PQclear(pqRes);
}
}
}
}else{
printf("callback_create_entity() HTTP POST request error!\n");
ulfius_set_string_body_response(response, 400, "This is the /entity/create route: HTTP POST request error!");
}
/*clean up remainings*/
printf("callback_create_entity() Done.\n");
//TODO Why this casting?
(void)(request);
(void)(user_data);
ulfius_set_string_body_response(response, 200, "Done.\n");
return U_CALLBACK_CONTINUE;
}
/**
* Callback function that put "Hello World!" and all the data sent by the client in the response as string (http method, url, params, cookies, headers, post, json, and user specific data in the response
*/
int callback_all_test_foo (const struct _u_request * request, struct _u_response * response, void * user_data) {
char * url_params = print_map(request->map_url), * headers = print_map(request->map_header), * cookies = print_map(request->map_cookie);
char * post_params = print_map(request->map_post_body);
char * response_body;
int r=asprintf(
&response_body,
"Hello World!\n\n method is %s\n url is %s\n\n parameters from the url are \n%s\n\n cookies are \n%s\n\n headers are \n%s\n\n post parameters are \n%s\n\n user data is %s\n\nclient address is %s\n\n",
request->http_verb, request->http_url, post_params, cookies, headers, post_params, (char *)user_data, inet_ntoa(((struct sockaddr_in *)request->client_address)->sin_addr));
ulfius_set_string_body_response(response, 200, response_body);
free(post_params);
free(headers);
free(cookies);
free(post_params);
free(response_body);
return U_CALLBACK_CONTINUE;
}

25
http-post-update/makefile Normal file
View File

@ -0,0 +1,25 @@
#target: dependency_1 dependency_2 dependency_3 ...
# command
#
RM = /bin/rm -f
OBJ = main.o pqconfo.o file2char.o
EXE = main
CC = /usr/bin/gcc
CFLAGS = -Wall
#
all: $(EXE)
#
$(EXE): $(OBJ)
$(CC) $(CFLAGS) $(OBJ) -L/usr/lib/x86_64-linux-gnu -lconfig -lulfius -lpq -ljansson -o $(EXE)
#
pqconfo.o: pqconfo.c pqconfo.h
$(CC) -c pqconfo.c -o pqconfo.o
#
file2char.o: file2char.c file2char.h
$(CC) -c file2char.c -o file2char.o
#
main.o: main.c
$(CC) -I/usr/include/postgresql -c main.c -o main.o
#
clean:
$(RM) $(OBJ) $(EXE) *~

View File

@ -0,0 +1,89 @@
/*to use malloc*/
#include <stdlib.h>
/*to use libconfig*/
#include <libconfig.h>
/*to use struct pq_confo*/
#include "pqconfo.h"
/*get Postgresql connection information*/
int get_pq_confo(const char * file,const struct pq_confo ** confo){
/*declaration*/
config_t cfg;
const char * db, * host, * secret, * user;
int port;
fprintf(stdout,"get_pq_confo() Started...\n");
/*initialise new and EMPTY config*/
config_init(&cfg);
/* Read the file. If there is an error, report it and exit. */
/*TODO Validate config file name!*/
if(! config_read_file(&cfg, file))
{
fprintf(stderr, "get_pq_confo() %s:%d - %s\n", config_error_file(&cfg),
config_error_line(&cfg), config_error_text(&cfg));
/*destroy config, BUT NOT the structure*/
config_destroy(&cfg);
return 2;
}
fprintf(stdout,"get_pq_confo() Parsing config file done\n");
/*lookup db string*/
if(config_lookup_string(&cfg, "pq.db", &db)){
printf("get_pq_confo() db: %s\n", db);
}else{
fprintf(stderr, "get_pq_confo() NO 'db' setting in config file found.\n");
return 3;
}
/*lookup host string*/
if(config_lookup_string(&cfg, "pq.host", &host)){
printf("get_pq_confo() host: %s\n", host);
}else{
fprintf(stderr, "get_pq_confo() NO 'host' setting in config file found.\n");
return 4;
}
/*lookup secret string*/
if(!config_lookup_string(&cfg, "pq.secret", &secret)){
fprintf(stderr, "get_pq_confo() NO 'secret' setting in config file found.\n");
return 5;
}
/*lookup user string*/
if(config_lookup_string(&cfg, "pq.user", &user)){
printf("get_pq_confo() user: %s\n", user);
}else{
fprintf(stderr, "get_pq_confo() NO 'user' setting in config file found.\n");
return 6;
}
/*lookup port int*/
if(config_lookup_int(&cfg, "pq.port", &port)){
printf("get_pq_confo() port: %d\n", port);
}else{
fprintf(stderr, "get_pq_confo() NO 'port' setting in config file found.\n");
return 7;
}
/*create struct*/
struct pq_confo * pqConfo = (struct pq_confo *)malloc( sizeof(struct pq_confo));
sprintf(pqConfo->db,"%s",db);
sprintf(pqConfo->host,"%s",host);
pqConfo->port=port;
sprintf(pqConfo->secret,"%s",secret);
sprintf(pqConfo->user,"%s",user);
*confo = pqConfo;
/*destroy config, BUT NOT the structure*/
config_destroy(&cfg);
/*return success*/
return 0;
}
/*free Postgresql connection information*/
int free_pq_confo(const struct pq_confo ** confo){
free((struct pq_confo *)*confo);
return 0;
}

View File

@ -0,0 +1,21 @@
/*We can use CPP tricks to avoid parsing the same header file more than once*/
#ifndef PQCONFO_H
# define PQCONFO_H
/*structure for Postgresql connection information*/
struct pq_confo
{
char db[23];
char host[23];
int port;
char secret[42];
char user[23];
};
/*get Postgresql connection information*/
int get_pq_confo(const char * file,const struct pq_confo ** confo);
/*free Postgresql connection information*/
int free_pq_confo(const struct pq_confo ** confo);
#endif /* PQCONFO_H */

View File

@ -0,0 +1,21 @@
# rgncycle-libulfius
libulfius API for rgncycle
* build
```
make
```
* run
```
./main
```
* run Valgrind tool `Memcheck`
```
valgrind --leak-check=yes -s ./main
```