refactored optionsfrom as in an object-oriented way using the options_t class. Eliminated all memory leaks

This commit is contained in:
Andreas Steffen
2008-02-04 14:44:14 +00:00
parent 3b1692c058
commit 0730fec464
2 changed files with 151 additions and 42 deletions
+109 -32
View File
@@ -6,7 +6,9 @@
*/ */
/* /*
* Copyright (C) 1998, 1999 Henry Spencer. * Copyright (C) 2007-2008 Andreas Steffen
*
* Hochschule fuer Technik Rapperswil
* *
* This library is free software; you can redistribute it and/or modify it * This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Library General Public License as published by * under the terms of the GNU Library General Public License as published by
@@ -18,6 +20,7 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
* License for more details. * License for more details.
* *
* RCSID $Id$
*/ */
#include <stdio.h> #include <stdio.h>
@@ -30,29 +33,64 @@
#include "optionsfrom.h" #include "optionsfrom.h"
#define MAX_USES 20 /* loop-detection limit */ #define MAX_USES 20 /* loop-detection limit */
#define SOME_ARGS 10 /* first guess at how many arguments we'll need */ #define MORE_ARGS 10 /* first guess at how many arguments we'll need */
/* /*
* Defined in header. * Defined in header.
*/ */
bool optionsfrom(const char *filename, int *argcp, char **argvp[], int optind)
{ typedef struct private_options_t private_options_t;
static int nuses = 0;
/**
* Private data of a options_t object.
*/
struct private_options_t {
/**
* Public interface
*/
options_t public;
/**
* reallocated argv array
*/
char **newargv; char **newargv;
/**
* number of free arguments in newargv
*/
int room;
/**
* number of included option files
*/
int nuses;
/**
* allocated space for option files
*/
char *buffers[MAX_USES];
};
/**
* Defined in header
*/
bool from(private_options_t *this, char *filename, int *argcp, char **argvp[],
int optind)
{
int newargc; int newargc;
int next; /* place for next argument */ int next; /* place for next argument */
int room; /* how many more new arguments we can hold */ char **newargv;
size_t bytes; size_t bytes;
chunk_t chunk, src, line, token; chunk_t src, line, token;
bool good = TRUE; bool good = TRUE;
int linepos = 0; int linepos = 0;
FILE *fd; FILE *fd;
/* avoid endless loops with recursive --optionsfrom arguments */ /* avoid endless loops with recursive --optionsfrom arguments */
nuses++; this->nuses++;
if (nuses >= MAX_USES) if (this->nuses >= MAX_USES)
{ {
DBG1("optionsfrom called %d times - looping?", (*argvp)[0], nuses); DBG1("optionsfrom called %d times by \"%s\" - looping?", this->nuses + 1, (*argvp)[0]);
return FALSE; return FALSE;
} }
@@ -66,26 +104,31 @@ bool optionsfrom(const char *filename, int *argcp, char **argvp[], int optind)
/* determine the file size */ /* determine the file size */
fseek(fd, 0, SEEK_END); fseek(fd, 0, SEEK_END);
chunk.len = ftell(fd); src.len = ftell(fd);
rewind(fd); rewind(fd);
/* allocate one byte more just in case of a missing final newline */ /* allocate one byte more just in case of a missing final newline */
chunk.ptr = malloc(chunk.len + 1); src.ptr = this->buffers[this->nuses] = malloc(src.len + 1);
/* read the whole file into a chunk */ /* read the whole file into a chunk */
bytes = fread(chunk.ptr, 1, chunk.len, fd); bytes = fread(src.ptr, 1, src.len, fd);
fclose(fd); fclose(fd);
newargc = *argcp + SOME_ARGS; if (this->room)
newargv = malloc((newargc + 1) * sizeof(char *)); {
newargc = *argcp;
newargv = malloc((newargc + 1 + this->room) * sizeof(char *));
}
else
{
newargc = *argcp + MORE_ARGS;
this->room = MORE_ARGS;
newargv = malloc((newargc + 1) * sizeof(char *));
}
memcpy(newargv, *argvp, optind * sizeof(char *)); memcpy(newargv, *argvp, optind * sizeof(char *));
room = SOME_ARGS;
next = optind; next = optind;
newargv[next] = NULL; newargv[next] = NULL;
/* we keep the chunk pointer so that we can still free it */
src = chunk;
while (fetchline(&src, &line) && good) while (fetchline(&src, &line) && good)
{ {
linepos++; linepos++;
@@ -116,11 +159,11 @@ bool optionsfrom(const char *filename, int *argcp, char **argvp[], int optind)
} }
/* do we have to allocate more memory for additional arguments? */ /* do we have to allocate more memory for additional arguments? */
if (room == 0) if (this->room == 0)
{ {
newargc += SOME_ARGS; newargc += MORE_ARGS;
newargv = realloc(newargv, (newargc+1) * sizeof(char *)); newargv = realloc(newargv, (newargc + 1) * sizeof(char *));
room = SOME_ARGS; this->room = MORE_ARGS;
} }
/* terminate the token by replacing the delimiter with a null character */ /* terminate the token by replacing the delimiter with a null character */
@@ -129,20 +172,54 @@ bool optionsfrom(const char *filename, int *argcp, char **argvp[], int optind)
/* assign the token to the next argument */ /* assign the token to the next argument */
newargv[next] = token.ptr; newargv[next] = token.ptr;
next++; next++;
room--; this->room--;
} }
} }
if (!good) /* error of some kind */ /* assign newargv to argv */
if (good)
{ {
free(chunk.ptr); memcpy(newargv + next, *argvp + optind, (*argcp + 1 - optind) * sizeof(char *));
free(newargv); *argcp += next - optind;
return FALSE; *argvp = newargv;
} }
memcpy(newargv + next, *argvp + optind, (*argcp + 1 - optind) * sizeof(char *)); /* keep a pointer to the latest newargv and free any earlier version */
*argcp += next - optind; free(this->newargv);
*argvp = newargv; this->newargv = newargv;
return TRUE;
return good;
} }
/**
* Defined in header
*/
void destroy(private_options_t *this)
{
while (this->nuses >= 0)
{
free(this->buffers[this->nuses--]);
}
free(this->newargv);
free(this);
}
/*
* Defined in header
*/
options_t *options_create(void)
{
private_options_t *this = malloc_thing(private_options_t);
/* initialize */
this->newargv = NULL;
this->room = 0;
this->nuses = -1;
memset(this->buffers, '\0', MAX_USES);
/* public functions */
this->public.from = (bool (*) (options_t*,char*,int*,char***,int))from;
this->public.destroy = (void (*) (options_t*))destroy;
return &this->public;
}
+41 -9
View File
@@ -6,8 +6,9 @@
*/ */
/* /*
* Copyright (C) 1998, 1999 Henry Spencer. * Copyright (C) 2007-2008 Andreas Steffen
* Copyright (C) 2007 Andreas Steffen, Hochschule fuer Technik Rapperswil *
* Hochschule fuer Technik Rapperswil
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the * under the terms of the GNU General Public License as published by the
@@ -18,20 +19,51 @@
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details. * for more details.
*
* RCSID $Id$
*/ */
#ifndef OPTIONSFROM_H_ #ifndef OPTIONSFROM_H_
#define OPTIONSFROM_H_ #define OPTIONSFROM_H_
typedef struct options_t options_t;
/** /**
* @brief Pick up more options from a file, in the middle of an option scan * @brief options object.
* *
* @param filename file containing the options * @b Constructors:
* @param argcp pointer to argc * - options_create()
* @param argvp pointer to argv[] *
* @param optind current optind, number of next argument * @ingroup utils
* @return TRUE if optionsfrom parsing successful
*/ */
bool optionsfrom(const char *filename, int *argcp, char **argvp[], int optind); struct options_t {
/**
* @brief Check if the PKCS#7 contentType is data
*
* @param this calling object
* @param filename file containing the options
* @param argcp pointer to argc
* @param argvp pointer to argv[]
* @param optind current optind, number of next argument
* @return TRUE if optionsfrom parsing successful
*/
bool (*from) (options_t * this, char *filename, int *argcp, char **argvp[], int optind);
/**
* @brief Destroys the options_t object.
*
* @param this options_t object to destroy
*/
void (*destroy) (options_t *this);
};
/**
* @brief Create an options object.
*
* @return created options_t object
*
* @ingroup utils
*/
options_t *options_create(void);
#endif /*OPTIONSFROM_H_*/ #endif /*OPTIONSFROM_H_*/