/* Build with: cc -Os -o nrj nrj.c */ #include #include #include #include #include #ifndef NRJBITS #define NRJBITS 16 #endif #ifndef NRJWORD #define NRJWORD unsigned short #endif #define NRJSIZE (1 << NRJBITS) #define NRJWSIZE sizeof(NRJWORD) int kbhit() { struct timeval tv = { 0L, 0L }; fd_set fds; FD_ZERO(&fds); FD_SET(0, &fds); return select(1, &fds, NULL, NULL, &tv) > 0; } int getch() { int r; unsigned char c; if((r = read(0, &c, 1)) < 0) return r; else return c; } struct termios tty_opts_backup, tty_opts_raw; void restore_term() { tcsetattr(STDIN_FILENO, TCSANOW, &tty_opts_backup); } void nrj_in(NRJWORD *ctxid, NRJWORD *val) { int x; if(*ctxid == (NRJWORD) 0) { /* for now, only emulate standard context id */ *val = (NRJWORD) 0; if(kbhit()) { x = getch(); if(x > -1) *val = (NRJWORD) x; } } } void nrj_out(NRJWORD *ctxid, NRJWORD *val) { if(*ctxid == (NRJWORD) 0) /* for now, only emulate standard context id */ putchar((unsigned char) *val); } void nrj_load(NRJWORD* m, NRJWORD offset, char *fname) { FILE *prog = fopen(fname, "rb"); if(prog) { fseek(prog, 0, SEEK_END); int flen = ftell(prog); fseek(prog, 0, SEEK_SET); fread(m+offset, NRJWSIZE, flen/NRJWSIZE, prog); fclose(prog); cfmakeraw(&tty_opts_raw); tcsetattr(STDIN_FILENO, TCSANOW, &tty_opts_raw); } else { printf("NRJ16: could not open the input file %s\r\n", fname); exit(1); } } void nrj_run(char *program) { NRJWORD maxaddr = (NRJWORD) (NRJSIZE - 1), mem[NRJSIZE], pc; mem[0] = mem[1] = mem[2] = (NRJWORD) 0; pc = (NRJWORD) 3; nrj_load(mem, pc, program); while(pc != maxaddr) { if(mem[0]) nrj_in(&mem[2], &mem[mem[0]]); mem[mem[pc]] = (~(mem[mem[pc]] | mem[mem[pc+1]])) & maxaddr; pc = mem[mem[pc+2]]; mem[0] = (NRJWORD) 0; if(mem[1]) { nrj_out(&mem[2], &mem[mem[1]]); mem[1] = (NRJWORD) 0; } } } int main(int argc, char* argv[]) { tcgetattr(STDIN_FILENO, &tty_opts_backup); atexit(&restore_term); if(argc > 1) nrj_run(argv[1]); else { puts("NRJ16: no binary specified\r"); return 1; } return 0; }