-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathenv-value.zig
More file actions
230 lines (217 loc) · 7.93 KB
/
env-value.zig
File metadata and controls
230 lines (217 loc) · 7.93 KB
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
const std = @import("std");
pub const MAX_ENV_VALUE_LENGTH = 32768;
const EnvPair = @import("env-pair.zig").EnvPair;
const VariablePosition = @import("variable-position.zig").VariablePosition;
const InterpolationHelper = @import("interpolation-helper.zig");
const quoteHelper = @import("quote-helper.zig");
const processValueInsideQuoted = @import("quote-helper.zig").processValueInsideQuoted;
const incrementInterpolDepth = InterpolationHelper.incrementInterpolDepth;
const decrementInterpolDepth = InterpolationHelper.decrementInterpolDepth;
const walkBackSlashes = quoteHelper.walkBackSlashes;
const walkDoubleQuotes = quoteHelper.walkDoubleQuotes;
const walkSingleQuotes = quoteHelper.walkSingleQuotes;
pub const EnvValue = struct {
const Self = @This();
value: []u8 = undefined, //reuse stack buffer for speed
isParsingVariable: bool = false,
interpolations: []VariablePosition = undefined,
interpolationIndex: u32 = 0,
quoted: bool = false,
tripleQuoted: bool = false,
doubleQuoted: bool = false,
tripleDoubleQuoted: bool = false,
valueIndex: u32 = 0,
allocator: *std.mem.Allocator = undefined,
isAlreadyInterpolated: bool = false,
isBeingInterpolated: bool = false,
didOverFlow: bool = false,
backSlashStreak: u32 = 0,
singleQuoteStreak: u32 = 0,
doubleQuoteStreak: u32 = 0,
pub fn free_value(self: *EnvValue) void {
self.allocator.free(self.value);
}
pub fn init(self: *Self, allocator: *std.mem.Allocator, tmp_buffer: []u8) !void {
std.debug.print("creating intOp array \n", .{});
self.valueIndex = 0;
self.interpolationIndex = 0;
var tmp = try allocator.alloc(VariablePosition, 8);
self.interpolations = tmp;
self.value = tmp_buffer;
self.allocator = allocator;
self.isAlreadyInterpolated = false;
self.tripleQuoted = false;
self.didOverFlow = false;
self.doubleQuoted = false;
self.quoted = false;
self.isBeingInterpolated = false;
self.backSlashStreak = 0;
self.singleQuoteStreak = 0;
self.doubleQuoteStreak = 0;
}
pub fn hadInterpolation(self: *Self) bool {
return self.interpolationIndex > 0;
}
pub fn finalize_value(self: *Self) !void {
if (self.valueIndex <= 0) {
return error.ValueWouldBeEmpty;
}
std.debug.print("Finalizing Value of length {} \n", .{self.valueIndex});
var tmp = try self.allocator.alloc(u8, self.valueIndex);
const bufferSlice = self.value[0..self.valueIndex];
std.mem.copy(u8, tmp, bufferSlice);
self.value = tmp;
}
pub fn placeValueCharacter(self: *Self, value: u8) !void {
if (self.valueIndex >= MAX_ENV_VALUE_LENGTH) {
//emit warning we are over allowed buffer length
std.debug.print("Value {c} can not be stored. ENV has a max size. \n", .{value});
self.didOverFlow = true;
return;
//todo: handle overflow -- probably will just ignore. ENV can't hold more than 32k on linux.
//return;
}
std.debug.print("Adding character {c} \n", .{value});
self.value[self.valueIndex] = value;
self.valueIndex = self.valueIndex + 1;
std.debug.print(" {s} \n", .{self.value[0..20]});
}
pub fn processValueNextValue(self: *Self, value: u8) !bool {
if (self.didOverFlow) {
//we've told the user they overflowed. Just return; Nothing else can be processed.
return true;
}
std.debug.print("Looking for quotes or braces... \n", .{});
switch (value) {
'"' => {
self.doubleQuoteStreak = self.doubleQuoteStreak + 1;
std.debug.print("Found a double quote {} \n", .{self.doubleQuoteStreak});
return false;
},
'\'' => {
self.singleQuoteStreak = self.singleQuoteStreak + 1;
std.debug.print("Found a single quote {} \n", .{self.singleQuoteStreak});
return false;
},
'\\' => {
self.backSlashStreak = self.backSlashStreak + 1;
std.debug.print("Found a backslash quote {} \n", .{self.backSlashStreak});
return false;
},
'{' => {
std.debug.print("Found a Open Brace \n", .{});
if (!self.isParsingVariable) {
const optional_count = self.previousIsDollarSign();
if(optional_count) |count| {
try incrementInterpolDepth(self, count);
}
}
},
'}' => {
std.debug.print("Found a close Brace \n", .{});
if (self.isParsingVariable) {
decrementInterpolDepth(self);
}
},
'\r' => {
return false;
},
else =>{
}
}
std.debug.print("Looking for newlines and if quoted \n", .{});
if (!self.quoted) {
//quick note, we know that it's not any of the following characters because of the switch.
//you check for when it's no longer a \\ streak or "" streak to determine the length of it.
//We read one char at a time so there is no forward only backwards.
if (self.backSlashStreak > 0) {
if (walkBackSlashes(self, value)) {
return true;
}
}
if (self.doubleQuoteStreak > 0) {
if (walkDoubleQuotes(self)) {
return true;
}
}
}
if (self.singleQuoteStreak > 0) {
if (walkSingleQuotes(self)) {
return true;
}
}
if (value == '\n') {
std.debug.print("Found a new line \n", .{});
if (!self.isHereDoc()) {
std.debug.print("Newline hit on double/no quote\n", .{});
return true;
}
}
try self.placeValueCharacter(value);
return false;
}
pub fn isHereDoc(self: *Self) bool {
return self.tripleQuoted or self.tripleDoubleQuoted;
}
pub fn fourCharactersAgoNewline(self: *Self) bool {
if (self.valueIndex < 4) {
return false;
}
return self.value[self.valueIndex - 4] == '\n';
}
pub fn previousSingleQuoteCount(self: *Self) u32 {
var tmp = self.valueIndex;
var count: u32 = 0;
while (tmp > 0) {
if (self.value[tmp - 1] == '\'') {
count = count + 1;
}
if (count >= 3) {
//avoid """"""""""""""""""""""""
break;
}
tmp = tmp - 1;
}
return count;
}
pub fn previousDoubleQuoteCount(self: *Self) u32 {
var tmp = self.valueIndex;
var count: u32 = 0;
while (tmp > 0) {
if (self.value[tmp - 1] == '"') {
count = count + 1;
}
if (count >= 3) {
//avoid """"""""""""""""""""""""
break;
}
tmp = tmp - 1;
}
return count;
}
pub fn isAtStart(self: *Self) bool {
return self.valueIndex == 0;
}
pub fn fourCharactersAgoStart(self: *Self) bool {
return self.valueIndex == 3;
}
// checks for $ being behind the { and ignoring whitespace
pub fn previousIsDollarSign(self: *Self) ?u32 {
if (self.valueIndex == 0) {
return null;
}
var tmp = self.valueIndex - 1;
var count: u32 = 0;
while (tmp >= 0) : (tmp = tmp - 1) {
count = count + 1;
if (self.value[tmp] == '$') {
return count;
}
if (self.value[tmp] == ' ') {
continue;
}
return null;
}
return count;
}
};