-
Notifications
You must be signed in to change notification settings - Fork 92
/
Copy pathstring_to_vector.c
142 lines (119 loc) · 3.83 KB
/
string_to_vector.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include "common.h"
// Vector in this context means a null terminated array. Think of argv. It is a null terminated array of pointers to
// null terminated arrays of chars. The v in argv stands for vector. Using vectors makes bounds checking much easier.
// The other advantage to this approach is not using strtok() which is destructive. The below function malloc()s new
// space for a non-destructive tokenization. free_vector() below is then provide to simplify cleanup.
// To-Do: I've got this same routine in several of my projects. I really need to start a libmonkey project with all
// my common function / code idioms in one place.
/**********************************************************************************************************************
*
* string_to_vector()
*
* Input: A string of tokens, whitespace delimited, null terminated.
* Output: An array of strings containing the tokens. The array itself is also null terminated. NULL will be returned
* on error.
*
* Purpose: Tokenize a string for later consumption.
*
**********************************************************************************************************************/
char **string_to_vector(char *command_string){
int was_space = 1;
int count = 0;
int i, len;
char *index;
char *token_start = NULL;
char **argv;
index = command_string;
while(*index){
/* Lets step through the string and look for tokens. We aren't grabbing them yet, just counting them. */
/* Note, we are looking at the transition boundaries from space->!space and !space->space to define the */
/* token. "count" will denote these transitions. An odd count implies that we are in a token. An even */
/* count implies we are between tokens. */
if(isspace(*index)){
if(!was_space){
/* end of a token. */
count++;
}
was_space = 1;
}else{
if(was_space){
/* start of a token. */
count++;
}
was_space = 0;
}
index++;
}
/* Don't forget to account for the case where the last token is up against the '\0' terminator with no space */
/* between. */
if(count % 2){
count++;
}
/* Now, (count / 2) will be the number of tokens. Since we know the number of tokens, lets setup argv. */
if((argv = (char **) malloc((sizeof(char *) * ((count / 2) + 1)))) == NULL){
report_error("string_to_vector(): malloc(%d): %s", (int) ((sizeof(char *) * ((count / 2) + 1))), strerror(errno));
return(NULL);
}
memset(argv, 0, (sizeof(char *) * ((count / 2) + 1)));
/* Now, let's do that loop again, this time saving the tokens. */
i = 0;
len = 0;
count = 0;
was_space = 1;
index = command_string;
while(*index){
if(isspace(*index)){
if(!was_space){
/* end of a token. */
if((argv[i] = (char *) malloc(sizeof(char) * (len + 1))) == NULL){
report_error("string_to_vector(): malloc(%d): %s", (int) (sizeof(char) * (len + 1)), strerror(errno));
goto CLEAN_UP;
}
memset(argv[i], 0, sizeof(char) * (len + 1));
memcpy(argv[i], token_start, sizeof(char) * len);
i++;
len = 0;
count++;
}
was_space = 1;
}else{
if(was_space){
/* start of a token. */
count++;
token_start = index;
}
len++;
was_space = 0;
}
index++;
}
/* Same final token termination case. */
if(count % 2){
if((argv[i] = malloc(sizeof(char) * (len + 1))) == NULL){
report_error("string_to_vector(): malloc(%d): %s", (int) (sizeof(char) * (len + 1)), strerror(errno));
goto CLEAN_UP;
}
memset(argv[i], 0, sizeof(char) * (len + 1));
memcpy(argv[i], token_start, sizeof(char) * len);
}
return(argv);
CLEAN_UP:
i = 0;
while(argv[i]){
free(argv[i]);
i++;
}
free(argv);
return(NULL);
}
void free_vector(char **vector){
char **tmp_vector;
char *tmp_string;
tmp_vector = vector;
tmp_string = *(tmp_vector++);
while(tmp_string){
free(tmp_string);
tmp_string = *(tmp_vector++);
}
free(vector);
}