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
This commit is contained in:
Eric Wong 2006-07-29 18:55:00 +00:00
parent f05166a6a0
commit f08342c11f
4 changed files with 59 additions and 117 deletions

View File

@ -21,99 +21,43 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.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 i = 0;
int count = 0; char *c = buffer;
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++) { while (*c != '\0' && i < max) {
if (!quotes && (buffer[curr] == ' ' || buffer[curr] == '\t')) { if (*c == '\"') {
markArray[curr] = '0'; int escape = 0;
} else if (buffer[curr] == '\"') { array[i++] = ++c;
if (curr > 0 && buffer[curr - 1] != '\\') { while (*c != '\0') {
quotes = quotes ? 0 : 1; if (*c == '\"') {
markArray[curr] = '0'; if (escape)
} else { memmove(c - 1, c,
markArray[curr] = '1'; strlen(c) + 1);
else {
*(c++) = '\0';
break;
}
}
escape = (*(c++) != '\\') ? 0 : !escape;
} }
} else { } else {
markArray[curr] = '1'; while (isspace(*c))
} ++c;
if (markArray[curr] == '1') { array[i++] = c++;
if (curr > 0) { if (*c == '\0')
if (markArray[curr - 1] == '0') { return i;
count++; while (!isspace(*c) && *c != '\0')
} ++c;
} else {
count++;
}
} }
if (*c == '\0')
return i;
*(c++) = '\0';
while (isspace(*c))
++c;
} }
markArray[bufferLength] = '\0'; return i;
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;
}
} else {
beginArray[count++] = curr;
}
} else {
buffer[curr] = '\0';
}
}
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);
} }

View File

