Patch from Richard Boulton for large-file support. Works by using
[sgt/tweak] / main.c
diff --git a/main.c b/main.c
index 05df563..5e1dbfa 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1,15 +1,6 @@
 /*
- * TODO before releasable quality:
- * 
- *  - Thorough testing.
- * 
- *  - Half decent build system.
- * 
  * TODO possibly after that:
  * 
- *  - Need to handle >2Gb files! Up the `filesize' type to long
- *    long and use it everywhere.
- *
  *  - Multiple buffers, multiple on-screen windows.
  *     + ^X^F to open new file
  *     + ^X^R to open new file RO
  *      rather than the current rather crap one; in particular
  *      this enables pasting into the search string.
  *     + er, how exactly do we deal with the problem of saving over
- *      a file which we're maintaining references to?
+ *      a file which we're maintaining references to in another
+ *      buffer? The _current_ buffer can at least be sorted out by
+ *      replacing it with a fresh tree containing a single
+ *      file-data block, but other buffers are in trouble.
+ *       * if we can rely on Unix fd semantics, this isn't too
+ *         bad; we can just keep the fd open on the original file,
+ *         and then the data stays around even after we rename(2)
+ *         our new version over the top. Disk space usage gets
+ *         silly after a few iterations, but it's better than
+ *         nothing.
  * 
  *  - Undo!
  *     + this actually doesn't seem _too_ horrid. For a start, one
  *      buf_delete_data (both must be cloned for an overwrite),
  *      but I'm not convinced that simply cloning the entire thing
  *      isn't a superior option.
- * 
- *  - Reverse search.
- *     + need to construct a reverse DFA.
- *     + probably should construct both every time, so that you can
- *      search forward for a thing and then immediately change
- *      your mind and search backward for the same thing.
+ *     + this really starts to show up the distinction between a
+ *      `buffer' and a bare tree. A buffer is something which has
+ *      an undo chain attached; so, in particular, the cut buffer
+ *      shouldn't be one. Sort that out.
  * 
  *  - In-place editing.
  *     + this is an extra option when running in Fix mode. It
@@ -52,7 +50,9 @@
  *      one, we simply seek within the original file and write out
  *      all the pieces that have changed.
  *     + Primarily useful for editing disk devices directly
- *      (yikes!).
+ *      (yikes!), or other situations where you actually cannot
+ *      create a fresh copy of the file and rename(2) it into
+ *      place.
  *     + I had intended to suggest that in Fix mode this would be
  *      nice and easy, since every element of the buffer tree is
  *      either a literal block (needs writing) or a from-file
@@ -74,6 +74,8 @@
  *         _and_ when pasting a cut buffer _into_ one.
  */
 
+#include "tweak.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -89,8 +91,6 @@
 #include <process.h>
 #endif
 
-#include "tweak.h"
-
 static void init(void);
 static void done(void);
 static void load_file (char *);
@@ -100,8 +100,8 @@ char hex[256][3];                  /* LUT: binary to hex, 1 byte */
 
 char message[80];
 
-char decstatus[] = "%s TWEAK "VER": %-18.18s %s posn=%-10d size=%-10d";
-char hexstatus[] = "%s TWEAK "VER": %-18.18s %s posn=0x%-8X size=0x%-8X";
+char decstatus[] = "%s TWEAK "VER": %-18.18s %s posn=%-10"OFF"d size=%-10"OFF"d";
+char hexstatus[] = "%s TWEAK "VER": %-18.18s %s posn=0x%-8"OFF"X size=0x%-8"OFF"X";
 char *statfmt = hexstatus;
 
 char last_char;
@@ -118,12 +118,12 @@ int marking = FALSE;
 int modified = FALSE;
 int new_file = FALSE;                 /* shouldn't need initialisation -
                                        * but let's not take chances :-) */
-int width = 16;
-int realoffset = 0, offset = 16;
+fileoffset_t width = 16;
+fileoffset_t realoffset = 0, offset = 16;
 
 int ascii_enabled = TRUE;
 
