1+ // Copyright 2021 Alexey Kutepov <reximkut@gmail.com>
2+ //
3+ // Permission is hereby granted, free of charge, to any person obtaining
4+ // a copy of this software and associated documentation files (the
5+ // "Software"), to deal in the Software without restriction, including
6+ // without limitation the rights to use, copy, modify, merge, publish,
7+ // distribute, sublicense, and/or sell copies of the Software, and to
8+ // permit persons to whom the Software is furnished to do so, subject to
9+ // the following conditions:
10+ //
11+ // The above copyright notice and this permission notice shall be
12+ // included in all copies or substantial portions of the Software.
13+ //
14+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+ // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+ // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17+ // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18+ // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19+ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20+ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21+ //
22+ // ============================================================
23+ //
24+ // nobuild — 0.0.1 — Header only library for writing build recipes in C.
25+ //
26+ // https://github.com/tsoding/nobuild
27+ //
28+ // ============================================================
29+ //
30+ // ChangeLog (https://semver.org/ is implied)
31+ //
32+ // 0.0.1 First Official Release
33+
34+ #ifndef NOBUILD_H_
35+ #define NOBUILD_H_
36+
137#include <assert.h>
238#include <stdio.h>
339#include <stdlib.h>
945# define WIN32_LEAN_AND_MEAN
1046# include "windows.h"
1147# include <process.h>
48+ // minirent.h HEADER BEGIN ////////////////////////////////////////
49+ // Copyright 2021 Alexey Kutepov <reximkut@gmail.com>
50+ //
51+ // Permission is hereby granted, free of charge, to any person obtaining
52+ // a copy of this software and associated documentation files (the
53+ // "Software"), to deal in the Software without restriction, including
54+ // without limitation the rights to use, copy, modify, merge, publish,
55+ // distribute, sublicense, and/or sell copies of the Software, and to
56+ // permit persons to whom the Software is furnished to do so, subject to
57+ // the following conditions:
58+ //
59+ // The above copyright notice and this permission notice shall be
60+ // included in all copies or substantial portions of the Software.
61+ //
62+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
63+ // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
64+ // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
65+ // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
66+ // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
67+ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
68+ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
69+ //
70+ // ============================================================
71+ //
72+ // minirent — 0.0.1 — A subset of dirent interface for Windows.
73+ //
74+ // https://github.com/tsoding/minirent
75+ //
76+ // ============================================================
77+ //
78+ // ChangeLog (https://semver.org/ is implied)
79+ //
80+ // 0.0.1 First Official Release
81+
82+ #ifndef MINIRENT_H_
83+ #define MINIRENT_H_
84+
85+ #define WIN32_LEAN_AND_MEAN
86+ #include "windows.h"
87+
88+ struct dirent
89+ {
90+ char d_name [MAX_PATH + 1 ];
91+ };
92+
93+ typedef struct DIR DIR ;
94+
95+ DIR * opendir (const char * dirpath );
96+ struct dirent * readdir (DIR * dirp );
97+ int closedir (DIR * dirp );
98+
99+ #endif // MINIRENT_H_
100+ // minirent.h HEADER END ////////////////////////////////////////
12101#else
13102# include <sys/stat.h>
14103# include <sys/types.h>
15104# include <sys/wait.h>
16105# include <unistd.h>
106+ # include <dirent.h>
17107#endif // _WIN32
18108
19109// TODO(#1): no way to disable echo in nobuild scripts
20110// TODO(#2): no way to ignore fails
21111
22- #ifdef _WIN32
23- struct dirent
24- {
25- char d_name [MAX_PATH + 1 ];
26- };
27-
28- typedef struct {
29- HANDLE hFind ;
30- WIN32_FIND_DATA data ;
31- struct dirent * dirent ;
32- } DIR ;
33-
34- DIR * opendir (const char * dirpath )
35- {
36- assert (dirpath );
37-
38- char buffer [MAX_PATH ];
39- snprintf (buffer , MAX_PATH , "%s\\*" , dirpath );
40-
41- DIR * dir = (DIR * )calloc (1 , sizeof (DIR ));
42-
43- dir -> hFind = FindFirstFile (buffer , & dir -> data );
44- if (dir -> hFind == INVALID_HANDLE_VALUE ) {
45- goto fail ;
46- }
47-
48- return dir ;
49-
50- fail :
51- if (dir ) {
52- free (dir );
53- }
54-
55- return NULL ;
56- }
57-
58- struct dirent * readdir (DIR * dirp )
59- {
60- assert (dirp );
61-
62- if (dirp -> dirent == NULL ) {
63- dirp -> dirent = (struct dirent * )calloc (1 , sizeof (struct dirent ));
64- } else {
65- if (!FindNextFile (dirp -> hFind , & dirp -> data )) {
66- return NULL ;
67- }
68- }
69-
70- memset (dirp -> dirent -> d_name , 0 , sizeof (dirp -> dirent -> d_name ));
71-
72- strncpy (
73- dirp -> dirent -> d_name ,
74- dirp -> data .cFileName ,
75- sizeof (dirp -> dirent -> d_name ) - 1 );
76-
77- return dirp -> dirent ;
78- }
79-
80- void closedir (DIR * dirp )
81- {
82- assert (dirp );
83-
84- FindClose (dirp -> hFind );
85- if (dirp -> dirent ) {
86- free (dirp -> dirent );
87- }
88- free (dirp );
89- }
90- #else
91- # include <dirent.h>
92- #endif // _WIN32
93-
94112#ifdef _WIN32
95113# define PATH_SEP "\\"
96114#else
@@ -133,6 +151,109 @@ void closedir(DIR *dirp)
133151 closedir(dir); \
134152 } while(0)
135153
154+ // TODO(#5): there is no way to redirect the output of CMD to a file
155+ #define CMD (...) \
156+ do { \
157+ printf("[INFO] %s\n", CONCAT_SEP(" ", __VA_ARGS__)); \
158+ cmd_impl(69, __VA_ARGS__, NULL); \
159+ } while(0)
160+
161+ const char * concat_impl (int ignore , ...);
162+ const char * concat_sep_impl (const char * sep , ...);
163+ void mkdirs_impl (int ignore , ...);
164+ void cmd_impl (int ignore , ...);
165+ void nobuild_exec (const char * * argv );
166+ const char * remove_ext (const char * path );
167+ char * shift (int * argc , char * * * argv );
168+
169+ #define CONCAT (...) concat_impl(69, __VA_ARGS__, NULL)
170+ #define CONCAT_SEP (sep , ...) concat_sep_impl(sep, __VA_ARGS__, NULL)
171+ #define PATH (...) CONCAT_SEP(PATH_SEP, __VA_ARGS__)
172+ #define MKDIRS (...) mkdirs_impl(69, __VA_ARGS__, NULL)
173+
174+ #endif // NOBUILD_H_
175+
176+ #ifdef NOBUILD_IMPLEMENTATION
177+
178+ #ifdef _WIN32
179+ // minirent.h IMPLEMENTATION BEGIN ////////////////////////////////////////
180+ struct DIR
181+ {
182+ HANDLE hFind ;
183+ WIN32_FIND_DATA data ;
184+ struct dirent * dirent ;
185+ };
186+
187+ DIR * opendir (const char * dirpath )
188+ {
189+ assert (dirpath );
190+
191+ char buffer [MAX_PATH ];
192+ snprintf (buffer , MAX_PATH , "%s\\*" , dirpath );
193+
194+ DIR * dir = (DIR * )calloc (1 , sizeof (DIR ));
195+
196+ dir -> hFind = FindFirstFile (buffer , & dir -> data );
197+ if (dir -> hFind == INVALID_HANDLE_VALUE ) {
198+ errno = ENOSYS ;
199+ goto fail ;
200+ }
201+
202+ return dir ;
203+
204+ fail :
205+ if (dir ) {
206+ free (dir );
207+ }
208+
209+ return NULL ;
210+ }
211+
212+ struct dirent * readdir (DIR * dirp )
213+ {
214+ assert (dirp );
215+
216+ if (dirp -> dirent == NULL ) {
217+ dirp -> dirent = (struct dirent * )calloc (1 , sizeof (struct dirent ));
218+ } else {
219+ if (!FindNextFile (dirp -> hFind , & dirp -> data )) {
220+ if (GetLastError () != ERROR_NO_MORE_FILES ) {
221+ errno = ENOSYS ;
222+ }
223+
224+ return NULL ;
225+ }
226+ }
227+
228+ memset (dirp -> dirent -> d_name , 0 , sizeof (dirp -> dirent -> d_name ));
229+
230+ strncpy (
231+ dirp -> dirent -> d_name ,
232+ dirp -> data .cFileName ,
233+ sizeof (dirp -> dirent -> d_name ) - 1 );
234+
235+ return dirp -> dirent ;
236+ }
237+
238+ int closedir (DIR * dirp )
239+ {
240+ assert (dirp );
241+
242+ if (!FindClose (dirp -> hFind )) {
243+ errno = ENOSYS ;
244+ return -1 ;
245+ }
246+
247+ if (dirp -> dirent ) {
248+ free (dirp -> dirent );
249+ }
250+ free (dirp );
251+
252+ return 0 ;
253+ }
254+ // minirent.h IMPLEMENTATION END ////////////////////////////////////////
255+ #endif // _WIN32
256+
136257const char * concat_sep_impl (const char * sep , ...)
137258{
138259 const size_t sep_len = strlen (sep );
@@ -169,10 +290,6 @@ const char *concat_sep_impl(const char *sep, ...)
169290 return result ;
170291}
171292
172- #define CONCAT_SEP (sep , ...) concat_sep_impl(sep, __VA_ARGS__, NULL)
173-
174- #define PATH (...) CONCAT_SEP(PATH_SEP, __VA_ARGS__)
175-
176293void mkdirs_impl (int ignore , ...)
177294{
178295 size_t length = 0 ;
@@ -218,8 +335,6 @@ void mkdirs_impl(int ignore, ...)
218335 });
219336}
220337
221- #define MKDIRS (...) mkdirs_impl(69, __VA_ARGS__, NULL)
222-
223338// TODO(#3): there is no way to remove a folder
224339// TODO(#4): there is no way to remove a file
225340
@@ -244,7 +359,8 @@ const char *concat_impl(int ignore, ...)
244359 return result ;
245360}
246361
247- #define CONCAT (...) concat_impl(69, __VA_ARGS__, NULL)
362+
363+
248364
249365void nobuild_exec (const char * * argv )
250366{
@@ -322,13 +438,6 @@ void cmd_impl(int ignore, ...)
322438 nobuild_exec (argv );
323439}
324440
325- // TODO(#5): there is no way to redirect the output of CMD to a file
326- #define CMD (...) \
327- do { \
328- printf("[INFO] %s\n", CONCAT_SEP(" ", __VA_ARGS__)); \
329- cmd_impl(69, __VA_ARGS__, NULL); \
330- } while(0)
331-
332441const char * remove_ext (const char * path )
333442{
334443 size_t n = strlen (path );
@@ -355,3 +464,5 @@ char *shift(int *argc, char ***argv)
355464 * argc -= 1 ;
356465 return result ;
357466}
467+
468+ #endif // NOBUILD_IMPLEMENTATION
0 commit comments