first commit

This commit is contained in:
Jose Caban
2025-06-07 01:59:34 -04:00
commit 388ac241f0
3558 changed files with 9116289 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
/Makefile/1.2/Sat Feb 18 02:10:09 2006//
/debug.h/1.1/Tue Feb 21 00:58:27 2006//
/http.c/1.4/Mon Feb 20 23:05:47 2006//
/http.h/1.1/Thu Feb 16 01:12:25 2006//
/networking.c/1.6/Mon Feb 20 23:05:47 2006//
/networking.h/1.5/Sun Feb 19 08:35:24 2006//
/queue.c/1.5/Sun Feb 19 19:35:47 2006//
/queue.h/1.4/Sun Feb 19 19:35:47 2006//
/threading.h/1.1/Thu Feb 16 01:12:25 2006//
/timer.h/1.3/Sun Feb 19 07:27:08 2006//
/util.c/1.7/Mon Feb 20 16:00:58 2006//
/util.h/1.5/Sun Feb 19 01:42:40 2006//
D

View File

@@ -0,0 +1 @@
cs4210/proj1/src/common

View File

@@ -0,0 +1 @@
/usr/_CVS

View File

@@ -0,0 +1,103 @@
##############################################################################
#
# Generic Makefile. Only need to modify the variables for src, obj,
# and bin directories, and the name of the executable.
#
# $Author: vurazov $
# $Date: 2006/02/18 02:10:09 $
# $Revision: 1.2 $
#
##############################################################################
########################### Directories and Target ###########################
# Source directory:
SRC_DIR = .
# Object directory:
OBJ_DIR = ./obj
# Executable directory:
BIN_DIR = ../../bin
# Name of the executable:
BIN_NAME = common
######################## Compiler and Linker Options #########################
# Compiler:
CC = gcc
# Linker:
LD = ar
# Preprocessor flags:
DFLAGS =
# Compiler flags:
CFLAGS = -std=c99 -Wall -pedantic -O2
# Linker flags:
LDFLAGS = rcs
############################ Other Programs Used #############################
# Dependency generator:
MDEPEND = $(CC) -M
# Make Dir command:
MKDIR = /bin/mkdir -p
# Clean-up command:
RM = /bin/rm -f
######################### Automatic Object Variables #########################
# The list of source files:
SRCS = $(wildcard $(SRC_DIR)/*.c)
# Generated object files:
OBJS = $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR)/%.o,$(SRCS))
OBDS = $(patsubst $(SRC_DIR)/%.c,%.o,$(SRCS))
# Look for .o files in obj dir:
vpath %.o $(OBJ_DIR)
# Program file:
PROG = $(BIN_DIR)/lib$(BIN_NAME).a
################################### Rules ####################################
# Top-level rule: compile everything
all: $(PROG)
# The program link rule:
$(PROG): $(OBDS) $(BIN_DIR)
$(LD) $(LDFLAGS) $(PROG) $(OBJS)
# Meta rule for compiling ".c" files
%.o: $(SRC_DIR)/%.c $(OBJ_DIR)
$(CC) $(CFLAGS) $(DFLAGS) -c -o $(OBJ_DIR)/$@ $<
# Rules for obj and bin dirs:
$(OBJ_DIR):
$(MKDIR) $(OBJ_DIR)
$(BIN_DIR):
$(MKDIR) $(BIN_DIR)
# Rule for cleaning up before a recompile:
.PHONY: clean
clean:
$(RM) $(PROG) $(OBJS) .depend
# Rule for creating dependency lists and writing them into a dependency file:
.depend: $(SRCS)
$(MDEPEND) $(SRCS) > .depend
#Include dependency list:
include .depend

View File

@@ -0,0 +1,10 @@
#ifndef __DEBUG_H__
#define __DEBUG_H__
#ifdef DEBUG
#define DEBUG_PRINTF(x) printf x
#else
#define DEBUG_PRINTF(x)
#endif
#endif/*__DEBUG_H__*/

View File

@@ -0,0 +1,152 @@
#include <stdlib.h>
#include "debug.h"
#include "http.h"
#include "util.h"
/* The length of the buffer to read the stuff from the socket into. */
#define BUFFER_LENGTH 256
char* http_read_header(socket_t csocket)
{
char* result = NULL;
char buffer[BUFFER_LENGTH];
int bytes_received = 0;
DEBUG_PRINTF(("[HTTP] Reading header.\n"));
do
{
bytes_received = recv(csocket, buffer, BUFFER_LENGTH - 1, 0);
if (bytes_received > 0)
{
char* substr = NULL;
buffer[bytes_received] = '\0';
/* Append buffer to result: */
result = strcatd(result, buffer);
/* See if result now has two CRLFs in a row, to indicate the
end of the header: */
substr = strstr(result, "\r\n\r\n");
if (substr)
{
substr[4] = '\0';
break;
}
}
} while (bytes_received > 0);
DEBUG_PRINTF(("[HTTP] Got header:\n%s\n[HTTP] End header.\n", result));
return result;
}
char* http_get_requesturi(const char* header)
{
char* start = ((char*) strchr(header, ' ')) + 1;
if (start == NULL)
{
return NULL;
}
else
{
const char* stop = strchr(start, ' ');
if (stop == NULL)
{
return NULL;
}
else
{
/* Count the length of the request: */
char* ptr = NULL;
size_t count = 0;
for (ptr = start; ptr != stop; ptr++)
{
count ++;
}
return strncatd(NULL, start, count);
}
}
}
const char* http_get_method(const char* header)
{
/* If header starts with GET, then we have a GET request. */
if (strstr(header, HTTP_METHOD_GET) == header)
{
return HTTP_METHOD_GET;
}
else
{
return NULL;
}
}
void http_send_canned_response(socket_t socket, int status)
{
static const char* html1 = "<html>HTTP Status code ";
static const char* html2 = "</html>";
char buffer[8];
sprintf(buffer, "%d", status);
/* Send the appropriate header: */
http_send_header(socket, status);
/* Send some HTML: */
net_send_string(socket, html1, strlen(html1));
net_send_string(socket, buffer, strlen(buffer));
net_send_string(socket, html2, strlen(html2));
}
void http_send_header(socket_t socket, int status)
{
char buffer[32];
char* header = NULL;
/*
static struct utsname *our_name = NULL;
if (uname(our_name))
{
return NULL;
}
our_name->nodename
*/
/* Make status line: */
sprintf(buffer, "HTTP/1.1 %d %d\r\n", status, status);
header = strcatd(header, buffer);
/* Add various other headers: */
header = strcatd(header, "Content-Type: text/html\r\n");
header = strcatd(header, "Server: CS4210P1/vlad,omar\r\n");
header = strcatd(header, "Connection: Close\r\n");
header = strcatd(header, "\r\n");
net_send_string(socket, header, strlen(header));
free(header);
}
void http_send_text_file(socket_t socket, FILE* f)
{
char buffer[BUFFER_LENGTH];
size_t bytes_read = 0;
while (!feof(f))
{
bytes_read = fread(buffer, sizeof(char), BUFFER_LENGTH - 1, f);
buffer[bytes_read] = '\0';
if (bytes_read > 0)
{
net_send_string(socket, buffer, bytes_read);
}
else
{
break;
}
}
}

View File

@@ -0,0 +1,41 @@
#ifndef _HTTP_H_
#define _HTTP_H_
#include <stdio.h>
#include "networking.h"
/* Some useful request methods: */
#define HTTP_METHOD_GET "GET"
/* Some useful response codes: */
#define HTTP_STATUS_OK 200
#define HTTP_STATUS_BADREQUEST 400
#define HTTP_STATUS_FORBIDDEN 403
#define HTTP_STATUS_NOTFOUND 404
/*#define HTTP_STATUS_INTERNALERROR 500*/
#define HTTP_STATUS_NOTIMPLEMENTED 501
/* Returns a newly allocated string containing the HTTP header read
* from the socket. */
char* http_read_header(socket_t socket);
/* Returns a newly allocated string containing the requested URI from
* the header. */
char* http_get_requesturi(const char* header);
/* Given a request header, returns the type of request method that we
* have. If the method is unsupported, returns NULL. */
const char* http_get_method(const char* header);
/* Sends a hard-coded html response according to the status code passed in. */
void http_send_canned_response(socket_t socket, int status);
/* Sends a response header to the socket, according to the status code
* passed in. */
void http_send_header(socket_t socket, int status);
/* Sends the contents of the file as text through the socket. */
void http_send_text_file(socket_t socket, FILE* f);
#endif/*_HTTP_H_*/

View File

@@ -0,0 +1,164 @@
#include <ctype.h>
#include <stdio.h>
#include "networking.h"
int net_get_hostaddr(sockaddress_t* addr,
const char* hostname, const port_t port)
{
struct hostent* he = NULL;
if (isdigit(hostname[0]))
{
/* First character in host name is a digit... Could be an IP address */
unsigned long address = inet_addr(hostname);
if (address != INADDR_NONE)
{
he = gethostbyaddr((const char*) &address, 4, AF_INET);
}
}
if (he == NULL)
{
/* Well, the IP address bit didn't work. Try host name lookup: */
he = gethostbyname(hostname);
}
if (he == NULL)
{
fprintf(stderr, "[NET] Could not get host information as IP address, nor by name.\n");
net_report_error();
return 1;
}
addr->sin_family = AF_INET;
addr->sin_port = htons(port);
addr->sin_addr = *((struct in_addr*) (he->h_addr));
return 0;
}
socket_t net_open_data_socket(sockaddress_t* addr)
{
int err = 0;
socket_t result = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (IS_BAD_SOCKET(result))
{
fprintf(stderr, "[NET] Could not open client socket.\n");
net_report_error();
return 1;
}
err = connect(result, (struct sockaddr*) addr, sizeof(*addr));
if (err)
{
fprintf(stderr, "[NET] Could not connect on socket.\n");
net_report_error();
return -1;
}
return result;
}
/*
* Creates and initializes a new listening socket, ready to accept connections.
*/
socket_t net_listen_on_port(port_t port)
{
int reuse = 1;
int error_code = 0;
socket_t socket_id = -1;
sockaddress_t sockinfo;
/* Initialize socket using the TCP/IP protocol: */
socket_id = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (IS_BAD_SOCKET(socket_id))
{
fprintf(stderr, "[NET] Could not open listening socket.\n");
net_report_error();
return -1;
}
/* Set socket options to release unused socket numbers: */
error_code = setsockopt(socket_id, SOL_SOCKET, SO_REUSEADDR,
(sockoption_t) &reuse, sizeof(reuse));
if (error_code)
{
fprintf(stderr, "[NET] Could not set socket options.\n");
net_report_error();
return -1;
}
/* Bind the socket: */
sockinfo.sin_family = AF_INET;
sockinfo.sin_port = htons(port);
sockinfo.sin_addr.s_addr = htonl(INADDR_ANY); /* Bind to all interfaces */
error_code = bind(socket_id, (struct sockaddr*) &sockinfo, sizeof(sockinfo));
if (error_code)
{
fprintf(stderr, "[NET] Could not bind socket.\n");
net_report_error();
return -1;
}
/* Start Listening: */
error_code = listen(socket_id, 8);
if (error_code)
{
fprintf(stderr, "[NET] Could not listen on socket.\n");
net_report_error();
return -1;
}
return socket_id;
}
int net_send_string(socket_t socket, const char* data, size_t len)
{
if (send(socket, data, (int) len, 0) < (int) len)
{
fprintf(stderr, "[NET] Could not send data through socket.\n");
net_report_error();
return 1;
}
return 0;
}
int net_close_socket(socket_t socket)
{
int result = shutdown(socket, SHUT_RDWR);
if (result)
{
fprintf(stderr, "[NET] Could not shut down socket.\n");
net_report_error();
}
/* Curiously, the WinSock documentation says that shutdown does not
* actually close the socket, but tells the socket to stop accepting
* and sending data. Apparently, we also need to call this close
* socket deal. */
#ifdef WIN32
result = closesocket(socket);
#else
result = close(socket);
#endif
if (result)
{
fprintf(stderr, "[NET] Could not close socket.\n");
net_report_error();
}
return result;
}
void net_report_error()
{
#ifdef WIN32
int errcode = WSAGetLastError();
#else
int errcode = errno;
#endif
fprintf(stderr, "[NET] \tError #: %d.\n\n", errcode);
}

View File

@@ -0,0 +1,96 @@
#ifndef _NETWORKING_H_
#define _NETWORKING_H_
#ifdef WIN32
#include <winsock2.h>
#else
#include <sys/types.h> /* header containing all basic data types */
#include <sys/socket.h> /*header containing socket data types and functions*/
#include <netinet/in.h> /* IPv4 and IPv6 stuff */
#include <netdb.h> /* for DNS - gethostbyname() */
#include <unistd.h>
#include <arpa/inet.h> /* contains all inet_* functions */
#endif
#include <errno.h> /* contains the error functions */
#if 0 /* TODO: Remove this stuff? */
#include <fcntl.h> /* file control */
#endif
#ifdef WIN32
/* Apparently, this socklen_t business is not defined in Win. */
typedef int socklen_t;
#endif
/* The socket type. Typedef'ed to make the code more platform-independent. */
#ifdef WIN32
typedef SOCKET socket_t;
#else
typedef int socket_t;
#endif
/* The setsockopt function takes different parameter type for the
* value of the option in Berkeley sockets and WinSock. */
#ifdef WIN32
typedef const char* sockoption_t;
#else
typedef const void* sockoption_t;
#endif
/* The 'how' parameter to the shutdown function is different in
* Berkeley sockets and WinSock, too. */
#ifndef SHUT_RDWR
#define SHUT_RDWR SD_BOTH
#endif
/* The ways to check for illegal socket in windows and Linux are different: */
#ifdef WIN32
#define IS_BAD_SOCKET(socket) (socket == INVALID_SOCKET)
#else
#define IS_BAD_SOCKET(socket) (socket < 0)
#endif
/* The port type. Typedef'ed in case we want to make this code
* platform-independent at some point and the ports on another
* platform are something other than this. */
typedef unsigned short port_t;
/* This is the struct we will be using for socket addresses. */
typedef struct sockaddr_in sockaddress_t;
/* Given a host name and a port number, fills in the sockaddress struct with the
appropriate information for the host. This function will automagically work both if the host is a host name, or if it's an IP address in dotted notation. **WARNING** This function IS NOT mt-safe! */
int net_get_hostaddr(sockaddress_t* addr,
const char* hostname, const port_t port);
/* Opens a client socket on the specified address. */
socket_t net_open_data_socket(sockaddress_t* addr);
/*
* Creates a new listening socket on the specified port, sets up the
* correct options, binds and starts listening. Returns the id of the
* socket if all these operations were successful, and -1 if there was
* an error at any point. If there is an error, then also this
* function will print out to stderr what the error was. If a valid
* socket id is returned, then accept can be called on the socket to
* accept connections.
*/
socket_t net_listen_on_port(port_t port);
/* Sends the string through the socket. Returns 0 on success, and an
* error code on failure. */
int net_send_string(socket_t socket, const char* data, size_t len);
/*
* Shuts down the socket. Returns zero on success, and error code on
* failure. Also, on failure will print out the error to stderr.
*/
int net_close_socket(socket_t socket);
/*
* Reports the last error to stderr.
*/
void net_report_error();
#endif/*_NETWORKING_H_*/

View File

@@ -0,0 +1,162 @@
#include <stdio.h>
#include <stdlib.h>
#include "queue.h"
void queue_initialize(queue_t* q)
{
q->head = NULL;
q->tail = NULL;
pthread_mutex_init(&(q->mutex), NULL);
pthread_cond_init(&(q->has_stuff), NULL);
}
void queue_free(queue_t* q)
{
sllnode_t* cur = NULL;
pthread_mutex_lock(&(q->mutex));
cur = q->head;
q->head = NULL;
q->tail = NULL;
while (cur)
{
sllnode_t* next = cur->next;
cur->data = NULL;
cur->next = NULL;
free(cur);
cur = next;
}
pthread_mutex_unlock(&(q->mutex));
}
int queue_enqueue(queue_t* q, void* data)
{
/* Make a linked list node */
sllnode_t* node = (sllnode_t*) calloc(1, sizeof(sllnode_t));
if (!node)
{
fprintf(stderr,
"[QUE] Could not allocate memory for linked list node.\n");
return 1;
}
node->next = NULL;
node->data = data;
/* Add node to the end of the queue: */
pthread_mutex_lock(&q->mutex);
if (q->tail != NULL)
{
q->tail->next = node;
}
q->tail = node;
if (q->head == NULL)
{
q->head = node;
}
pthread_mutex_unlock(&(q->mutex));
pthread_cond_signal(&(q->has_stuff));
return 0;
}
void* queue_dequeue(queue_t* q)
{
sllnode_t* node;
void* result;
pthread_mutex_lock(&q->mutex);
while (q->head == NULL)
{
pthread_cond_wait(&(q->has_stuff), &(q->mutex));
}
node = q->head;
q->head = q->head->next;
if (q->head == NULL)
{
q->tail = NULL;
}
pthread_mutex_unlock(&(q->mutex));
node->next = NULL;
result = node->data;
free(node);
return result;
}
void* queue_dequeue_nb(queue_t* q)
{
sllnode_t* node = NULL;
void* result = NULL;
pthread_mutex_lock(&q->mutex);
if (q->head != NULL)
{
node = q->head;
q->head = q->head->next;
if (q->head == NULL)
{
q->tail = NULL;
}
}
pthread_mutex_unlock(&(q->mutex));
if (node != NULL)
{
node->next = NULL;
result = node->data;
free(node);
}
return result;
}
int queue_has_data(queue_t* q)
{
int result = 0;
pthread_mutex_lock(&q->mutex);
result = (q->head != NULL);
pthread_mutex_unlock(&(q->mutex));
return result;
}
void iterator_initialize(queue_iterator_t* iter, queue_t* q, int wrap)
{
iter->q = q;
iter->cur = q->head;
iter->wrap = wrap;
}
void* iterator_next(queue_iterator_t* iter)
{
void* result = NULL;
if (!iter->cur) return NULL;
pthread_mutex_lock(&(iter->q->mutex));
result = iter->cur->data;
iter->cur = iter->cur->next;
if (!iter->cur && iter->wrap) iter->cur = iter->q->head;
pthread_mutex_unlock(&(iter->q->mutex));
return result;
}

View File

@@ -0,0 +1,69 @@
/* queue.h
*
* Here we define a generic MT-safe queue data structure.
*/
#ifndef _QUEUE_H_
#define _QUEUE_H_
#include "threading.h"
typedef struct tagSinglyLinkedList
{
struct tagSinglyLinkedList* next;
void* data;
} sllnode_t;
typedef struct
{
sllnode_t* head;
sllnode_t* tail;
pthread_mutex_t mutex;
pthread_cond_t has_stuff;
} queue_t;
typedef struct
{
queue_t* q;
sllnode_t* cur;
int wrap;
} queue_iterator_t;
/* Initializes the queue q. */
void queue_initialize(queue_t* q);
/* Frees the queue, and its associated structures, but not the data if
there is any in it. */
void queue_free(queue_t* q);
/* Adds a new thing to the end of the queue q. */
int queue_enqueue(queue_t* q, void* data);
/* Removes an item from the queue q, and returns a pointer to it. If the queue
does not contain any items, will wait till data is inserted. */
void* queue_dequeue(queue_t* q);
/* Removes an item from the queue q, and returns a pointer to it. If the queue
does not contain any items, returns null. */
void* queue_dequeue_nb(queue_t* q);
/* Returns true if queue has data, and false if it is empty. */
int queue_has_data(queue_t* q);
/* Initializes the iterator iter over the queue q. If next function is
called on the iterator after this, the head data will be
returned. The wrap parameter will determine whether the iterator will wrap
around to the bedinning of the queue when the end is reached. */
void iterator_initialize(queue_iterator_t* iter, queue_t* q, int wrap);
/* Returns whatever the iterator points to currently (would be the
head of the queue right after the initialize call), and moves the
iterator to the next position. Note that if the end of the queue is
reached, this function will whip around and start from the
beginning again. Note also that bad things may happen if the queue
is modified between calls to this function. */
void* iterator_next(queue_iterator_t* iter);
#endif/*_QUEUE_H_*/

View File

@@ -0,0 +1,8 @@
#ifndef _THREADING_H_
#define _THREADING_H_
#include <pthread.h>
#include <signal.h>
#endif/*_THREADING_H_*/

View File

@@ -0,0 +1,85 @@
#ifndef _TIMER_H_
#define _TIMER_H_
/* In windows, we'll use QueryPerformanceCounter, and in everything
else, we will use gettimeofday (windows does not seem to support
that function. */
#ifdef WIN32
#define _WINSOCKAPI_ /* Have to do this, else windows.h and winsock2.h */
#include <windows.h> /* (from the networking module) start fighting,
as windows.h will include the old
winsock.h. */
#else
#include <sys/time.h>
#endif
/* The units of time we will be storing in our time span for the
beginning and end of the measurement period. */
#ifdef WIN32
typedef LARGE_INTEGER timestamp_t;
#else
typedef struct timeval timestamp_t;
#endif
/* The timespan structure, holding the beginning and ending times for
our measurements. */
typedef struct
{
timestamp_t start;
timestamp_t stop;
} time_span_t;
/* The function to start the timer. It is inlined for better performance. */
#ifdef WIN32
static inline void timer_start(time_span_t* s)
{
QueryPerformanceCounter(&(s->start));
}
#else
static inline void timer_start(time_span_t* s)
{
gettimeofday(&(s->start), NULL);
}
#endif
/* The function to stop the timer. */
#ifdef WIN32
static inline void timer_stop(time_span_t* s)
{
QueryPerformanceCounter(&(s->stop));
}
#else
static inline void timer_stop(time_span_t* s)
{
gettimeofday(&(s->stop), NULL);
}
#endif
/* The function to convert the time stamp to milliseconds. */
#ifdef WIN32
static inline double timer_millis(timestamp_t* value)
{
timestamp_t frequency;
double v, f;
QueryPerformanceFrequency(&frequency);
v = (double) (*value).LowPart;
f = (double) frequency.LowPart;
return 1000 * v / f;
}
#else
static inline double timer_millis(timestamp_t* v)
{
return (v->tv_sec * 1000.0) + (v->tv_usec / 1000.0);
}
#endif
/* The function to calculate the time span in milliseconds. */
static inline double timer_span(time_span_t* s)
{
return timer_millis(&(s->stop)) - timer_millis(&(s->start));
}
#endif/*_TIMER_H_*/

View File

@@ -0,0 +1,203 @@
#include <stdlib.h>
#include "util.h"
#define BUFFER_SIZE 256
char* strcatd(char* dest, const char* src)
{
return strncatd(dest, src, strlen(src));
}
char* strncatd(char* dest, const char* src, size_t len)
{
size_t dest_length = 0;
size_t total_length = 0;
char* result = NULL;
if (dest) { dest_length = strlen(dest); }
total_length = dest_length + len;
result = (char*) realloc(dest, (total_length + 1) * sizeof(char));
if (!result)
{
fprintf(stderr, "[UTIL] Could not allocate memory "
"for dynamic string concatenation.\n");
}
result[dest_length] = '\0';
strncat(result, src, len);
return result;
}
/* TODO: Refactor with the HTTP Header Reading Code */
char* read_line(FILE* stream)
{
char* result = NULL;
char buffer[BUFFER_SIZE];
buffer[0] = '\0';
while (!feof(stream))
{
fgets(buffer, BUFFER_SIZE, stream);
result = strcatd(result, buffer);
if (buffer[strlen(buffer) - 1] == '\n')
{
break;
}
}
return result;
}
int parse_url(const char* url, char** host, port_t* port, char** path)
{
char* durl = strdup(url);
if (strstr(durl, "http://") != durl)
{
/* The URL does not start with http, it is malformed. */
*host = NULL;
*path = NULL;
free(durl);
return 1;
}
else
{
/* Separate the protocol from the rest: */
char* url_start = durl + strlen("http://");
/* Separate the port from the rest: */
char* port_start = strchr(url_start, ':');
/* Separate the host from the path: */
char* path_start = strchr(url_start, '/');
if (port_start)
{
port_start[0] = '\0';
port_start ++;
}
else
{
port_start = "0";
}
if (path_start)
{
path_start[0] = '\0';
path_start ++;
}
else
{
path_start = "";
}
*host = strdup(url_start);
*port = (port_t) atoi(port_start);
*path = strcatd(NULL, "/");
*path = strcatd(*path, path_start);
return 0;
}
}
/* Tries to parse the parameter param. If succeeded, returns zero and
* puts the name of the parameter into opname, and the value of the
* parameter into opvalue. Note that the strings put into output
* parameters are dynamically allocated and need to be freed. */
int m_parse_parameter(const char* param, char** opname, char** opvalue)
{
char* parameter = strdup(param);
if (strstr(parameter, "help") || strstr(parameter, "?"))
{
*opname = strdup("help");
*opvalue = strdup(" ");
free(parameter);
return 0;
}
*opname = strtok(parameter, "=");
*opvalue = strtok(NULL, "=");
if (!*opname || !*opvalue)
{
*opname = NULL;
*opvalue = NULL;
}
else
{
*opname = strdup(*opname);
*opvalue = strdup(*opvalue);
}
free(parameter);
return (*opname == NULL);
}
int parse_command_parameters(int argc, const char** argv,
register_parameter_func f)
{
int i;
for (i = 0; i < argc; i++)
{
char* pname = NULL;
char* pvalue = NULL;
int result = 0;
/* Parse the curren parameter: */
if(m_parse_parameter(argv[i], &pname, &pvalue)) continue;
/* Record the parameter value: */
result = f(pname, pvalue);
free(pname);
free(pvalue);
if (result) return result;
}
return 0;
}
int parse_file_parameters(FILE* stream, register_parameter_func f)
{
char* current_line = NULL;
for (current_line = read_line(stream); current_line;
free(current_line), current_line = read_line(stream))
{
if (current_line[0] != '#')
{
char* pname = NULL;
char* pvalue = NULL;
int result = 0;
/* Parse the curren parameter: */
if(m_parse_parameter(current_line, &pname, &pvalue)) continue;
/* Record the parameter value: */
result = f(pname, pvalue);
free(pname);
free(pvalue);
if (result) break;
}
}
if (current_line)
{
free(current_line);
return 1;
}
else
{
return 0;
}
}

View File

@@ -0,0 +1,57 @@
#ifndef _UTIL_H_
#define _UTIL_H_
#include <stdio.h>
#include <string.h>
#include "networking.h"
/* Windows and Linux have their own wierdness related to strdup. */
#ifdef WIN32
#define strdup _strdup
#else
char* strdup(const char* src);
#endif
/* A function with this signature can be used to register a
* parameter-name/value pair. It should return 0 if the parameter is
* valid and an error code if the parameter is invalid. */
typedef int (*register_parameter_func)(const char* pname, const char* pvalue);
/* Dynamic strcat. Given a dynamically allocated string dest, and a
* string src, will append src to the end of dest, while reallocating
* the string as necessary. If dest is NULL, will allocate a new
* string. If src is NULL, will crash. */
char* strcatd(char* dest, const char* src);
/* Dynamic strncat. Basically, the same as strcatd, but copies only
* len characters from src. */
char* strncatd(char* dest, const char* src, size_t len);
/* Reads until a newline or EOF is encountered in the stream and returns the
result in a newly allocated string. */
char* read_line(FILE* stream);
/* Given a url, parses it into the host name, the port, and the path. If the url
* does not have a host name and a path, or does not begin with "http://"
* protocol, then the url is malformed, host and path are set to NULL, and an
* error code is returned. Otherwise, the host and path are filled with newly
* allocated strings which will need to be freed, and zero is returned. Also, if
* the port is not present in the url, it will be filled in with 0. */
int parse_url(const char* url, char** host, port_t* port, char** path);
/* Parses the command-line parameters and registers them with function
* f. If an illegal parameter is encountered (according to the
* function f), then immediately stops parsing parameters and returns
* and error code. Otherwise, keeps parsing until runs out of the
* parameters, and then returns 0. */
int parse_command_parameters(int argc, const char** argv,
register_parameter_func f);
/* Parses the parameters from the file. If an illegal parameter is
* encountered (according to the function f), then immediately stops
* parsing parameters and returns an error code. Otherwise, keeps
* parsing until runs out of the parameters, and then returns 0. */
int parse_file_parameters(FILE* stream, register_parameter_func f);
#endif/*_UTIL_H_*/