tiny-shell 0.2
A mini shell project aiming to gain knowledge about Win32 and Linux API
Loading...
Searching...
No Matches
args.c
Go to the documentation of this file.
1#include "args.h"
2#include "../core/io_wrap.h"
3#include "config.h"
4
5#include <assert.h>
6#include <stdlib.h>
7#include <string.h>
8
9enum {
12};
13#define QUOTATION_MARK_STR "\""
14
16os_char *transform_quotes(const os_char *str) {
17 unsigned int length = 0;
18 os_char *res = malloc(strlen(str) + 1);
19 bool quote_opened = false;
20 for(int i = 0; str[i] != '\0'; ++i) {
21 if(str[i] == QUOTATION_MARK) {
22 quote_opened = !quote_opened;
23 } else if(quote_opened) {
24 if(is_whitespace(str[i]))
25 res[length] = MAGIC_TOKEN;
26 else
27 res[length] = str[i];
28 length++;
29 } else {
30 res[length] = str[i];
31 length++;
32 }
33 }
34
35 if(quote_opened) {
36 format_error("Number of " QUOTATION_MARK_STR " character is odd\n");
37 free(res);
38 return NULL;
39 }
40
41 res[length] = '\0';
42 os_char *tmp = realloc(res, length + 1);
43 if(!tmp) {
44 format_error("Cannot allocate memory for input args\n");
45 free(res);
46 return NULL;
47 } else {
48 return tmp;
49 }
50}
51
52void split_by_whitespaces(const os_char *str, struct args *buffer) {
53 os_char **argv = (os_char **)malloc(MAX_ARGC * sizeof(os_char *));
54 unsigned int argc = 0;
55
56 bool is_space = true;
57 bool was_space = true;
58 int start = 0;
59
60 for(int i = 0; true; ++i) {
61 is_space = is_whitespace(str[i]) || str[i] == '\0';
62 if(is_space && !was_space) {
63 if(argc >= MAX_ARGC) {
64 format_error("Too many arguments, max number is %u\n", MAX_ARGC);
65 break;
66 }
67 const unsigned int len = (i - 1) - start + 1;
68 argv[argc] = malloc(len + 1);
69 memcpy(argv[argc], str + start, len);
70 argv[argc][len] = '\0';
71 argc++;
72 }
73 if(!is_space && was_space) {
74 start = i;
75 }
76 was_space = is_space;
77 if(str[i] == '\0') {
78 break;
79 }
80 }
81
82 argv[argc] = NULL;
83 buffer->argc = argc;
84 buffer->argv = argv;
85}
86
88 int first_oc = -1;
89 for(int i = 0; i < args->argc; ++i) {
90 if(strcmp(args->argv[i], "&") == 0) {
91 first_oc = i;
92 break;
93 }
94 }
95 if(first_oc < 0) {
96 args->background = false;
97 return;
98 }
99 free(args->argv[first_oc]);
100 for(int i = first_oc + 1; i < args->argc; ++i) {
101 args->argv[i - 1] = args->argv[i];
102 }
103 args->argc--;
104 args->background = true;
105}
106
108void re_transform_arg(os_char *arg) {
109 const unsigned int len = strlen(arg);
110 for(int i = 0; i < len; ++i) {
111 if(arg[i] == MAGIC_TOKEN) {
112 arg[i] = ' ';
113 }
114 }
115}
116
117bool args_init_from_str(struct args *obj, const os_char *input) {
118 assert(obj && "NULL input");
119 obj->argc = 0;
120 obj->argv = NULL;
121 obj->background = false;
122 os_char *quote_transformed = transform_quotes(input);
123 if(!quote_transformed) {
124 return false;
125 }
126 split_by_whitespaces(quote_transformed, obj);
127 free(quote_transformed);
128 for(int i = 0; i < obj->argc; ++i) {
129 re_transform_arg(obj->argv[i]);
130 }
132 return true;
133}
134
135void args_destroy(struct args *obj) {
136 if(!obj) {
137 return;
138 }
139 for(int i = 0; i < obj->argc; ++i) {
140 free(obj->argv[i]);
141 }
142 free((void *)obj->argv);
143}
144
145struct args *args_deep_copy(const struct args *obj) {
146 if(!obj) {
147 return NULL;
148 }
149 struct args *res = malloc(sizeof(struct args));
150 res->argc = obj->argc;
151 res->background = obj->background;
152 res->argv = (os_char **)malloc((obj->argc + 1) * sizeof(os_char *));
153 for(int i = 0; i < obj->argc; ++i) {
154 const unsigned int len = strlen(obj->argv[i]);
155 res->argv[i] = malloc((len + 1) * sizeof(os_char));
156 memcpy(res->argv[i], obj->argv[i], len * sizeof(os_char));
157 res->argv[i][len] = '\0';
158 }
159 res->argv[obj->argc] = NULL;
160 return res;
161}
162
163void args_deep_copy_init(struct args *obj, const struct args *source) {
164 assert(source != NULL && "Cannot deep copy null");
165 obj->argc = source->argc;
166 obj->background = source->background;
167 obj->argv = (os_char **)malloc((source->argc + 1) * sizeof(os_char *));
168 for(int i = 0; i < source->argc; ++i) {
169 const unsigned int len = strlen(source->argv[i]);
170 obj->argv[i] = malloc((len + 1) * sizeof(os_char));
171 memcpy(obj->argv[i], source->argv[i], len * sizeof(os_char));
172 obj->argv[i][len] = '\0';
173 }
174 obj->argv[obj->argc] = NULL;
175}
176
177bool is_whitespace(os_char c) {
178 return c == ' ' || c == '\t' || c == '\n';
179}
void verify_background(struct args *args)
Definition args.c:87
void args_deep_copy_init(struct args *obj, const struct args *source)
Initialize the object by deep copying source
Definition args.c:163
@ MAGIC_TOKEN
Definition args.c:10
@ QUOTATION_MARK
Definition args.c:11
void split_by_whitespaces(const os_char *str, struct args *buffer)
Definition args.c:52
bool is_whitespace(os_char c)
!
Definition args.c:177
struct args * args_deep_copy(const struct args *obj)
Deep copy the object, including arguments string.
Definition args.c:145
void args_destroy(struct args *obj)
Definition args.c:135
bool args_init_from_str(struct args *obj, const os_char *input)
Build args from an input string.
Definition args.c:117
os_char * transform_quotes(const os_char *str)
Transform whitespaces inside quotes into MAGIC_TOKEN
Definition args.c:16
void re_transform_arg(os_char *arg)
Transform MAGIC_TOKEN inside arg into space.
Definition args.c:108
#define QUOTATION_MARK_STR
Definition args.c:13
#define MAX_ARGC
Definition config.h:9
void format_error(char *fmt,...)
Used format_xxx instead of printf and such for uniform output.
Definition io_wrap.c:89
Result after parsing an arbitrary string.
Definition args.h:10
os_char ** argv
Definition args.h:11
unsigned int argc
Definition args.h:12
bool background
Definition args.h:13