ecce.c - ubuntuperonista/wiki_tp GitHub Wiki

<file></file>

  1. define VERSION "V2.10b" /* %V */
static const char *RCS_Version = "$Revision: 1.4 $"; /* only relevant to my home linux /usr/local/src/ecce */
  1. define DATE "$Date: 2021/11/30 03:55:52 $"
  2. include <stdio.h></stdio.h>
  3. include <string.h></string.h>
  4. include <stdlib.h></stdlib.h>
  5. include <ctype.h></ctype.h>
  6. include <signal.h></signal.h>
  7. include <errno.h></errno.h>
  8. ifdef WANT_UTF8
/* EXPERIMENTAL SUPPORT FOR UTF-8 - been tested for a few years now, seems robust enough to make default. */
  1. include <wchar.h></wchar.h>
  2. include <locale.h></locale.h>
typedef wint_t ecce_int; typedef wchar_t ecce_char;
  1. else
typedef int ecce_int; typedef char ecce_char;
  1. define fputwc(x,f) fputc(x,f)
  2. define fgetwc(f) fgetc(f)
  3. define WEOF EOF
  4. endif
/**************************************************/ /* */ /* */ /* E C C E */ /* */ /* */ /* ECCE fue diseñado por Hamish Dewar, ahora */ /* retirado. Esta implementación es de Graham */ /* Toal, del Proyecto de Historia del Cómputo */ /* de Edimburgo. */ /* */ /* Este código fuente fue lanzado al dominio */ /* público por su autor, sin restricciones */ /* */ /* (c) Graham Toal, 1984. (Original BCPL version, */ /* translated into C in 1992). */ /**************************************************/

/**************************************************************************/

  1. define NOTE_FILE "/tmp/Note0" /* Specific to Linux - unfortunately, /tmp is shared by other users */
/* so this version of Ecce is really only expected to be used on a single-user system */

/* #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.

  • /
/* Name of temp file for multiple contexts - system dependant. */ /* Something like "/tmp/Note%c" would be a small improvement, */ /* but using a proper function like tmpnam() would be best. */

/* 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. */

  1. define CONTEXT_OFFSET (strlen(NOTE_FILE)-1)
/* Index of variable part in name above (i.e. of '0') */

static char *ProgName = NULL; static char *parameter[4] = {NULL, NULL, NULL, NULL}; /* parameters - from, to, log, command */ static char *commandp = NULL;

  1. define F 0 /* FROM */
  2. define T 1 /* TO */
  3. define L 2 /* LOG */
  4. define C 3 /* COMMAND */
unsigned long estimate_buffer_size(char *fname) { FILE *tmp = fopen(fname, "rw"); unsigned long maxbuf = 0UL; long rc;

/* 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; }

/**************************************************************************/

  1. define FALSE (0!=0)
  2. define TRUE (0==0)
/* Types */

typedef int bool; typedef ecce_char *cindex;

/* Consts */

  1. define bs 8
  2. define bell 7
  3. define nul 0
  4. define del 127
/* The casebit logic only works on 8-bit characters. Will need to rewrite case handling if/when we move to UTF 32-bit encoding */
  1. define casebit ('a'-'A')
  2. define minusbit casebit
  3. define plusbit 0x80
/* I know it is bad practise to have these fixed length arrays and I will work on that eventually. I increased the size of these considerably when I modified Ecce to accept a command string as a parameter, because scripts were starting to need quite long command strings that were exceeding the inital bounds of 127 chars. Again, we're assuming a non-hostile single-user environment. */
  1. define Max_command_units 4095
  2. define Max_parameter 4095
  3. define Max_prompt_length 4095
  4. define rep 1
  5. define txt 2
  6. define scope 4
  7. define sign 8
  8. define delim 16
  9. define numb 32
  10. define ext 64
  11. define err 128
  12. define dig 0
  13. define pc 1
  14. define lpar 2
  15. define comma 3
  16. define rpar 4
  17. define plus 5
  18. define minus 6
  19. define pling 7
  20. define star 8
  21. define termin 15
void init_globals (void); void free_buffers (void); void local_echo (ecce_int *sym); /* Later, make this a char fn. */ void read_sym (void); bool fail_with (char *mess, ecce_int culprit); void percent (ecce_int Command_sym); void unchain(void); void stack(void); void execute_command(void); void Scan_sign(void); /* Could be a macro */ void Scan_scope(void); /* ditto macro */ void Scan_text(void); void Scan_repeat (void); bool analyse (void); void load_file (void); bool execute_unit (void); void execute_all (void); ecce_int case_op (ecce_int sym); /* should be made a macro */ bool right (void); bool left (void); void right_star(void); /* Another macro */ void left_star(void); /* Likewise... */ void move (void); void move_back(void); void move_star (void); void move_back_star (void); void insert (void); void insert_back (void); bool verify(void); bool verify_back (void); bool find (void); bool find_back (void);

/* 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,

⚠️ **GitHub.com Fallback** ⚠️