1 // UrForth/C standalone
2 // coded by Ketmar // Invisible Vector
18 #include <sys/types.h>
28 #include "liburforth/urforth.h"
31 #define UR_FORCE_INLINE static inline __attribute__((always_inline))
32 #define UR_INLINE static inline
40 #define MAYBE_UNUSED __attribute__((unused))
43 // ////////////////////////////////////////////////////////////////////////// //
45 static const char *ur_assert_failure (const char *cond
, const char *fname
, int fline
,
48 for (const char *t
= fname
; *t
; ++t
) {
50 if (*t
== '/' || *t
== '\\') fname
= t
+1;
52 if (*t
== '/') fname
= t
+1;
56 fprintf(stderr
, "\n%s:%d: Assertion in `%s` failed: %s\n", fname
, fline
, func
, cond
);
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 //==========================================================================
72 //==========================================================================
73 static void initUFEInclideDir (void) {
74 const char *id
= getenv("URASM_URFORTH_INCLUDE_DIR");
76 ufoIncludeDir
= strdup(id
);
79 memset(myDir
, 0, sizeof(myDir
));
81 if (readlink("/proc/self/exe", myDir
, sizeof(myDir
)-1) < 0) {
84 char *p
= (char *)strrchr(myDir
, '/');
85 if (!p
) strcpy(myDir
, "."); else *p
= '\0';
88 GetModuleFileName(GetModuleHandle(NULL
), myDir
, sizeof(myDir
)-1);
89 char *p
= strrchr(myDir
, '\\');
90 if (!p
) strcpy(myDir
, "."); else *p
= '\0';
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
;
103 static char **g_argv
;
106 //==========================================================================
110 //==========================================================================
111 __attribute__((noreturn
))
112 void ufoFatalError (void) {
117 //==========================================================================
121 //==========================================================================
122 static char *strprintfVA (const char *fmt
, va_list vaorig
) {
127 if (buf
== NULL
) { fprintf(stderr
, "\nFATAL: out of memory!\n"); abort(); }
133 olen
= vsnprintf(buf
, len
, fmt
, 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(); }
145 //==========================================================================
149 //==========================================================================
150 static __attribute__((format(printf
,1,2))) char *strprintf (const char *fmt
, ...) {
154 buf
= strprintfVA(fmt
, va
);
160 //==========================================================================
164 // return NULL or new path
166 //==========================================================================
167 static char *findMain (const char *path
, const char **mainList
) {
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
)) {
183 static const char *sysMains
[] = {
189 static const char *userMains
[] = {
199 //==========================================================================
203 // return malloced string
205 //==========================================================================
206 static char *createIncludeName (const char *fname
, int assystem
, const char *lastIncPathUFO
) {
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
);
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
) {
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) {
236 if (S_ISDIR(st
.st_mode
)) {
237 newpath
= findMain(res
, sysMains
);
238 if (newpath
!= NULL
) {
248 //fprintf(stderr, "inc: fname=<%s>; sys=%d; def=<%s>; res=<%s>\n", fname, assystem, defaultmain, res);
253 //==========================================================================
255 // ufoCreateIncludeName
257 //==========================================================================
258 char *ufoCreateIncludeName (const char *fname
, int assystem
, const char *lastIncPath
) {
260 fprintf(stderr
, "ICIN: fname=<%s>; lastinc=<%s>; assystem=%d\n",
261 fname
, lastIncPath
, assystem
);
263 if (lastIncPath
== NULL
&& assystem
) lastIncPath
= ufoIncludeDir
;
264 return createIncludeName(fname
, assystem
, lastIncPath
);
269 //==========================================================================
273 //==========================================================================
274 static void sigCtrlC (int sig
) {
280 //==========================================================================
284 //==========================================================================
285 static void ufcWord_N_BYE (uint32_t pfa
) {
286 uint32_t ec
= ufoPopData();
291 //==========================================================================
295 //==========================================================================
296 static void ufcWord_BYE (uint32_t pfa
) {
301 //==========================================================================
305 //==========================================================================
306 static void ufcWord_ARGC (uint32_t pfa
) {
308 if (rest
<= 0) ufoPushData(0); else ufoPushData((uint32_t)rest
);
312 //==========================================================================
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();
324 const uint32_t addr
= ufoGetPAD() + 4u;
326 if (rest
> 0 || idx
< rest
) {
327 const unsigned char *arg
= (const unsigned char *)(g_argv
[(int)idx
]);
329 ufoPokeByte(addr
+ count
, *arg
);
330 count
+= 1u; arg
+= 1u;
333 ufoPokeCell(addr
- 4u, count
);
339 //==========================================================================
343 //==========================================================================
344 static void initUrForth (void) {
346 ufoCondDefine("SHITDOZE");
348 ufoCondDefine("NIX");
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 //==========================================================================
363 //==========================================================================
364 static void urcShutdown (void) {
366 if (ufoIncludeDir
) free(ufoIncludeDir
);
370 //==========================================================================
374 //==========================================================================
375 int main (int argc
, char *argv
[]) {
380 ufoSetUserPostInit(&initUrForth
);
384 printf("UrForth/C & UrAsm v%d.%d.%d, compile date: %s %s\n",
385 VERSION_HI
, VERSION_MID
, VERSION_LO
, __DATE__
, __TIME__
);
390 if (g_argc
> 0 && strcmp(g_argv
[0], "--repl") == 0) {
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");
401 g_argc
-= 1; g_argv
+= 1;
405 signal(SIGINT
, &sigCtrlC
);
408 atexit(&urcShutdown
);
410 if (setjmp(errJP
) == 0) {
413 fprintf(stderr
, "FATAL: INITILIZATION FAILED!\n");
417 ufoSetSStepAllowed(allowDebug
);
421 if (setjmp(errJP
) == 0) {
423 cfa
= ufoFindWordInVocabulary("UFO-RUN-REPL", ufoGetForthVocId());
425 fprintf(stderr
, "FATAL: REPL is not available.\n");
433 uint32_t cfa
= ufoFindWordInVocabulary("RUN-URASM", ufoGetForthVocId());
435 fprintf(stderr
, "FATAL: cannot find main URASM loop word.\n");
438 if (setjmp(errJP
) == 0) {
445 return (res
? 1 : 0);