ecce.c - ubuntuperonista/wiki_tp GitHub Wiki
<file></file>
- define VERSION "V2.10b" /* %V */
- define DATE "$Date: 2021/11/30 03:55:52 $"
- include <stdio.h></stdio.h>
- include <string.h></string.h>
- include <stdlib.h></stdlib.h>
- include <ctype.h></ctype.h>
- include <signal.h></signal.h>
- include <errno.h></errno.h>
- ifdef WANT_UTF8
- include <wchar.h></wchar.h>
- include <locale.h></locale.h>
- else
- define fputwc(x,f) fputc(x,f)
- define fgetwc(f) fgetc(f)
- define WEOF EOF
- endif
/**************************************************************************/
- define NOTE_FILE "/tmp/Note0" /* Specific to Linux - unfortunately, /tmp is shared by other users */
/* #define NOTE_FILE "/dev/shm/Note0" // Specific to the variation of Linux I'm using (ram disk) *SYS*/
/* I'm aware that this area of the code needs work to be made robust. It looks like I can't have robustness without some OS-specific code.
This code is already less portable than was first intended. Look for lines containing the marker *SYS* to see if the small deviations from portability affect your system.
Note that the libraries with most windows C compilers try to handle some unix constructs such as / as a filename separator, so even some of the code marked *SYS* is likely to work on Windows.
- /
/* Unfortunately tmpnam is deprecated due to timing issues */ /* with setting up file permissions - but it is the only call */ /* in this area that is portable to Win/DOS, and I'm trying */ /* to keep this source OS-independent. (without ifdef's) */
/* This is the remaining code issue I'ld like to fix before */ /* moving this to sourceforge. */
- define CONTEXT_OFFSET (strlen(NOTE_FILE)-1)
static char *ProgName = NULL; static char *parameter[4] = {NULL, NULL, NULL, NULL}; /* parameters - from, to, log, command */ static char *commandp = NULL;
- define F 0 /* FROM */
- define T 1 /* TO */
- define L 2 /* LOG */
- define C 3 /* COMMAND */
/* since we allocate RAM for the whole file, don't bother handling files longer than 32 bits. It's just a text editor after all... */
if (tmp == NULL) return 2UL*1024UL*1024UL; (void)fseek(tmp, 0L, SEEK_END); rc = ftell(tmp); if ((rc < 0) || ferror(tmp)) maxbuf = 0UL; else maxbuf = (unsigned long)rc; (void)fclose(tmp); return (maxbuf + 1024UL*256UL) * 3UL; }
/**************************************************************************/
- define FALSE (0!=0)
- define TRUE (0==0)
typedef int bool; typedef ecce_char *cindex;
/* Consts */
- define bs 8
- define bell 7
- define nul 0
- define del 127
- define casebit ('a'-'A')
- define minusbit casebit
- define plusbit 0x80
- define Max_command_units 4095
- define Max_parameter 4095
- define Max_prompt_length 4095
- define rep 1
- define txt 2
- define scope 4
- define sign 8
- define delim 16
- define numb 32
- define ext 64
- define err 128
- define dig 0
- define pc 1
- define lpar 2
- define comma 3
- define rpar 4
- define plus 5
- define minus 6
- define pling 7
- define star 8
- define termin 15
/* Global variables */
static unsigned long buffer_size = 0UL; static char *note_file; static bool ok; static bool printed; static long stopper; static int max_unit; static ecce_int pending_sym;
/* significance of file pointers using the 'buffer gap' method: */
/* [NL] o n e NL t w . . . o NL n e x t NL . . NL l a s t NL [NL] */ /* ! ! ! ! ! ! */ /* f l p f l f */ /* b b p p e e */ /* e e n n */ /* g g d d */
/* Note that when the buffer is 100% full, pp and fp are equal, and any insertion operations will fail. This is valid as pp is exclusive and fp is inclusive. */
/* When editing a secondary input buffer, these pointers are saved and re-created within the buffer gap */
/* Hamish's implementations forced the top part of the buffer out to file when the buffer was full (cf 'makespace()'); this isn't really an option in today's environment. Alternative choices are:
1) crash. (what we did, prior to 2.7) 2) fail to insert (what we do now) 3) expand the buffer (realloc, or malloc+free) - I don't like this because at some point you do run out of RAM or VM, and have to fail anyway. Since the most likely reason this is happening is a bad user command (eg (b0)0 ) rather than a file that is genuinely too large, I'd prefer to fail on the first instance of it going wrong. 4) use memory-mapped files (unix has them now too, very similar to what we had on EMAS) - but the argument against is just a delayed version of (3) above.
Note that the failure mode of this code is *not* atomic. A complete 'get line' or 'insert string' operation would fail in Hamish's implementation. Here it fails on the individual character level. I chose this model primarily to lower the cost of the buffer-full test. */
static cindex fbeg; static cindex lbeg; static cindex pp; static cindex fp; static cindex lend; static cindex fend;
static int type; static ecce_int command; static long repeat_count; static long limit; static int pointer; static int last_unit; static int this_unit; static int pos; static int endpos; static ecce_int sym; /************* sym has to be an int as it is tested against EOF ************/ static long number; static cindex pp_before; static cindex fp_before; static cindex ms; static cindex ms_back; static cindex ml; static cindex ml_back; static int to_upper_case; static int to_lower_case; static int caseflip; static bool blank_line; static char *eprompt; static cindex noted; static int changes; static bool in_second; static char *com_prompt;
static int symtype[256] = { ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ ext+termin, /*NL*/ err, /* */ ext+numb+7, /*!*/ delim, /*"*/ err, /*#*/ err, /*$*/ ext+1, /*%*/ err, /*&*/ delim, /*'*/ ext+2, /*(*/ ext+4, /*)*/ ext+numb+8, /***/ ext+5, /*+*/ ext+3, /*,*/ ext+6, /*-*/ delim, /*.*/ delim, /*slash*/ ext+numb+0, /*0*/ ext+numb+0, /*1*/ ext+numb+0, /*2*/ ext+numb+0, /*3*/ ext+numb+0, /*4*/ ext+numb+0, /*5*/ ext+numb+0, /*6*/ ext+numb+0, /*7*/ ext+numb+0, /*8*/ ext+numb+0, /*9*/ delim, /*:*/ ext+15, /*;*/ ext+2, /*<*/ delim, /*=*/ ext+4, /*>*/ 0, /*?*/ err, /*@*/ scope, /*A*/ sign+rep, /*B*/ sign+rep, /*C*/ sign+scope+txt+rep, /*D*/ sign+rep, /*E*/ sign+scope+txt+rep, /*F*/ sign+rep, /*G*/ scope, /*H*/ sign+txt+rep, /*I*/ sign+rep, /*J*/ sign+rep, /*K*/ sign+rep, /*L*/ sign+rep, /*M*/ 0, /*N*/ err, /*O*/ sign+rep, /*P*/ err, /*Q*/ sign+rep, /*R*/ sign+txt, /*S*/ sign+scope+txt+rep, /*T*/ sign+scope+txt+rep, /*U*/ sign+txt, /*V*/ err, /*W*/ err, /*X*/ err, /*Y*/ err, /*Z*/
ext+2, /*[*/ ]*/ ]ext+6, /*^*/delim, /*_*/ err, /*@*/ err, /*A*/ sign+rep, /*B*/ sign+rep, /*C*/ sign+scope+txt+rep, /*D*/ sign+rep, /*E*/ sign+scope+txt+rep, /*F*/ sign+rep, /*G*/ err, /*H*/ sign+txt+rep, /*I*/ sign+rep, /*J*/ sign+rep, /*K*/ sign+rep, /*L*/ sign+rep, /*M*/ err, /*N*/ err, /*O*/ sign+rep, /*P*/ err, /*Q*/ sign+rep, /*R*/ sign+txt, /*S*/ sign+scope+txt+rep, /*T*/ sign+scope+txt+rep, /*U*/ sign+txt, /*V*/ err, /*W*/ err, /*X*/ err, /*Y*/ err, /*Z*/ ext+2, /*[*/ ]*/ ext+6, /*^*/ delim /*_*/ /* May change some of these to delim at users discretion */ , err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err, err };
static int sym_type(ecce_char c) { if ((0 <= c) && (c <= 255)) return symtype[(unsigned]; return err; }
static cindex a; static FILE *main_in; static FILE *main_out; static FILE *tty_in; static FILE *tty_out; static FILE *log_out;
static ecce_int *com; static int *link; static ecce_char *text; static long *num; static long *lim;
/*****************************************************************************/
static int IntSeen = FALSE; /* set asynchronously by signal routine on ^C */
void gotint(int n) { (void)n; /* Supress the annoying 'not used' warning message... */ IntSeen = TRUE; }
int h(char c) { if (('0' <= c) && (c <= '9')) return c - '0'; if (('A' <= c) && (c <= 'F')) return c - 'A' + 10; if (('a' <= c) && (c <= 'f')) return c - 'a' + 10; fprintf(stderr, "%s: hex-command parámetro corrupto - char '%c' no es hex\n", ProgName, c); exit(1); }
char *hex_to_ascii(char *hex) { static char commandline[Max_parameter], *f, *t; if (strlen(hex)/2+3 >= Max_parameter) { fprintf(stderr, "%s: hex-command parámetro muy largo.\n", ProgName); exit(1); } f = hex; t = commandline; for (;;) { int c1,c2; if (*f == '\0') break; c1 = h(*f++); if (*f == '\0') { fprintf(stderr, "%s: hex-command parámetro corrupto. (nro. impar de caracteres)\n", ProgName); exit(1); } c2 = h(*f++); *t++ = c1<<4 | c2; } *t = '\0'; return commandline; }
char *backup_save;
int main(int argc, char **argv) { static char backup_save_buf[256+L_tmpnam+1]; /* L_tmpnam on Win/DOS (LCC32) doesn't include path */ int argno = 1, inoutlog = 0; char *s;
#ifdef WANT_UTF8 /* If your native locale doesn't use UTF-8 encoding * you need to replace the empty string with a * locale like "en_US.utf8" */ char *locale = setlocale(LC_ALL, ""); #endif
backup_save = tmpnam(backup_save_buf); /*SYS*/
/* Historical code, not really needed nowadays as people only use Windows and Unix variants :-( */
ProgName = argv[0]; s = strrchr(ProgName, '/'); if (s == NULL) s = strrchr(ProgName, '\\'); if (s == NULL) s = strrchr(ProgName, ':'); if (s == NULL) s = strrchr(ProgName, ']'); if (s == NULL) s = ProgName; else s = s+1; ProgName = malloc(strlen(s)+1); strcpy(ProgName, s); s = strchr(ProgName, '.'); if (s != NULL) *s = '\0';
/* decode argv into parameter[0..3] and buffer_size */ for (;;) { if (argno == argc) break; if ((argv[argno][0] == '-') && (argv[argno][1] != '\0')) { int offset = 1; if (argv[argno][1] == '-') offset += 1; if (strcmp(argv[argno]+offset, "desde") == 0) { parameter[F] = argv[argno+1]; } else if (strcmp(argv[argno]+offset, "a") == 0) { parameter[T] = argv[argno+1]; } else if (strcmp(argv[argno]+offset, "log") == 0) { parameter[L] = argv[argno+1]; } else if (strcmp(argv[argno]+offset, "hex-command") == 0) { if (parameter[C] != NULL) { fprintf(stderr, "%s: solo un -hex-command \"...\" o -comando \"...\" se permite\n", ProgName); exit(1); } parameter[C] = hex_to_ascii(argv[argno+1]); commandp = parameter[C]; } else if (strcmp(argv[argno]+offset, "command") == 0) { if (parameter[C] != NULL) { fprintf(stderr, "%s: only one -command \"...\" or -hex-command \"...\" is allowed\n", ProgName); exit(1); } parameter[C] = argv[argno+1]; commandp = parameter[C]; } else if (strcmp(argv[argno]+offset, "size") == 0) { char *buf_size_str, *endptr; buf_size_str = argv[argno+1]; errno = 0; buffer_size = strtoul(buf_size_str, &endptr, 10); if (errno != 0) { fprintf(stderr, "%s: parámetro de tamaño incorrecto '%s'\n", ProgName, buf_size_str); exit(1); } if ((*endptr != '\0') && (endptr[1] == '\0')) { /* memo: removed strcasecmp for portability. Also avoiding toupper etc for locale simplification */ if (*endptr == 'k' || *endptr == 'K') { buffer_size *= 1024UL; } else if (*endptr == 'm' || *endptr == 'M') { buffer_size *= (1024UL*1024UL); } else { fprintf(stderr, "%s: tipo incorrecto de unidad '%s' (se espera %luK o %luM)\n", ProgName, endptr, buffer_size, buffer_size); exit(1); } } } else { fprintf (stderr, "%s: Opción desconocida '%s'\n", ProgName, argv[argno]); exit(1); } if (argv[argno+1] == NULL) argno += 1; else argno += 2; } else { /* positional parameters */ parameter[inoutlog++] = argv[argno++]; } }
if (buffer_size == 0UL) buffer_size = estimate_buffer_size(parameter[F]); parameter[F] = argv[1];
if (parameter[F] == NULL) { fprintf (stderr,