/* -------------------------------------------------------------------------- * Copyright 2003-2011 (inclusive) Nathan Angelacos * (nangel@users.sourceforge.net) * * This file is part of haserl. * * Haserl is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, * as published by the Free Software Foundation. * * Haserl is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with haserl. If not, see . * * ------------------------------------------------------------------------ */ #if HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "common.h" #include "h_error.h" /* we define this here, but should use the header files instead. */ void *xrealloc (void *buf, size_t size); /* * split a string into an argv[] array, and return the number of elements. * Warning: Overwrites instr with nulls (to make ASCIIZ strings) and mallocs * space for the argv array. The argv array will point to the offsets in * instr where the elements occur. The calling function must free the argv * array, and should do so before freeing instr memory. * * If comment points to a non-null string, then any character in the string * will mark the beginning of a comment until the end-of-line: * * comment="#;" * foo bar # This is a comment * foo baz ; This is a comment as well * * Example of use: * * int argc, count; argv_t *argv; char string[2000]; * * strcpy (string, "This\\ string will be \"separated into\" '6' elements.", ""); * argc = argc_argv (string, &argv); * for (count = 0; count < argc; count++) { * printf ("%03d: %s\n", count, argv[count].string); * } * free (argv); * */ int argc_argv (char *instr, argv_t ** argv, char *commentstr) { char quote = '\0'; int arg_count = 0; enum state_t { WHITESPACE, WORDSPACE, TOKENSTART } state = WHITESPACE; argv_t *argv_array = NULL; int argc_slots = 0; size_t len, pos; len = strlen (instr); pos = 0; char quoted = 0; while (pos < len) { // printf ("%3d of %3d: %s\n", pos, len, instr); /* Comments are really, really special */ if ((state == WHITESPACE) && (strchr (commentstr, *instr))) { while ((*instr != '\n') && (*instr != '\0')) { instr++; pos++; } } switch (*instr) { /* quoting */ case '"': case '\'': /* Begin quoting */ if (state == WHITESPACE) { quote = *instr; state = TOKENSTART; quoted = -1; if (*(instr + 1) == quote) { /* special case for NULL quote */ *instr = '\0'; } else { instr++; pos++; } } else { /* WORDSPACE, so quotes end or quotes within quotes */ /* Is it the same kind of quote? */ if ( (*instr == quote) && quoted ) { quote = '\0'; *instr = '\0'; state = WHITESPACE; } } break; /* backslash - if escaping a quote within a quote */ case '\\': if ((quote) && (*(instr + 1) == quote)) { memmove (instr, instr + 1, strlen (instr)); len--; } /* otherwise, its just a normal character */ else { if (state == WHITESPACE) { state = TOKENSTART; } } break; /* whitepsace */ case ' ': case '\t': case '\r': case '\n': if ((state == WORDSPACE) && (quote == '\0')) { state = WHITESPACE; *instr = '\0'; } break; case '\0': break; default: if (state == WHITESPACE) { state = TOKENSTART; } } /* end switch */ if (state == TOKENSTART) { arg_count++; if (arg_count > argc_slots) { argc_slots += ALLOC_CHUNK; argv_array = (argv_t *) xrealloc (argv_array, sizeof (argv_t) * (argc_slots + ALLOC_CHUNK)); } if (argv_array == NULL) { return (-1); } argv_array[arg_count - 1].string = instr; argv_array[arg_count - 1].quoted = quoted; state = WORDSPACE; quoted = 0; } instr++; pos++; } if ( arg_count == 0 ) return (0); argv_array[arg_count].string = NULL; *argv = argv_array; return (arg_count); } /* Expandable Buffer is a reimplementation based on buffer.c in GCC originally by Per Bother */ void haserl_buffer_init (buffer_t * buf) { buf->data = NULL; buf->ptr = NULL; buf->limit = NULL; } void buffer_destroy (buffer_t * buf) { if (buf->data) { free (buf->data); } haserl_buffer_init (buf); } /* don't reallocate - just forget about the current contents */ void buffer_reset (buffer_t * buf) { if (buf->data) { buf->ptr = buf->data; } else { buf->ptr = NULL; } } void buffer_add (buffer_t * buf, const void *data, unsigned long size) { unsigned long newsize; unsigned long index; /* if we need to grow the buffer, do so now */ if ((buf->ptr + size) >= buf->limit) { index = (buf->limit - buf->data); newsize = index; while (newsize <= index + size) { newsize += 1024; } index = buf->ptr - buf->data; buf->data = realloc (buf->data, newsize); buf->limit = buf->data + newsize; buf->ptr = buf->data + index; } memcpy (buf->ptr, data, size); buf->ptr += size; } #ifndef JUST_LUACSHELL /* uppercase an entire string, using toupper */ void uppercase (char *instr) { while (*instr != '\0') { *instr = toupper (*instr); instr++; } } /* lowercase an entire string, using tolower */ void lowercase (char *instr) { while (*instr != '\0') { *instr = tolower (*instr); instr++; } } /* return ptr to first non-whitespace character */ char * skip_whitespace (char *instr) { while (isspace (*instr) && *instr) instr++; return instr; } /* return ptr to first whitespace character */ char * find_whitespace (char *instr) { while (!isspace (*instr) && *instr) instr++; return instr; } /* Counts the number of newlines in a buffer */ int count_lines (char *instr, size_t len, char *where) { size_t line = 1; while ((where > instr) && (len)) { if (*instr == '\n') line++; len--; instr++; } return line; } #endif #ifdef TEST_FRAMEWORK main () { int argc, count; argv_t *argv; char string[2000]; strcpy (string, "\\This\\ string will be '' \"separated into\" \"'\\\"'\" ' 16 ' elements.\n" "' including a multi-line\n" "element' with a comment. # This should not be parsed\n" ";Nor should this\n" "The End."); argc = argc_argv (string, &argv, "#;"); printf ("%s\n", string); for (count = 0; count < argc; count++) { printf ("%03d: [%s] ", count, argv[count].string, ""); if (argv[count].quoted) { printf ("(it was quoted)"); } printf ("\n"); } if (argc != 15) { puts ("Test FAILED"); } else { puts ("Test PASSED"); } free (argv); } #endif