/nobber/trunk

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/nobber/trunk

« back to all changes in this revision

Viewing changes to utils.h

  • Committer: Stream
  • Date: 2025-10-12 21:19:24 UTC
  • Revision ID: streamer@octo-20251012211924-r4fksu08qztqqbxz
* Moved functions to utils.h
* Added split_string ()
* Added get_path_of_current_executable
* added test_macros.h
* added first tests.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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