UrForth: added flags to some built-in words
[urasm.git] / src / urasm-new.c
blob992f609564c453a6d0eaa44e2eb31db900790570
1 // UrForth/C standalone
2 // coded by Ketmar // Invisible Vector
3 // GPLv3 ONLY
4 //
5 #ifndef _GNU_SOURCE
6 # define _GNU_SOURCE
7 #endif
9 #include <setjmp.h>
10 #include <stdarg.h>
11 #include <stddef.h>
12 #include <stdint.h>
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <unistd.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
22 #ifdef WIN32
23 # include <windows.h>
24 #else
25 # include <signal.h>
26 #endif
28 #include "liburforth/urforth.h"
31 #define UR_FORCE_INLINE static inline __attribute__((always_inline))
32 #define UR_INLINE static inline
35 #define VERSION_HI 2
36 #define VERSION_MID 0
37 #define VERSION_LO 1
40 #define MAYBE_UNUSED __attribute__((unused))
43 // ////////////////////////////////////////////////////////////////////////// //
44 __attribute((unused))
45 static const char *ur_assert_failure (const char *cond, const char *fname, int fline,
46 const char *func)
48 for (const char *t = fname; *t; ++t) {
49 #ifdef WIN32
50 if (*t == '/' || *t == '\\') fname = t+1;
51 #else
52 if (*t == '/') fname = t+1;
53 #endif
55 fflush(stdout);
56 fprintf(stderr, "\n%s:%d: Assertion in `%s` failed: %s\n", fname, fline, func, cond);
57 fflush(stderr);
58 abort();
61 #define ur_assert(cond_) do { if (__builtin_expect((!(cond_)), 0)) { ur_assert_failure(#cond_, __FILE__, __LINE__, __PRETTY_FUNCTION__); } } while (0)
64 // ////////////////////////////////////////////////////////////////////////// //
65 static char *ufoIncludeDir = NULL;
68 //==========================================================================
70 // initUFEInclideDir
72 //==========================================================================
73 static void initUFEInclideDir (void) {
74 const char *id = getenv("URASM_URFORTH_INCLUDE_DIR");
75 if (id && id[0]) {
76 ufoIncludeDir = strdup(id);
77 } else {
78 char myDir[4096];
79 memset(myDir, 0, sizeof(myDir));
80 #ifndef WIN32
81 if (readlink("/proc/self/exe", myDir, sizeof(myDir)-1) < 0) {
82 strcpy(myDir, ".");
83 } else {
84 char *p = (char *)strrchr(myDir, '/');
85 if (!p) strcpy(myDir, "."); else *p = '\0';
87 #else
88 GetModuleFileName(GetModuleHandle(NULL), myDir, sizeof(myDir)-1);
89 char *p = strrchr(myDir, '\\');
90 if (!p) strcpy(myDir, "."); else *p = '\0';
91 #endif
92 strcat(myDir, "/urflibs");
93 ur_assert(ufoIncludeDir == NULL);
94 ufoIncludeDir = strdup(myDir);
96 while (ufoIncludeDir[0] && ufoIncludeDir[strlen(ufoIncludeDir)-1] == '/') ufoIncludeDir[strlen(ufoIncludeDir)-1] = '\0';
97 if (!ufoIncludeDir[0]) strcpy(ufoIncludeDir, ".");
101 static jmp_buf errJP;
102 static int g_argc;
103 static char **g_argv;
106 //==========================================================================
108 // ufoFatalError
110 //==========================================================================
111 __attribute__((noreturn))
112 void ufoFatalError (void) {
113 longjmp(errJP, 666);
117 //==========================================================================
119 // strprintfVA
121 //==========================================================================
122 static char *strprintfVA (const char *fmt, va_list vaorig) {
123 char *buf = NULL;
124 int olen, len = 128;
126 buf = malloc(len);
127 if (buf == NULL) { fprintf(stderr, "\nFATAL: out of memory!\n"); abort(); }
128 for (;;) {
129 char *nb;
130 va_list va;
132 va_copy(va, vaorig);
133 olen = vsnprintf(buf, len, fmt, va);
134 va_end(va);
135 if (olen >= 0 && olen < len) return buf;
136 if (olen < 0) olen = len*2-1;
137 nb = realloc(buf, olen+1);
138 if (nb == NULL) { fprintf(stderr, "\nFATAL: out of memory!\n"); abort(); }
139 buf = nb;
140 len = olen+1;
145 //==========================================================================
147 // strprintf
149 //==========================================================================
150 static __attribute__((format(printf,1,2))) char *strprintf (const char *fmt, ...) {
151 char *buf = NULL;
152 va_list va;
153 va_start(va, fmt);
154 buf = strprintfVA(fmt, va);
155 va_end(va);
156 return buf;
160 //==========================================================================
162 // findMain
164 // return NULL or new path
166 //==========================================================================
167 static char *findMain (const char *path, const char **mainList) {
168 struct stat st;
169 while (*mainList != NULL) {
170 char *newpath = strprintf("%s/%s", path, *mainList);
171 if (stat(newpath, &st) == 0) {
172 if (!S_ISDIR(st.st_mode)) {
173 return newpath;
176 free(newpath);
177 mainList += 1u;
179 return NULL;
183 static const char *sysMains[] = {
184 "00-main-loader.f",
185 NULL
189 static const char *userMains[] = {
190 "zzmain.f",
191 "main.f",
192 "00-main-loader.f",
193 "zzmain.zas",
194 "main.zas",
195 NULL,
199 //==========================================================================
201 // createIncludeName
203 // return malloced string
205 //==========================================================================
206 static char *createIncludeName (const char *fname, int assystem, const char *lastIncPathUFO) {
207 struct stat st;
208 char *res;
209 char *newpath;
211 if (!fname || !fname[0]) return NULL;
213 if (fname[0] != '/') {
214 const char *incdir = lastIncPathUFO;
215 if (assystem && (!incdir || !incdir[0])) incdir = ufoIncludeDir;
216 if (incdir == NULL || incdir[0] == 0) incdir = ".";
217 res = strprintf("%s/%s", incdir, fname);
218 } else {
219 res = strprintf("%s", fname);
222 if (stat(res, &st) == 0) {
223 if (S_ISDIR(st.st_mode)) {
224 newpath = findMain(res, (assystem ? sysMains : userMains));
225 if (newpath != NULL) {
226 free(res);
227 res = newpath;
230 } else if (assystem && fname[0] != '/' && ufoIncludeDir != NULL && ufoIncludeDir[0] != 0) {
231 // if it is a system include, try from system root
232 newpath = strprintf("%s/%s", ufoIncludeDir, fname);
233 if (stat(newpath, &st) == 0) {
234 free(res);
235 res = newpath;
236 if (S_ISDIR(st.st_mode)) {
237 newpath = findMain(res, sysMains);
238 if (newpath != NULL) {
239 free(res);
240 res = newpath;
243 } else {
244 free(newpath);
248 //fprintf(stderr, "inc: fname=<%s>; sys=%d; def=<%s>; res=<%s>\n", fname, assystem, defaultmain, res);
249 return res;
253 //==========================================================================
255 // ufoCreateIncludeName
257 //==========================================================================
258 char *ufoCreateIncludeName (const char *fname, int assystem, const char *lastIncPath) {
259 #if 0
260 fprintf(stderr, "ICIN: fname=<%s>; lastinc=<%s>; assystem=%d\n",
261 fname, lastIncPath, assystem);
262 #endif
263 if (lastIncPath == NULL && assystem) lastIncPath = ufoIncludeDir;
264 return createIncludeName(fname, assystem, lastIncPath);
268 #ifndef WIN32
269 //==========================================================================
271 // sigCtrlC
273 //==========================================================================
274 static void sigCtrlC (int sig) {
275 ufoSetUserAbort();
277 #endif
280 //==========================================================================
282 // ufcWord_N_BYE
284 //==========================================================================
285 static void ufcWord_N_BYE (uint32_t pfa) {
286 uint32_t ec = ufoPopData();
287 exit((int)ec);
291 //==========================================================================
293 // ufcWord_BYE
295 //==========================================================================
296 static void ufcWord_BYE (uint32_t pfa) {
297 exit(0);
301 //==========================================================================
303 // ufcWord_ARGC
305 //==========================================================================
306 static void ufcWord_ARGC (uint32_t pfa) {
307 int rest = g_argc;
308 if (rest <= 0) ufoPushData(0); else ufoPushData((uint32_t)rest);
312 //==========================================================================
314 // ufcWord_ARGV
316 // ARGV ( idx -- addr count )
317 // copy CLI arg to PAD+4, and set counter to PAD.
318 // 0 is first arg, not program name!
320 //==========================================================================
321 static void ufcWord_ARGV (uint32_t pfa) {
322 uint32_t idx = ufoPopData();
323 int rest = g_argc;
324 const uint32_t addr = ufoGetPAD() + 4u;
325 uint32_t count = 0;
326 if (rest > 0 || idx < rest) {
327 const unsigned char *arg = (const unsigned char *)(g_argv[(int)idx]);
328 while (*arg) {
329 ufoPokeByte(addr + count, *arg);
330 count += 1u; arg += 1u;
333 ufoPokeCell(addr - 4u, count);
334 ufoPushData(addr);
335 ufoPushData(count);
339 //==========================================================================
341 // initUrForth
343 //==========================================================================
344 static void initUrForth (void) {
345 #ifdef WIN32
346 ufoCondDefine("SHITDOZE");
347 #else
348 ufoCondDefine("NIX");
349 #endif
350 ufoCondDefine("URASM-NEW");
351 if (ufoSStepAllowed()) ufoCondDefine("DEBUGGER");
352 ufoRegisterWord("N-BYE", &ufcWord_N_BYE, UFW_FLAG_PROTECTED);
353 ufoRegisterWord("BYE", &ufcWord_BYE, UFW_FLAG_PROTECTED);
354 ufoRegisterWord("ARGC", &ufcWord_ARGC, UFW_FLAG_PROTECTED);
355 ufoRegisterWord("ARGV", &ufcWord_ARGV, UFW_FLAG_PROTECTED);
359 //==========================================================================
361 // urcShutdown
363 //==========================================================================
364 static void urcShutdown (void) {
365 ufoDeinit();
366 if (ufoIncludeDir) free(ufoIncludeDir);
370 //==========================================================================
372 // main
374 //==========================================================================
375 int main (int argc, char *argv[]) {
376 int res = 0;
377 int dorepl = 0;
378 int allowDebug = 0;
380 ufoSetUserPostInit(&initUrForth);
382 initUFEInclideDir();
384 printf("UrForth/C & UrAsm v%d.%d.%d, compile date: %s %s\n",
385 VERSION_HI, VERSION_MID, VERSION_LO, __DATE__, __TIME__);
387 g_argc = argc - 1;
388 g_argv = argv + 1;
390 if (g_argc > 0 && strcmp(g_argv[0], "--repl") == 0) {
391 dorepl = 1;
392 g_argc -= 1; g_argv += 1;
395 if (g_argc > 0 && strcmp(g_argv[0], "--debug") == 0) {
396 if (!ufoIsMTaskEnabled()) {
397 fflush(NULL); fprintf(stderr, "FATAL: cannot enable debugger, no multitask support!\n");
398 exit(1);
400 allowDebug = 1;
401 g_argc -= 1; g_argv += 1;
404 #ifndef WIN32
405 signal(SIGINT, &sigCtrlC);
406 #endif
408 atexit(&urcShutdown);
410 if (setjmp(errJP) == 0) {
411 ufoInit();
412 } else {
413 fprintf(stderr, "FATAL: INITILIZATION FAILED!\n");
414 exit(1);
417 ufoSetSStepAllowed(allowDebug);
419 if (dorepl) {
420 for (;;) {
421 if (setjmp(errJP) == 0) {
422 uint32_t cfa;
423 cfa = ufoFindWordInVocabulary("UFO-RUN-REPL", ufoGetForthVocId());
424 if (cfa == 0) {
425 fprintf(stderr, "FATAL: REPL is not available.\n");
426 exit(1);
427 } else {
428 ufoRunWord(cfa);
432 } else {
433 uint32_t cfa = ufoFindWordInVocabulary("RUN-URASM", ufoGetForthVocId());
434 if (cfa == 0) {
435 fprintf(stderr, "FATAL: cannot find main URASM loop word.\n");
436 exit(1);
438 if (setjmp(errJP) == 0) {
439 ufoRunWord(cfa);
440 } else {
441 res = 1;
445 return (res ? 1 : 0);