-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathjsh-common.c
231 lines (207 loc) · 7.03 KB
/
jsh-common.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
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
231
/* This file is part of jsh.
*
* jsh: A basic UNIX shell implementation in C
* Copyright (C) 2014 Jo Van Bulck <jo.vanbulck@student.kuleuven.be>
*
* jsh is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* jsh is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with jsh. If not, see <http://www.gnu.org/licenses/>.
*/
#include "jsh-common.h"
#define SET_ERR_COLOR \
if (IS_INTERACTIVE && COLOR) \
textcolor(stderr, BRIGHT, RED);
void printerr(const char *format, ...) {
SET_ERR_COLOR;
va_list args;
fprintf(stderr, "jsh: ");
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
RESTORE_COLOR(stderr);
}
void printerrno(const char *format, ...) {
SET_ERR_COLOR;
va_list args;
fprintf(stderr, "jsh: ");
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args );
fprintf(stderr, ": %s", strerror(errno));
RESTORE_COLOR(stderr);
}
// TODO mss int debuglevel / priority
void printdebug(const char *format, ...) {
if (DEBUG) {
if (IS_INTERACTIVE && COLOR)
textcolor(stdout, RESET, YELLOW);
va_list args;
fprintf(stdout, "[DEBUG: ");
va_start(args, format);
vfprintf(stdout, format, args);
va_end(args);
fprintf(stdout, "]");
RESTORE_COLOR(stdout);
fflush(stdout); // force the debug info to be instantly written
}
}
void printinfo(const char *format, ...) {
va_list args;
fprintf(stdout, "jsh: ");
va_start(args, format);
vfprintf(stdout, format, args);
va_end(args );
fprintf(stdout, "\n");
}
/*
* only set the style and fg (to prevent problems with translucency...)
* use RESTORE_COLOR macro to reset the color afterwards
*/
void textcolor(FILE *stream, int style, int fg) {
char colorcode[13];
sprintf(colorcode, "%c[%d;%dm", 0x1B, style, fg + 30);
fprintf(stream, "%s", colorcode);
}
/*
* returns getenv("HOME") if not null; else "."
*/
char *gethome() {
char *curdir = ".";
char *rv = getenv("HOME");
return (rv != NULL)? rv: curdir;
}
/*
* @note: inline function implementation should be in header. Moreover one extern
* declaration should be used, to tell the compiler where to put the non-inlined function,
* if needed. See (http://stackoverflow.com/questions/26503235/c-inline-funtion-and-gcc).
*/
extern inline int puts_verbatim(const char *s);
/*
* parsefile: wrapper for parsestream(), opening and closing the file at the provided path.
* @arg errmsg: true = print an error message if opening the file failed
* false = exit silently if opening the file failed
* @NOTE: if you pass a pointer to 'printf()' here, this may introduce format-string-
* vulnerabilities as the lines are passed verbatim to the function. If you want to use
* this function to print the content of a file line per line, pass a pointer to
* 'puts_verbatim()' (defined in jsh-common.h) instead.
*/
void parsefile(char *path, void (*fct)(char*), bool errmsg) {
FILE *file = fopen(path, "r");
if (file == NULL) {
if (errmsg) printerrno("opening of file '%s' failed", path);
return;
}
parsestream(file, path, fct);
fclose(file);
}
/*
* parsestream: reads the provided stream strm line per line, passing each line,
* including '\n' to the provided function fct.
* @NOTE: if you pass a pointer to 'printf()' here, this may introduce format-string-
* vulnerabilities as the lines are passed verbatim to the function. If you want to use
* this function to print the content of a file line per line, pass a pointer to
* 'puts_verbatim()' (defined in jsh-common.h) instead.
*/
void parsestream(FILE *strm, char* name, void (*fct)(char*)) {
printdebug("-------- now parsing stream '%s' --------", name);
char line[MAX_FILE_LINE_LENGTH+1];
int c, i = 0, j = 1; // i = index in line; j = line nb
while ((c = fgetc(strm)) != EOF)
if (c == '\n') {
line[i] = '\0';
printdebug("%s: now parsing line %d: '%s'", name, j, line);
fct(line);
fct("\n");
i = 0;
j++;
}
else if (i < MAX_FILE_LINE_LENGTH)
line[i++] = c;
else {
printerr("%s: ignoring line %d exeeding the max line length: %d", name, j, MAX_FILE_LINE_LENGTH);
while ((c=fgetc(strm)) != '\n');
i = 0;
j++;
}
printdebug("-------- end of stream '%s' --------", name);
}
/*
* string_cmp: wrapper function for strcmp(); to be passed to bsearch() or qsort() in order to compare
* two pointers to a string (char**)
*/
int string_cmp(const void *a, const void *b) {
const char **ia = (const char **) a;
const char **ib = (const char **) b;
return strcmp(*ia, *ib);
}
/*
* is_sorted: returns false iff the provided array a isn't sorted according to the provided comparison function,
* else returns true; time complexity O(n)
*/
bool is_sorted(void *a, size_t n, size_t el_size, int (*compar)(const void *, const void *)) {
int i;
for (i = 0; i < (n - 1)*el_size; i += el_size) {
int rv = compar((a + i), (a + i + el_size));
if (rv >= 0)
return false;
}
return true;
}
/*
* strclone: returns a pointer to a malloc block with a copy of the provided string.
*/
char *strclone(const char* str) {
char *ret = malloc(strlen(str)+1);
strcpy(ret, str);
return ret;
}
/*
* concat: concatenates count nb of strings and returns a pointer to the malloc()ed result.
* the caller should free() the result afterwards
* credits: http://stackoverflow.com/a/11394336
*/
char* concat(int count, ...) {
va_list ap;
int i;
// Find required length to store merged string
int len = 1; // room for NULL
va_start(ap, count);
for(i=0 ; i<count ; i++)
len += strlen(va_arg(ap, char*));
va_end(ap);
// Allocate memory to concat strings TODO chkerr
char *merged = calloc(sizeof(char),len);
int null_pos = 0;
// Actually concatenate strings
va_start(ap, count);
for(i=0 ; i<count ; i++)
{
char *s = va_arg(ap, char*);
strcpy(merged+null_pos, s);
null_pos += strlen(s);
}
va_end(ap);
return merged;
}
/*
* remove_char: helper function: deletes all occurences of a specified char in a given '\0' terminated string.
* returns the resuling '\0' terminated string
* credits: http://stackoverflow.com/a/8733511
*/
void remove_char(char *str, char garbage) {
char *src, *dst;
for (src = dst = str; *src != '\0'; src++) {
*dst = *src;
if (*dst != garbage) dst++;
}
*dst = '\0';
}