/nobber/trunk

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/nobber/trunk
4 by Stream
* Moved functions to utils.h
1
#pragma once
2
3
/*******
4
 * utils.h
5
 * These utility functions and macros can requiers nob.h
6
 *
7
 * You may use them as you see fit.
8
 *
9
 * This header file uses the standard STB-style inclue stuff:
10
 * define NOBBER_UTILS_IMPREMENTATION 
11
 * to in one file, so they get built.
12
 ******/
13
14
#include <stdlib.h>
15
#include <stdio.h>
16
17
#include <alloca.h>
18
#include <errno.h>
19
#include <linux/limits.h>
20
#include <stdlib.h>
21
#include <stddef.h>
22
#include <stdio.h>
23
#include <stdlib.h>
24
#include <string.h>
25
#include <stdbool.h>
26
#include <stdint.h>
27
#include <inttypes.h>
28
#include <unistd.h>
29
#include <assert.h>
30
#if defined(__unix__) || defined(__linux__)
31
    #include <unistd.h>
32
#endif
33
#ifdef __darwin__
34
    #include <mach-o/dyld.h>
35
#endif
36
37
#include "nob.h"
38
39
#define IN /*Does nothing, just a mark.*/
40
#define OUT /*Does nothing, just a mark.*/
41
#define INOUT /*Does nothing, just a mark.*/
42
43
typedef struct da_strings_t DaStrings;
44
45
typedef enum NobberError {
46
    NOBBER_RETURN_NORMAL,
47
    NOBBER_RETURN_UNUSED0,
48
    NOBBER_RETURN_UNUSED1,
49
    NOBBER_RETURN_UNUSED2,
50
    NOBBER_RETURN_UNUSED3,
51
    NOBBER_RETURN_UNKNOWN_COMMAND,
52
    NOBBER_RETURN_EXEC,
53
    NOBBER_RETURN_COUNT
54
} NobberError;
55
56
void * malloc0 (size_t size);
57
char * strip_extention (IN char * file_name);
58
char * c_to_o_ext (IN char * str);
59
DaStrings * compile_files (IN char * source_files[], size_t source_files_len, IN char * build_flags[], size_t build_flags_len, INOUT Nob_Cmd * cmd, INOUT Nob_Procs * procs);
60
void link_files (IN DaStrings * object_files, IN char * exec_name, IN char * link_flags[], size_t link_flags_len, INOUT Nob_Cmd * cmd);
61
void clean_files (IN char * source_files[], size_t len, char * exec_name, INOUT Nob_Cmd * cmd);
62
char * construct_string (IN char * str, ...);
63
NobberError run_excutable (INOUT Nob_Cmd * cmd, IN char * executable);
64
char * get_path_of_current_executalbe ();
65
char ** split_string (IN char * str, char delimeter, OUT size_t * out_size);
66
67
68
//#define free0(ptr) \
69
//    free (ptr); \
70
//    ptr = NULL;
71
#define free0(ptr) \
72
    memset ((void *)ptr, 0, sizeof ((void *) ptr)); \
73
    free (ptr);
74
75
struct da_strings_t {
76
    char ** items;
77
    size_t count;
78
    size_t capacity;
79
};
80
81
82
/** 
83
 * free the items in a list propperly!
84
 * TODO: Need a version that takes a FreeFunc.
85
 **/
86
#define da_free_items(Type, da) { \
87
    for (Type *it = (da)->items; it < (da)->items + (da)->capacity; it++) { \
88
        if (*it == NULL) break;\
89
        free (*it);\
90
    }\
91
    free ((da)->items);\