-long file_size = 0, top_pos = 0, cur_pos = 0, mark_point = 0;
+fileoffset_t file_size = 0, top_pos = 0, cur_pos = 0, mark_point = 0;
 
 int scrlines;
 
@@ -131,7 +131,7 @@ int scrlines;
  * Main program
  */
 int main(int argc, char **argv) {
-    int newoffset = -1, newwidth = -1;
+    fileoffset_t newoffset = -1, newwidth = -1;
 
     /*
      * Parse command line arguments
@@ -167,10 +167,10 @@ int main(int argc, char **argv) {
                }
                switch (c) {
                  case 'o': case 'O':
-                   newoffset = strtol(value, NULL, 0);   /* allow `0xXX' */
+                   newoffset = parse_num(value, NULL);
                    break;
                  case 'w': case 'W':
-                   newwidth = strtol(value, NULL, 0);
+                   newwidth = parse_num(value, NULL);
                    break;
                }
                break;
@@ -226,7 +226,7 @@ int main(int argc, char **argv) {
 void fix_offset(void) {
     if (3*width+11 > display_cols) {
        width = (display_cols-11) / 3;
-       sprintf (message, "Width reduced to %d to fit on the screen", width);
+       sprintf (message, "Width reduced to %"OFF"d to fit on the screen", width);
     }
     if (4*width+14 > display_cols) {
        ascii_enabled = FALSE;
@@ -248,11 +248,11 @@ static void init(void) {
 
     display_setup();
 
-    display_define_colour(COL_BUFFER, 7, 0);
-    display_define_colour(COL_SELECT, 0, 7);
-    display_define_colour(COL_STATUS, 11, 4);
-    display_define_colour(COL_ESCAPE, 9, 0);
-    display_define_colour(COL_INVALID, 11, 0);
+    display_define_colour(COL_BUFFER, -1, -1, FALSE);
+    display_define_colour(COL_SELECT, 0, 7, TRUE);
+    display_define_colour(COL_STATUS, 11, 4, TRUE);
+    display_define_colour(COL_ESCAPE, 9, 0, FALSE);
+    display_define_colour(COL_INVALID, 11, 0, FALSE);
 
     for (i=0; i<256; i++) {
        sprintf(hex[i], "%02X", i);
@@ -276,7 +276,7 @@ static void load_file (char *fname) {
     file_size = 0;
     if ( (fp = fopen (fname, "rb")) ) {
        if (eager_mode) {
-           long len;
+           size_t len;
            static char buffer[4096];
 
            filedata = buf_new_empty();
@@ -292,12 +292,12 @@ static void load_file (char *fname) {
            }
            fclose (fp);
            assert(file_size == buf_length(filedata));
-           sprintf(message, "loaded %s (size %ld == 0x%lX).",
+           sprintf(message, "loaded %s (size %"OFF"d == 0x%"OFF"X).",
                    fname, file_size, file_size);
        } else {
            filedata = buf_new_from_file(fp);
            file_size = buf_length(filedata);
-           sprintf(message, "opened %s (size %ld == 0x%lX).",
+           sprintf(message, "opened %s (size %"OFF"d == 0x%"OFF"X).",
                    fname, file_size, file_size);
        }
        new_file = FALSE;
@@ -318,7 +318,7 @@ static void load_file (char *fname) {
  */
 int save_file (void) {
     FILE *fp;
-    long pos = 0;
+    fileoffset_t pos = 0;
 
     if (look_mode)
        return FALSE;                  /* do nothing! */
@@ -327,7 +327,7 @@ int save_file (void) {
        static char buffer[SAVE_BLKSIZ];
 
        while (pos < file_size) {
-           long size = file_size - pos;
+           fileoffset_t size = file_size - pos;
            if (size > SAVE_BLKSIZ)
                size = SAVE_BLKSIZ;
 
@@ -384,8 +384,9 @@ static int scrbuflines = 0;
  */
 void draw_scr (void) {
     int scrsize, scroff, llen, i, j;
-    long currpos;
-    int marktop, markbot, mark;
+    fileoffset_t currpos;
+    fileoffset_t marktop, markbot;
+    int mark;
     char *p;
     unsigned char c, *q;
     char *linebuf;
@@ -473,9 +474,10 @@ void draw_scr (void) {
                 * requiring highlighting: a hex bit and an ascii
                 * bit.
                 */
-               int localstart= (currpos<marktop?marktop:currpos) - currpos;
-               int localstop = (currpos+llen>markbot ? markbot :
-                                currpos+llen) - currpos;
+               fileoffset_t localstart= (currpos<marktop ? marktop :
+                                          currpos) - currpos;
+               fileoffset_t localstop = (currpos+llen>markbot ? markbot :
+                                          currpos+llen) - currpos;
                localstart += width-llen;
                localstop += width-llen;
                display_write_chars(linebuf, 11+3*localstart);
@@ -496,9 +498,11 @@ void draw_scr (void) {
                    display_write_chars(linebuf+10+3*localstop,
                                       2+3*width-3*localstop);
                }
-           } else
+           } else {
+                display_set_colour(COL_BUFFER);
                display_write_chars(linebuf,
                                   ascii_enabled ? 13+4*width : 10+3*width);
+            }
        }
        currpos += (currpos ? width : offset);
        display_clear_to_eol();
@@ -541,6 +545,9 @@ void draw_scr (void) {
     display_refresh ();
 }
 
+volatile int safe_update, update_required;
+void update (void);
+
 /*
  * Get a string, in the "minibuffer". Return TRUE on success, FALSE
  * on break. Possibly syntax-highlight the entered string for
@@ -563,9 +570,9 @@ int get_str (char *prompt, char *buf, int highlight) {
                    p++;
                    if (p<r && *p == '\\')
                        p++, display_set_colour(COL_ESCAPE);
-                   else if (p>=r || !isxdigit (*p))
+                   else if (p>=r || !isxdigit ((unsigned char)*p))
                        display_set_colour(COL_INVALID);
-                   else if (p+1>=r || !isxdigit (p[1]))
+                   else if (p+1>=r || !isxdigit ((unsigned char)p[1]))
                        p++, display_set_colour(COL_INVALID);
                    else
                        p+=2, display_set_colour(COL_ESCAPE);
@@ -633,7 +640,8 @@ int parse_quoted (char *buffer) {
            p++;
            if (*p == '\\')
                *q++ = *p++;
-           else if (p[1] && isxdigit(*p) && isxdigit(p[1])) {
+           else if (p[1] && isxdigit((unsigned char)*p) &&
+                    isxdigit((unsigned char)p[1])) {
                char buf[3];
                buf[0] = *p++;
                buf[1] = *p++;
@@ -664,8 +672,6 @@ void suspend(void) {
 #endif
 }
 
-volatile int safe_update, update_required;
-
 void update (void) {
     display_recheck_size();
     fix_offset ();
@@ -679,18 +685,18 @@ void schedule_update(void) {
        update_required = TRUE;
 }
 
-long parse_num (char *buffer, int *error) {
+fileoffset_t parse_num (char *buffer, int *error) {
     if (error)
        *error = FALSE;
     if (!buffer[strspn(buffer, "0123456789")]) {
        /* interpret as decimal */
-       return atoi(buffer);
+       return ATOOFF(buffer);
     } else if (buffer[0]=='0' && (buffer[1]=='X' || buffer[1]=='x') &&
               !buffer[2+strspn(buffer+2,"0123456789ABCDEFabcdef")]) {
-       return strtol(buffer+2, NULL, 16);
+       return STRTOOFF(buffer+2, NULL, 16);
     } else if (buffer[0]=='$' &&
               !buffer[1+strspn(buffer+1,"0123456789ABCDEFabcdef")]) {
-       return strtol(buffer+1, NULL, 16);
+       return STRTOOFF(buffer+1, NULL, 16);
     } else {
        return 0;
        if (error)