@ -21,8 +21,12 @@
#include "../config.h" #include "../config.h"
int buffer2array(char *buffer, char ***array); /* 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
void freeArgArray(char **array, int argArrayLength); * 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 #endif

View File

@ -104,6 +104,11 @@
#define COMMAND_STATUS_AUDIO "audio" #define COMMAND_STATUS_AUDIO "audio"
#define COMMAND_STATUS_UPDATING_DB "updating_db" #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 struct _CommandEntry CommandEntry;
typedef int (*CommandHandlerFunction) (FILE *, int *, int, char **); typedef int (*CommandHandlerFunction) (FILE *, int *, int, char **);
@ -1138,16 +1143,14 @@ static CommandEntry *getCommandEntryAndCheckArgcAndPermission(FILE * fp,
static CommandEntry *getCommandEntryFromString(char *string, int *permission) static CommandEntry *getCommandEntryFromString(char *string, int *permission)
{ {
CommandEntry *cmd = NULL; CommandEntry *cmd = NULL;
char **argv; char *argv[COMMAND_ARGV_MAX] = { 0 };
int argc = buffer2array(string, &argv); int argc = cstrtok(string, argv, COMMAND_ARGV_MAX);
if (0 == argc) if (0 == argc)
return NULL; return NULL;
cmd = getCommandEntryAndCheckArgcAndPermission(NULL, permission, cmd = getCommandEntryAndCheckArgcAndPermission(NULL, permission,
argc, argc, argv);
argv);
freeArgArray(argv, argc);
return cmd; return cmd;
} }
@ -1156,29 +1159,25 @@ static int processCommandInternal(FILE * fp, int *permission,
char *commandString, ListNode * commandNode) char *commandString, ListNode * commandNode)
{ {
int argc; int argc;
char **argv; char *argv[COMMAND_ARGV_MAX] = { 0 };
CommandEntry *cmd; CommandEntry *cmd;
int ret = -1; int ret = -1;
argc = buffer2array(commandString, &argv); argc = cstrtok(commandString, argv, COMMAND_ARGV_MAX);
if (argc == 0) if (argc == 0)
return 0; return 0;
if ((cmd = getCommandEntryAndCheckArgcAndPermission(fp, permission, if ((cmd = getCommandEntryAndCheckArgcAndPermission(fp, permission,
argc, argc, argv))) {
argv))) {
if (NULL == commandNode || NULL == cmd->listHandler) { if (NULL == commandNode || NULL == cmd->listHandler) {
ret = cmd->handler(fp, permission, argc, ret = cmd->handler(fp, permission, argc, argv);
argv);
} else { } else {
ret = cmd->listHandler(fp, permission, argc, ret = cmd->listHandler(fp, permission, argc, argv,
argv, commandNode, cmd); commandNode, cmd);
} }
} }
freeArgArray(argv, argc);
current_command = NULL; current_command = NULL;
return ret; return ret;

View File

@ -41,6 +41,7 @@
#define CONF_REPEATABLE_MASK 0x01 #define CONF_REPEATABLE_MASK 0x01
#define CONF_BLOCK_MASK 0x02 #define CONF_BLOCK_MASK 0x02
#define CONF_LINE_TOKEN_MAX 3
typedef struct _configEntry { typedef struct _configEntry {
unsigned char mask; unsigned char mask;
@ -193,15 +194,16 @@ static ConfigParam *readConfigBlock(FILE * fp, int *count, char *string)
{ {
ConfigParam *ret = newConfigParam(NULL, *count); ConfigParam *ret = newConfigParam(NULL, *count);
char **array;
int i; int i;
int numberOfArgs; int numberOfArgs;
int argsMinusComment; int argsMinusComment;
while (myFgets(string, MAX_STRING_SIZE, fp)) { while (myFgets(string, MAX_STRING_SIZE, fp)) {
char *array[CONF_LINE_TOKEN_MAX] = { 0 };
(*count)++; (*count)++;
numberOfArgs = buffer2array(string, &array); numberOfArgs = cstrtok(string, array, CONF_LINE_TOKEN_MAX);
for (i = 0; i < numberOfArgs; i++) { for (i = 0; i < numberOfArgs; i++) {
if (array[i][0] == CONF_COMMENT) if (array[i][0] == CONF_COMMENT)
@ -211,13 +213,11 @@ static ConfigParam *readConfigBlock(FILE * fp, int *count, char *string)
argsMinusComment = i; argsMinusComment = i;
if (0 == argsMinusComment) { if (0 == argsMinusComment) {
freeArgArray(array, numberOfArgs);
continue; continue;
} }
if (1 == argsMinusComment && if (1 == argsMinusComment &&
0 == strcmp(array[0], CONF_BLOCK_END)) { 0 == strcmp(array[0], CONF_BLOCK_END)) {
freeArgArray(array, numberOfArgs);
break; break;
} }
@ -238,8 +238,6 @@ static ConfigParam *readConfigBlock(FILE * fp, int *count, char *string)
} }
addBlockParam(ret, array[0], array[1], *count); addBlockParam(ret, array[0], array[1], *count);
freeArgArray(array, numberOfArgs);
} }
return ret; return ret;
@ -249,7 +247,6 @@ void readConf(char *file)
{ {
FILE *fp; FILE *fp;
char string[MAX_STRING_SIZE + 1]; char string[MAX_STRING_SIZE + 1];
char **array;
int i; int i;
int numberOfArgs; int numberOfArgs;
int argsMinusComment; int argsMinusComment;
@ -265,9 +262,10 @@ void readConf(char *file)
} }
while (myFgets(string, MAX_STRING_SIZE, fp)) { while (myFgets(string, MAX_STRING_SIZE, fp)) {
char *array[CONF_LINE_TOKEN_MAX] = { 0 };
count++; count++;
numberOfArgs = buffer2array(string, &array); numberOfArgs = cstrtok(string, array, CONF_LINE_TOKEN_MAX);
for (i = 0; i < numberOfArgs; i++) { for (i = 0; i < numberOfArgs; i++) {
if (array[i][0] == CONF_COMMENT) if (array[i][0] == CONF_COMMENT)
@ -277,7 +275,6 @@ void readConf(char *file)
argsMinusComment = i; argsMinusComment = i;
if (0 == argsMinusComment) { if (0 == argsMinusComment) {
freeArgArray(array, numberOfArgs);
continue; continue;
} }
@ -316,8 +313,6 @@ void readConf(char *file)
param = newConfigParam(array[1], count); param = newConfigParam(array[1], count);
insertInListWithoutKey(entry->configParamList, param); insertInListWithoutKey(entry->configParamList, param);
freeArgArray(array, numberOfArgs);
} }
fclose(fp); fclose(fp);
} }