92
}
93
94
#ifdef NOBBER_UTILS_IMPLEMENTAITON
95
96
/* ----------------- */
97
98
void * malloc0 (size_t size) {
99
    void * out_val = malloc (size);
100
    memset (out_val, 0, size);
101
    return out_val;
102
}
103
104
105
// https://stackoverflow.com/questions/43163677/how-do-i-strip-a-file-extension-from-a-string-in-c
106
char * strip_extention (IN char * file_name) {
107
    char * out_str = malloc(strlen(file_name) + 1);
108
    strcpy (out_str, file_name);
109
    char *end = out_str + strlen(out_str);
110
111
    while (end > out_str && *end != '.' && *end != '\\' && *end != '/') {
112
        --end;
113
    }
114
115
    if ((end > out_str && *end == '.') &&
116
            (*(end - 1) != '\\' && *(end - 1) != '/')) {
117
        *end = '\0';
118
    }
119
120
    return out_str;
121
}
122
123
char * c_to_o_ext (IN char * str) {
124
    char * out_str = malloc (strlen(str) + 1);
125
    char * tmp_str = strip_extention (str);
126
    sprintf (out_str, "%s.o", tmp_str); 
127
    free (tmp_str);
128
    return out_str;
129
}
130
131
DaStrings * compile_files (IN char * source_files[], size_t source_files_len,
132
                           IN char * build_flags[], size_t build_flags_len, 
133
                           INOUT Nob_Cmd * cmd, INOUT Nob_Procs * procs) {
134
    DaStrings * object_files = malloc0 (sizeof (DaStrings));
135
    for (size_t i = 0; i < source_files_len; i++) {
136
        cmd->count = 0;
137
        if (source_files[i] == NULL) break;
138
        nob_cmd_append (cmd, "cc");
139
        nob_cmd_append (cmd, source_files[i]);
140
        nob_da_append_many (cmd, build_flags, build_flags_len);
141
        nob_cmd_append (cmd, "-c");
142
        char * tmp_str = c_to_o_ext (source_files[i]);
143
        nob_cmd_append (cmd, "-o", tmp_str);
144
145
        char * s = malloc0 (strlen (tmp_str) + 1);
146
        strcpy (s, tmp_str);
147
        nob_da_append (object_files, s);
148
149
        nob_cmd_run (cmd, .async = procs);
150
        free0 (tmp_str);
151
    }
152
    return object_files;
153
}
154
155
void link_files (IN DaStrings * object_files, IN char * exec_name,
156
        IN char * link_flags[], size_t link_flags_len,
157
        INOUT Nob_Cmd * cmd) {
158
    nob_cmd_append (cmd, "cc");
159
    nob_cmd_append (cmd, "-o", exec_name);
160
    nob_da_append_many (cmd, (char**) object_files->items, object_files->count);
161
    nob_da_append_many (cmd, (char**) link_flags, link_flags_len);
162
    nob_cmd_run (cmd);
163
}
164
165
void clean_files (IN char * source_files[],  size_t len, char * exec_name, INOUT Nob_Cmd * cmd) {
166
    cmd->count = 0;
167
    DaStrings tmp_strings = {0};
168
    for (size_t i = 0; i < len; i++) {
169
        if (source_files[i] == NULL) break;
170
        char * tmp_file = strip_extention ((char *)source_files[i]);
171
        char * tmp_obj_file = c_to_o_ext (tmp_file);
172
        nob_da_append (&tmp_strings, tmp_obj_file);
173
        tmp_file = c_to_o_ext (tmp_file);
174
        free0 (tmp_file);
175
    }
176
    nob_cmd_append (cmd, "rm");
177
    nob_da_append_many (cmd, tmp_strings.items, tmp_strings.count);
178
    for (size_t i = 0; i < tmp_strings.count; i++) {
179
        char * s = tmp_strings.items[i];
180
        if (s == NULL) break;
181
    }
182
    nob_cmd_append (cmd, exec_name);
183
    nob_cmd_run (cmd);
184
    da_free_items (char *, &tmp_strings);
185
}
186
187
char * construct_string (IN char * str, ...) {
188
    char * retval = NULL;
189
    va_list list = {0};
190
    Nob_String_Builder sb = {0};
191
    nob_sb_append_cstr (&sb, str);
192
    va_start (list, str);
193
    while (*str++) {
194
        nob_sb_append_cstr (&sb, str);
195
    }
196
    va_end (list);
197
    Nob_String_View sv = nob_sv_from_parts (sb.items, sb.count);
198
    retval = malloc0 (strlen (sv.data) + 1);
199
    strcpy (retval, sv.data);
200
    return retval;
201
}
202
203
NobberError run_excutable (INOUT Nob_Cmd * cmd, IN char * executable) {
204
    // We assume we are only running from the current directory.
205
    char * cwd;
206
    NobberError ret_val = NOBBER_RETURN_NORMAL;
207
    strcat (cwd, "/");
208
    strcat (cwd, executable);
209
    return ret_val;
210
}
211
212
char * get_path_of_current_executalbe () {
213
    char buf[PATH_MAX];
214
#if  defined(__DragonFly__) || defined(__NetBSD__) || defined(__linux__)
215
    #if defined(__linux__)
216
    #define PROC_EXE_PATH "/proc/self/exe"
217
    #elif defined(__NetBSD__)
218
    #define PROC_EXE_PATH "/proc/curproc/exe"
219
    #elif defined(__DragonFly__)
220
    #endif
221
    if (readlink (PROC_EXE_PATH, buf, PATH_MAX) < 0) {
222
        fprintf (stderr, "[ERROR] Could not readlink /proc/self/exe: %s", strerror (errno));
223
        return NULL;
224
    }
225
#elif defined(__FreeBSD__)
226
    int mib[4];
227
    mib[0] = CTL_KERN;
228
    mib[1] = KERN_PROC;
229
    mib[2] = KERN_PROC_PATHNAME;
230
    mib[3] = -1;
231
    sysctl(mib, 4, buf, PATH_MAX, NULL, 0);
232
#elif defined(__darwin__)
233
    if (_NSGetExecutablePath(buf, PATH_MAX) < 0) {
234
        fprintf (stderr, "[ERROR] Could not get executable path.");
235
    }
236
#elif defined(WIN32)
237
    if (!GetModuleFileNameA (NULL, buf, MAX_PATH)) {
238
        fprintf (stderr, "[ERROR] Could not readlink /proc/self/exe: %s", strerror (errno));
239
        return NULL;
240
    }
241
#else
242
    static_assert (false, "get_path_of_current_executalbe () is not implemented for this platform.");
243
#endif
244
    char * ret = malloc (strlen (buf));
245
    strcpy(ret, buf);
246
    return ret;
247
}
248
249
char ** split_string (IN char * str, char deliminator, OUT size_t * out_size) {
250
    char * str_cpy = strndup (str, strlen (str));
251
    char * ptr = str_cpy;
252
    char delim[2] = {deliminator, 0};
253
    size_t no_of_tokens = 0;
254
255
    // Count the nuber of tokens
256
    while (*ptr) {
257
        if (*ptr == deliminator) {
258
            no_of_tokens++;
259
        }
260
        ptr++;
261
    }
262
    if (*(--ptr) != deliminator) {
263
        no_of_tokens++;
264
    }
265
    no_of_tokens++; // add empty space.
266
    
267
    char ** result = malloc0 (sizeof (char *) * no_of_tokens);
268
    if (result) {
269
        size_t idx = 0;
270
        char * tok_ptr = str_cpy;
271
  
272
        char * token = strtok (tok_ptr, delim);
273
        while (token) {
274
            result[idx] = strndup (token, strlen (token));
275
            token = strtok (NULL, delim);
276
            idx++;
277
        }
278
        result[idx] = 0;
279
    }
280
    *out_size = no_of_tokens - 1;
281
    free (str_cpy);
282
    return result;
283
}
284
285
286
#endif // NOBBER_UTILS_IMPLEMENTATION