blob: f25182b2f2f8cc975df224964a4697dbdd67d3a4 [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2005 The Regents of the University of California.
* This material was produced under U.S. Government contract W-7405-ENG-36
* for Los Alamos National Laboratory, which is operated by the University
* of California for the U.S. Department of Energy. The U.S. Government has
* rights to use, reproduce, and distribute this software. NEITHER THE
* GOVERNMENT NOR THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR
* ASSUMES ANY LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified
* to produce derivative works, such modified software should be clearly
* marked, so as not to confuse it with the version available from LANL.
*
* Additionally, this program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* LA-CC 04-115
******************************************************************************/
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "args.h"
#define CHUNK_SIZE 8
#define LENGTH_TO_CHUNKS(len) (len / CHUNK_SIZE + 1)
#define FREE_SPACE(len) (CHUNK_SIZE - (len - 1) % CHUNK_SIZE - 1)
/*
* Convert a string to an arg array
*/
char **
StrToArgs(char *s)
{
int squote = 0;
int dquote = 0;
int bsquote = 0;
int argc = 0;
int maxargc = 0;
char * arg;
char * copybuf;
char ** argv = NULL;
char ** nargv;
if ( s == NULL )
return argv;
copybuf = (char *)malloc(strlen(s) + 1);
do
{
while (isspace ((int)*s))
s++;
if ( (maxargc == 0) || (argc >= (maxargc - 1)) )
{
if ( argv == NULL )
{
maxargc = CHUNK_SIZE;
nargv = (char **)malloc(maxargc * sizeof (char *));
}
else
{
maxargc += CHUNK_SIZE;
nargv = (char **)realloc(argv, maxargc * sizeof (char *));
}
argv = nargv;
argv[argc] = NULL;
}
arg = copybuf;
while ( *s != '\0' )
{
if ( isspace((int)*s) && !squote && !dquote && !bsquote )
break;
switch (*s) {
case '\\':
if (bsquote) {
*arg++ = *s;
bsquote = 0;
} else
bsquote = 1;
break;
case '\'':
if (squote)
squote = 0;
else
squote = 1;
break;
case '"':
if (dquote)
dquote = 0;
else
dquote = 1;
break;
default:
if (bsquote)
{
bsquote = 0;
switch (*s) {
case 'n':
*arg++ = '\n';
break;
case 't':
*arg++ = '\t';
break;
default:
*arg++ = *s;
break;
}
break;
}
*arg++ = *s;
break;
}
s++;
}
*arg = '\0';
if ( (argv[argc] = strdup(copybuf)) == NULL )
{
free(copybuf);
FreeArgs(argv);
argv = NULL;
return argv;
}
argc++;
argv[argc] = NULL;
while ( isspace ((int)*s) )
s++;
}
while ( *s != '\0' );
free(copybuf);
return argv;
}
/*
* Free an arg array
*/
void
FreeArgs(char **args)
{
char ** ap;
if ( args == (char **)NULL )
return;
for ( ap = args ; *ap != NULL ; ap++ )
free(*ap);
free(args);
}
/*
* Create a new arg array. If a0 is NULL, create an empty array.
*/
char **
NewArgs(char *a0, ...)
{
int n = 1;
char ** ap;
char ** app;
va_list args;
if ( a0 == NULL )
{
ap = (char **)malloc(CHUNK_SIZE * sizeof(char *));
*ap = NULL;
return ap;
}
/*
* Calclulate number of arguments (n starts at 1 to allow for a0)
*/
va_start(args, a0);
while ( va_arg(args, char *) != NULL )
n++;
va_end(args);
/*
* Round up to multiple of CHUNK_SIZE. This takes into account the
* NULL entry also.
*/
app = ap = (char **)malloc(LENGTH_TO_CHUNKS(n + 2) * CHUNK_SIZE * sizeof(char *));
*app++ = strdup(a0);
va_start(args, a0);
while ( --n > 0 )
*app++ = strdup(va_arg(args, char *));
va_end(args);
*app = NULL;
return ap;
}
/*
* Append arg array ep to arg array ap. Returns a newly allocated array.
*/
char **
AppendArgv(char **ap, char **ep)
{
int na = 0;
int ne = 0;
char ** app;
char ** npp;
for ( app = ap ; *app != NULL ; app++ )
na++;
for ( app = ep ; *app != NULL ; app++ )
ne++;
npp = (char **)malloc(LENGTH_TO_CHUNKS(na + ne + 1) * CHUNK_SIZE * sizeof(char *));
for ( app = npp ; *ap != NULL ; ap++ )
*app++ = strdup(*ap);
for ( app = npp + na ; *ep != NULL ; ep++ )
*app++ = strdup(*ep);
*app = NULL;
return npp;
}
/*
* Append arguments to an arg array. Returns a newly allocted array.
*/
char **
AppendArgs(char **ap, ...)
{
int na = 0;
int ne = 0;
char * a;
char ** app;
char ** npp;
va_list args;
for ( app = ap ; *app != NULL ; app++ )
na++;
va_start(args, ap);
while ( va_arg(args, char *) != NULL )
ne++;
va_end(args);
npp = (char **)malloc(LENGTH_TO_CHUNKS(na + ne + 1) * CHUNK_SIZE * sizeof(char *));
for ( app = npp ; *ap != NULL ; ap++ )
*app++ = strdup(*ap);
va_start(args, ap);
for ( app = npp + na; (a = va_arg(args, char *)) != NULL ; )
*app++ = strdup(a);
va_end(args);
*app = NULL;
return npp;
}
/*
* Append a string to the array. Will expand the size of
* the array if necessary. Returns the array with the string
* appended.
*/
char **
AppendStr(char **ap, char *str)
{
int n;
int na = 0;
char ** app;
for ( app = ap ; *app != NULL ; app++ )
na++;
n = FREE_SPACE(na);
if (n < 2) {
ap = (char **)realloc(ap, LENGTH_TO_CHUNKS(na + 2) * CHUNK_SIZE * sizeof(char *));
}
*(ap + na) = strdup(str);
*(ap + na + 1) = NULL;
return ap;
}
/*
** Copy arguments into a string buffer.
*/
void
ArgsToBuf(char *argv[], int argc, char *buf, int len)
{
int i;
int l;
*buf = '\0';
for ( i = 0 ; i < argc ; i++ )
{
l = strlen(argv[i]);
if ( l > len - 1 )
return;
strcpy(buf, argv[i]);
buf += l;
len -= l;
if ( i < argc - 1 )
{
if ( len < 2 )
return;
strcpy(buf, " ");
buf++;
len--;
}
}
}
/*
* Convert arguments to a string
*/
char *
ArgsToStr(char **ap)
{
int n = 0;
char ** app;
char * res;
char * rp;
for ( app = ap ; *app != NULL ; app++ ) {
n += strlen(*app) + 1;
}
rp = res = (char *)malloc(sizeof(char *) * n + 1);
for ( app = ap ; *app != NULL ; app++ ) {
if (app != ap) {
*rp++ = ' ';
}
n = strlen(*app);
memcpy(rp, *app, n);
rp += n;
}
*rp = '\0';
return res;
}