aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2006-07-29 18:55:00 +0000
committerEric Wong <normalperson@yhbt.net>2006-07-29 18:55:00 +0000
commitf08342c11fb7f31b168902b4d89d8e543e03125a (patch)
treee56ebfd5f0b4376d10e4f02dba17f3dfef82b999
parentf05166a6a0f39e6c6f8ce9675d7f6f6f58300577 (diff)
downloadmpd-f08342c11fb7f31b168902b4d89d8e543e03125a.tar.gz
mpd-f08342c11fb7f31b168902b4d89d8e543e03125a.tar.xz
mpd-f08342c11fb7f31b168902b4d89d8e543e03125a.zip
replace buffer2array() with cstrtok() from mpd-ke
This modifies the string in place, and does not allocate any memory from the heap. This is considerably smaller than the function it replaces, and will be instrumental in getting the commands/conf malloc reductions done. git-svn-id: https://svn.musicpd.org/mpd/trunk@4481 09075e82-0dd4-0310-85a5-a0d7c8717e4f
-rw-r--r--src/buffer2array.c120
-rw-r--r--src/buffer2array.h10
-rw-r--r--src/command.c29
-rw-r--r--src/conf.c17
4 files changed, 59 insertions, 117 deletions
diff --git a/src/buffer2array.c b/src/buffer2array.c
index 4a0751eae..322036df0 100644
--- a/src/buffer2array.c
+++ b/src/buffer2array.c
@@ -21,99 +21,43 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
-int buffer2array(char *origBuffer, char ***array)
+int cstrtok(char *buffer, char *array[], const int max)
{
- int quotes = 0;
- int count = 0;
- int i;
- int curr;
- int *beginArray;
- char *buffer = strdup(origBuffer);
- int bufferLength = strlen(buffer);
- char *markArray = malloc(sizeof(char) * (bufferLength + 1));
-
- for (curr = 0; curr < bufferLength; curr++) {
- if (!quotes && (buffer[curr] == ' ' || buffer[curr] == '\t')) {
- markArray[curr] = '0';
- } else if (buffer[curr] == '\"') {
- if (curr > 0 && buffer[curr - 1] != '\\') {
- quotes = quotes ? 0 : 1;
- markArray[curr] = '0';
- } else {
- markArray[curr] = '1';
- }
- } else {
- markArray[curr] = '1';
- }
- if (markArray[curr] == '1') {
- if (curr > 0) {
- if (markArray[curr - 1] == '0') {
- count++;
- }
- } else {
- count++;
- }
- }
- }
- markArray[bufferLength] = '\0';
-
- if (!count) {
- free(buffer);
- free(markArray);
- return count;
- }
-
- beginArray = malloc(sizeof(int) * count);
- (*array) = malloc(sizeof(char *) * count);
-
- count = 0;
-
- for (curr = 0; curr < bufferLength; curr++) {
- if (markArray[curr] == '1') {
- if (curr > 0) {
- if (markArray[curr - 1] == '0') {
- beginArray[count++] = curr;
+ int i = 0;
+ char *c = buffer;
+
+ while (*c != '\0' && i < max) {
+ if (*c == '\"') {
+ int escape = 0;
+ array[i++] = ++c;
+ while (*c != '\0') {
+ if (*c == '\"') {
+ if (escape)
+ memmove(c - 1, c,
+ strlen(c) + 1);
+ else {
+ *(c++) = '\0';
+ break;
+ }
}
- } else {
- beginArray[count++] = curr;
+ escape = (*(c++) != '\\') ? 0 : !escape;
}
} else {
- buffer[curr] = '\0';
+ while (isspace(*c))
+ ++c;
+ array[i++] = c++;
+ if (*c == '\0')
+ return i;
+ while (!isspace(*c) && *c != '\0')
+ ++c;
}
+ if (*c == '\0')
+ return i;
+ *(c++) = '\0';
+ while (isspace(*c))
+ ++c;
}
-
- for (i = 0; i < count; i++) {
- int len = strlen(buffer + beginArray[i]) + 1;
- int arrayCurr = 0;
- (*array)[i] = malloc(sizeof(char) * len);
- for (curr = beginArray[i]; buffer[curr] != '\0'; curr++) {
- if (buffer[curr] == '\\') {
- if (buffer[curr + 1] != '\0') {
- curr++;
- }
- }
- (*array)[i][arrayCurr++] = buffer[curr];
- }
- (*array)[i][arrayCurr] = '\0';
- }
-
- free(markArray);
- free(beginArray);
- free(buffer);
-
- return count;
-}
-
-void freeArgArray(char **array, int argArrayLength)
-{
- int i;
-
- if (argArrayLength == 0)
- return;
-
- for (i = 0; i < argArrayLength; i++) {
- free(array[i]);
- }
- free(array);
+ return i;
}
diff --git a/src/buffer2array.h b/src/buffer2array.h
index fa6882fd9..cecd3b6d3 100644
--- a/src/buffer2array.h
+++ b/src/buffer2array.h
@@ -21,8 +21,12 @@
#include "../config.h"
-int buffer2array(char *buffer, char ***array);
-
-void freeArgArray(char **array, int argArrayLength);
+/* tokenizes up to max elements in buffer (a null-terminated string) and
+ * stores the result in array (which must be capable of holding up to
+ * max elements). Tokenization is based on C string quoting rules.
+ * The arguments buffer and array are modified.
+ * Returns the number of elements tokenized.
+ */
+int cstrtok(char *buffer, char *array[], const int max);
#endif
diff --git a/src/command.c b/src/command.c
index 8158032a6..cf4a37ae7 100644
--- a/src/command.c
+++ b/src/command.c
@@ -104,6 +104,11 @@
#define COMMAND_STATUS_AUDIO "audio"
#define COMMAND_STATUS_UPDATING_DB "updating_db"
+/* the most we ever use is argv[2], so argv[] has (at most)
+ * 3 usable elements. This means we tokenize up to 4 elements to
+ * detect errors clients may send us */
+#define COMMAND_ARGV_MAX 4
+
typedef struct _CommandEntry CommandEntry;
typedef int (*CommandHandlerFunction) (FILE *, int *, int, char **);
@@ -1138,16 +1143,14 @@ static CommandEntry *getCommandEntryAndCheckArgcAndPermission(FILE * fp,
static CommandEntry *getCommandEntryFromString(char *string, int *permission)
{
CommandEntry *cmd = NULL;
- char **argv;
- int argc = buffer2array(string, &argv);
+ char *argv[COMMAND_ARGV_MAX] = { 0 };
+ int argc = cstrtok(string, argv, COMMAND_ARGV_MAX);
if (0 == argc)
return NULL;
cmd = getCommandEntryAndCheckArgcAndPermission(NULL, permission,
- argc,
- argv);
- freeArgArray(argv, argc);
+ argc, argv);
return cmd;
}
@@ -1156,29 +1159,25 @@ static int processCommandInternal(FILE * fp, int *permission,
char *commandString, ListNode * commandNode)
{
int argc;
- char **argv;
+ char *argv[COMMAND_ARGV_MAX] = { 0 };
CommandEntry *cmd;
int ret = -1;
- argc = buffer2array(commandString, &argv);
+ argc = cstrtok(commandString, argv, COMMAND_ARGV_MAX);
if (argc == 0)
return 0;
if ((cmd = getCommandEntryAndCheckArgcAndPermission(fp, permission,
- argc,
- argv))) {
+ argc, argv))) {
if (NULL == commandNode || NULL == cmd->listHandler) {
- ret = cmd->handler(fp, permission, argc,
- argv);
+ ret = cmd->handler(fp, permission, argc, argv);
} else {
- ret = cmd->listHandler(fp, permission, argc,
- argv, commandNode, cmd);
+ ret = cmd->listHandler(fp, permission, argc, argv,
+ commandNode, cmd);
}
}
- freeArgArray(argv, argc);
-
current_command = NULL;
return ret;
diff --git a/src/conf.c b/src/conf.c
index 5aefa016f..f130334ba 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -41,6 +41,7 @@
#define CONF_REPEATABLE_MASK 0x01
#define CONF_BLOCK_MASK 0x02
+#define CONF_LINE_TOKEN_MAX 3
typedef struct _configEntry {
unsigned char mask;
@@ -193,15 +194,16 @@ static ConfigParam *readConfigBlock(FILE * fp, int *count, char *string)
{
ConfigParam *ret = newConfigParam(NULL, *count);
- char **array;
int i;
int numberOfArgs;
int argsMinusComment;
while (myFgets(string, MAX_STRING_SIZE, fp)) {
+ char *array[CONF_LINE_TOKEN_MAX] = { 0 };
+
(*count)++;
- numberOfArgs = buffer2array(string, &array);
+ numberOfArgs = cstrtok(string, array, CONF_LINE_TOKEN_MAX);
for (i = 0; i < numberOfArgs; i++) {
if (array[i][0] == CONF_COMMENT)
@@ -211,13 +213,11 @@ static ConfigParam *readConfigBlock(FILE * fp, int *count, char *string)
argsMinusComment = i;
if (0 == argsMinusComment) {
- freeArgArray(array, numberOfArgs);
continue;
}
if (1 == argsMinusComment &&
0 == strcmp(array[0], CONF_BLOCK_END)) {
- freeArgArray(array, numberOfArgs);
break;
}
@@ -238,8 +238,6 @@ static ConfigParam *readConfigBlock(FILE * fp, int *count, char *string)
}
addBlockParam(ret, array[0], array[1], *count);
-
- freeArgArray(array, numberOfArgs);
}
return ret;
@@ -249,7 +247,6 @@ void readConf(char *file)
{
FILE *fp;
char string[MAX_STRING_SIZE + 1];
- char **array;
int i;
int numberOfArgs;
int argsMinusComment;
@@ -265,9 +262,10 @@ void readConf(char *file)
}
while (myFgets(string, MAX_STRING_SIZE, fp)) {
+ char *array[CONF_LINE_TOKEN_MAX] = { 0 };
count++;
- numberOfArgs = buffer2array(string, &array);
+ numberOfArgs = cstrtok(string, array, CONF_LINE_TOKEN_MAX);
for (i = 0; i < numberOfArgs; i++) {
if (array[i][0] == CONF_COMMENT)
@@ -277,7 +275,6 @@ void readConf(char *file)
argsMinusComment = i;
if (0 == argsMinusComment) {
- freeArgArray(array, numberOfArgs);
continue;
}
@@ -316,8 +313,6 @@ void readConf(char *file)
param = newConfigParam(array[1], count);
insertInListWithoutKey(entry->configParamList, param);
-
- freeArgArray(array, numberOfArgs);
}
fclose(fp);
}