New server
authorRobert Pengelly <robertapengelly@hotmail.com>
Mon, 3 Jun 2024 03:36:56 +0000 (04:36 +0100)
committerRobert Pengelly <robertapengelly@hotmail.com>
Mon, 3 Jun 2024 03:36:56 +0000 (04:36 +0100)
26 files changed:
LICENSE [new file with mode: 0644]
Makefile.pdw [new file with mode: 0644]
Makefile.s64 [new file with mode: 0644]
Makefile.std [new file with mode: 0644]
Makefile.unix [new file with mode: 0644]
Makefile.vsc [new file with mode: 0644]
Makefile.w32 [new file with mode: 0644]
Makefile.wcd [new file with mode: 0644]
README.md [new file with mode: 0644]
append.c [new file with mode: 0644]
ar.c [new file with mode: 0644]
ar.h [new file with mode: 0644]
conv.c [new file with mode: 0644]
delete.c [new file with mode: 0644]
display.c [new file with mode: 0644]
extract.c [new file with mode: 0644]
lib.c [new file with mode: 0644]
lib.h [new file with mode: 0644]
makefile.slp [new file with mode: 0644]
makefile.sos [new file with mode: 0644]
makefile.std [new file with mode: 0644]
ranlib.c [new file with mode: 0644]
replace.c [new file with mode: 0644]
report.c [new file with mode: 0644]
report.h [new file with mode: 0644]
stdint.h [new file with mode: 0644]

diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..fdddb29
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <https://unlicense.org>
diff --git a/Makefile.pdw b/Makefile.pdw
new file mode 100644 (file)
index 0000000..6dbb921
--- /dev/null
@@ -0,0 +1,22 @@
+#******************************************************************************
+# @file             Makefile.pdw
+#******************************************************************************
+AS=aswin
+CC=gccwin
+LD=ldwin
+
+COPTS=-S -O2 -fno-common -ansi -I. -I../pdos/pdpclib -D__WIN32__ -D__NOBIVA__ -D__PDOS__
+COBJ=append.o ar.o conv.o delete.o display.o extract.o lib.o ranlib.o replace.o report.o
+
+all: clean xar.exe
+
+xar.exe: $(COBJ)
+  $(LD) -s -o xar.exe ../pdos/pdpclib/w32start.o $(COBJ) ../pdos/pdpclib/msvcrt.a
+
+.c.o:
+  $(CC) $(COPTS) $<
+  $(AS) -o $@ $*.s
+  rm -f $*.s
+
+clean:
+  rm -f *.o xar.exe
diff --git a/Makefile.s64 b/Makefile.s64
new file mode 100644 (file)
index 0000000..0ccc969
--- /dev/null
@@ -0,0 +1,24 @@
+CPP=pdcc
+CC=cc64
+CFLAGS=
+LD=pdld
+LDFLAGS=-s -nostdlib --no-insert-timestamp --image-base 0x400000
+AS=pdas --oformat coff --64
+COPTS=-I. -I../pdos/pdpclib -D__WIN32__ -D__NOBIVA__ -D__64BIT__ -D__CC64__
+
+OBJS=append.obj ar.obj conv.obj delete.obj display.obj extract.obj lib.obj ranlib.obj replace.obj report.obj
+
+TARGET=xar.exe
+
+all: clean $(TARGET)
+
+$(TARGET): $(OBJS)
+  $(LD) $(LDFLAGS) -o $(TARGET) ../pdos/pdpclib/w32start.obj $(OBJS) ../pdos/pdpclib/msvcrt.lib
+
+.c.obj:
+  $(CPP) -E $(COPTS) -o $*.i $<
+  $(CC) -c -out:$@ $*.i
+  rm -f $*.i
+
+clean:
+  rm -f $(OBJS) $(TARGET)
diff --git a/Makefile.std b/Makefile.std
new file mode 100644 (file)
index 0000000..a7f73c5
--- /dev/null
@@ -0,0 +1,19 @@
+AS=pdas --oformat coff
+CC=gccwin
+LD=pdld
+
+COPTS=-S -O2 -fno-common -ansi -I. -I../pdos/pdpclib -D__WIN32__ -D__NOBIVA__ -D__PDOS__
+COBJ=append.o ar.o conv.o delete.o display.o extract.o lib.o ranlib.o replace.o report.o
+
+all: clean xar.exe
+
+xar.exe: $(COBJ)
+  $(LD) -s -nostdlib --no-insert-timestamp -o xar.exe ../pdos/pdpclib/w32start.o $(COBJ) ../pdos/pdpclib/msvcrt.a
+
+.c.o:
+  $(CC) $(COPTS) $<
+  $(AS) -o $@ $*.s
+  rm -f $*.s
+
+clean:
+  rm -f *.o xar.exe
diff --git a/Makefile.unix b/Makefile.unix
new file mode 100644 (file)
index 0000000..f4f5b54
--- /dev/null
@@ -0,0 +1,30 @@
+#******************************************************************************
+# @file             Makefile.unix
+#******************************************************************************
+SRCDIR              ?=  $(CURDIR)
+VPATH               :=  $(SRCDIR)
+
+CC                  :=  gcc
+CFLAGS              :=  -D_FILE_OFFSET_BITS=64 -O2 -Wall -Werror -Wextra -ansi -pedantic -std=c90
+
+ifneq ($(shell uname -s),Darwin)
+CFLAGS += -m32
+endif
+
+CSRC                :=  append.c ar.c conv.c delete.c display.c extract.c lib.c ranlib.c replace.c report.c
+
+ifeq ($(OS), Windows_NT)
+all: xar.exe
+
+xar.exe: $(CSRC)
+       $(CC) $(CFLAGS) -o $@ $^
+else
+all: xar
+
+xar: $(CSRC)
+       $(CC) $(CFLAGS) -o $@ $^
+endif
+
+clean:
+       if [ -f xar.exe ]; then rm -rf xar.exe; fi
+       if [ -f xar ]; then rm -rf xar; fi
diff --git a/Makefile.vsc b/Makefile.vsc
new file mode 100644 (file)
index 0000000..b9fe4d6
--- /dev/null
@@ -0,0 +1,17 @@
+CC=cl
+LD=cl
+
+COPTS=-c -nologo -O2 -I.
+COBJ=append.obj ar.obj conv.obj delete.obj display.obj \
+  extract.obj lib.obj ranlib.obj replace.obj report.obj
+
+all: clean xar.exe
+
+xar.exe: $(COBJ)
+  $(LD) -nologo -Fexar.exe $(COBJ)
+
+.c.obj:
+  $(CC) $(COPTS) -Fo$@ $<
+
+clean:
+  rm -f *.obj xar.exe
diff --git a/Makefile.w32 b/Makefile.w32
new file mode 100644 (file)
index 0000000..ad0e650
--- /dev/null
@@ -0,0 +1,19 @@
+#******************************************************************************
+# @file             Makefile.w32
+#******************************************************************************
+SRCDIR              ?=  $(CURDIR)
+VPATH               :=  $(SRCDIR)
+
+CC                  :=  gcc
+CFLAGS              :=  -D_FILE_OFFSET_BITS=64 -O2 -Wall -Werror -Wextra -ansi -m32 -pedantic -std=c90
+
+CSRC                :=  append.c ar.c conv.c delete.c display.c extract.c lib.c ranlib.c replace.c report.c
+
+all: xar.exe
+
+clean:
+       if exist xar.exe ( del /q xar.exe )
+       if exist xar ( del /q xar )
+
+xar.exe: $(CSRC)
+       $(CC) $(CFLAGS) -o $@ $^
diff --git a/Makefile.wcd b/Makefile.wcd
new file mode 100644 (file)
index 0000000..8d1c0ca
--- /dev/null
@@ -0,0 +1,21 @@
+#******************************************************************************
+# @file             Makefile.wcd
+# 
+# Produce MSDOS executables links with PDPCLIB created by makefile.wcd
+#******************************************************************************
+CC=wcl
+COPTS=-ecc -q -w -c -ml -zl -D__MSDOS__ -D__PDOS__ -fpi87 -s -zdp -zu -I. -I..\pdos\pdpclib
+
+all: clean xar.exe
+
+xar.exe: append.obj ar.obj conv.obj delete.obj display.obj extract.obj lib.obj ranlib,obj replace.obj report.obj
+  wlink File ar.obj Name xar.exe Form dos Library temp.lib,..\pdos\pdpclib\watcom.lib Option quiet,map
+
+.c.obj:
+  $(CC) $(COPTS) $<
+  wlib -b -q temp +$*.obj
+
+clean:
+  rm -f *.obj
+  rm -f xar.exe
+  rm -f temp.lib
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..9433d5b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,23 @@
+All source code is Public Domain.
+
+## Obtain the source code
+
+    git clone https://git.candlhat.org/xar.git
+
+## Building
+
+    BSD:
+    
+        Make sure you have gcc and gmake installed then run gmake -f Makefile.unix.
+    
+    Linux:
+    
+        Make sure you have gcc and make installed then run make -f Makefile.unix.
+    
+    macOS:
+    
+        Make sure you have xcode command line tools installed then run make -f Makefile.unix.
+    
+    Windows:
+    
+        Make sure you have mingw installed and the location within your PATH variable then run mingw32-make.exe -f Makefile.w32.
diff --git a/append.c b/append.c
new file mode 100644 (file)
index 0000000..bab69e9
--- /dev/null
+++ b/append.c
@@ -0,0 +1,153 @@
+/******************************************************************************
+ * @file            append.c
+ *****************************************************************************/
+#include    <stdio.h>
+#include    <stdlib.h>
+#include    <string.h>
+
+#include    "ar.h"
+#include    "lib.h"
+#include    "report.h"
+
+void append (FILE *ofp, char *fname) {
+
+    unsigned char aout_magic[2];
+    FILE *tfp;
+    
+    struct ar_header header;
+    char temp[17];
+    
+    char *p, *name = fname, *contents;
+    long bytes, len, read;
+    
+    int need_newline = 0;
+    int valid = 0;
+    
+    if ((tfp = fopen (fname, "r+b")) == NULL) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "failed to open %s", fname);
+        return;
+    
+    }
+    
+    if (fread (aout_magic, 2, 1, tfp) != 1) {
+    
+        fclose (tfp);
+        
+        report_at (program_name, 0, REPORT_ERROR, "failed whilst reading %s", fname);
+        return;
+    
+    }
+    
+    valid = ((aout_magic[0] == 0x07 && aout_magic[1] == 0x01) || (aout_magic[0] == 0x4C && aout_magic[1] == 0x01) || (aout_magic[0] == 0x64 && aout_magic[1] == 0x86));
+    
+    if (!valid) {
+    
+        fclose (tfp);
+        
+        report_at (program_name, 0, REPORT_ERROR, "%s is not a valid a.out or coff object", fname);
+        return;
+    
+    }
+    
+    memset (temp, 0x20, 16);
+    temp[0] = '0';
+    
+    if ((p = strrchr (fname, '/'))) {
+        name = (p + 1);
+    }
+    
+    len = strlen (name);
+    
+    if (len > 16) {
+        len = 16;
+    }
+    
+    memcpy (header.name, name, len);
+    
+    while (len < 16) {
+        header.name[len++] = 0x20;
+    }
+    
+    memcpy (header.mtime, temp, 12);
+    memcpy (header.owner, temp, 6);
+    memcpy (header.group, temp, 6);
+    memcpy (header.mode, temp, 8);
+    
+    fseek (tfp, 0, SEEK_END);
+    bytes = ftell (tfp);
+    
+    len = sprintf (temp, "%ld", bytes);
+    temp[len] = 0x20;
+    
+    memcpy (header.size, temp, 10);
+    
+    header.endsig[0] = 0x60;
+    header.endsig[1] = 0x0A;
+    
+    need_newline = (bytes % 2);
+    
+    if (fwrite (&header, sizeof (header), 1, ofp) != 1) {
+    
+        fclose (tfp);
+        
+        report_at (program_name, 0, REPORT_ERROR, "failed whilst writing header");
+        return;
+    
+    }
+    
+    contents = xmalloc (512);
+    fseek (tfp, 0, SEEK_SET);
+    
+    for (;;) {
+    
+        if (bytes == 0 || feof (tfp)) {
+            break;
+        } else if (bytes >= 512) {
+            read = 512;
+        } else {
+            read = bytes;
+        }
+        
+        if (fread (contents, read, 1, tfp) != 1) {
+            
+            free (contents);
+            fclose (tfp);
+            
+            report_at (program_name, 0, REPORT_ERROR, "failed whilst reading %s", fname);
+            return;
+        
+        }
+        
+        bytes -= read;
+        
+        if (fwrite (contents, read, 1, ofp) != 1) {
+        
+            free (contents);
+            fclose (tfp);
+            
+            report_at (program_name, 0, REPORT_ERROR, "failed whilst writing %s to archive", fname);
+            return;
+        
+        }
+    
+    }
+    
+    free (contents);
+    
+    if (need_newline) {
+    
+        temp[0] = 0x0A;
+        
+        if (fwrite (temp, 1, 1, ofp) != 1) {
+        
+            fclose (tfp);
+            exit (EXIT_FAILURE);
+        
+        }
+    
+    }
+    
+    fclose (tfp);
+
+}
diff --git a/ar.c b/ar.c
new file mode 100644 (file)
index 0000000..65b823e
--- /dev/null
+++ b/ar.c
@@ -0,0 +1,129 @@
+/******************************************************************************
+ * @file            ar.c
+ *****************************************************************************/
+#include    <stdio.h>
+#include    <stdlib.h>
+#include    <string.h>
+
+#include    "ar.h"
+#include    "lib.h"
+#include    "report.h"
+#include    "stdint.h"
+
+struct ar_state *state = 0;
+const char *program_name = 0;
+
+FILE *arfp = NULL;
+
+int main (int argc, char **argv) {
+
+    char ar_magic[8];
+    long i;
+    
+    if (argc && *argv) {
+    
+        char *p;
+        program_name = *argv;
+        
+        if ((p = strrchr (program_name, '/'))) {
+            program_name = (p + 1);
+        }
+    
+    }
+    
+    state = xmalloc (sizeof (*state));
+    parse_args (&argc, &argv, 1);
+    
+    if (state->append || state->replace) {
+    
+        if ((arfp = fopen (state->outfile, "r+b")) == NULL) {
+        
+            if ((arfp = fopen (state->outfile, "w+b")) == NULL) {
+            
+                report_at (program_name, 0, REPORT_ERROR, "failed to create %s", state->outfile);
+                return EXIT_FAILURE;
+            
+            }
+            
+            if (fwrite ("!<arch>\n", 8, 1, arfp) != 1) {
+            
+                fclose (arfp);
+                
+                report_at (program_name, 0, REPORT_ERROR, "failed whilst writing to %s", state->outfile);
+                return EXIT_FAILURE;
+            
+            }
+        
+        }
+        
+        fclose (arfp);
+    
+    }
+    
+    if ((arfp = fopen (state->outfile, "r+b")) == NULL) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "failed to open %s", state->outfile);
+        return EXIT_FAILURE;
+    
+    }
+    
+    if (fread (ar_magic, 8, 1, arfp) != 1) {
+    
+        fclose (arfp);
+        
+        report_at (program_name, 0, REPORT_ERROR, "failed whilst reading %s", state->outfile);
+        return EXIT_FAILURE;
+    
+    }
+    
+    if (memcmp ("!<arch>\n", ar_magic, 8)) {
+    
+        fclose (arfp);
+        
+        report_at (program_name, 0, REPORT_ERROR, "%s is not a valid archive file", state->outfile);
+        return EXIT_FAILURE;
+    
+    }
+    
+    for (i = 0; i < state->nb_files; ++i) {
+    
+        if (state->append) {
+        
+            fseek (arfp, 0, SEEK_END);
+            append (arfp, state->files[i]);
+        
+        } else if (state->replace) {
+        
+            fseek (arfp, 8, SEEK_SET);
+            replace (state->files[i]);
+        
+        } else if (state->del) {
+        
+            fseek (arfp, 8, SEEK_SET);
+            delete (state->files[i]);
+        
+        } else if (state->extract) {
+        
+            fseek (arfp, 8, SEEK_SET);
+            extract (state->files[0]);
+        
+        }
+    
+    }
+    
+    if (state->display) {
+    
+        fseek (arfp, 8, SEEK_SET);
+        display ();
+    
+    } else if (state->ranlib) {
+    
+        fseek (arfp, 8, SEEK_SET);
+        ranlib ();
+    
+    }
+    
+    fclose (arfp);
+    return EXIT_SUCCESS;
+
+}
diff --git a/ar.h b/ar.h
new file mode 100644 (file)
index 0000000..2831f3b
--- /dev/null
+++ b/ar.h
@@ -0,0 +1,49 @@
+/******************************************************************************
+ * @file            ar.h
+ *****************************************************************************/
+#ifndef     _AR_H
+#define     _AR_H
+
+struct ar_state {
+
+    char **files;
+    long nb_files;
+    
+    const char *outfile;
+    
+    int del, move, print;
+    int append, replace, ranlib;
+    int display, extract;
+
+};
+
+extern struct ar_state *state;
+extern const char *program_name;
+
+struct ar_header {
+
+    char name[16];
+    char mtime[12];
+    char owner[6];
+    char group[6];
+    char mode[8];
+    char size[10];
+    char endsig[2];
+
+};
+
+#include    <stdio.h>
+
+#include    "stdint.h"
+
+extern FILE *arfp;
+uint32_t conv_dec (char *str, int32_t max);
+
+void append  (FILE *ofp, char *fname);
+void delete  (char *fname);
+void display (void);
+void extract (char *fname);
+void ranlib  (void);
+void replace (char *fname);
+
+#endif      /* _AR_H */
diff --git a/conv.c b/conv.c
new file mode 100644 (file)
index 0000000..f8267ab
--- /dev/null
+++ b/conv.c
@@ -0,0 +1,19 @@
+/******************************************************************************
+ * @file            conv.c
+ *****************************************************************************/
+#include    "stdint.h"
+
+uint32_t conv_dec (char *str, int32_t max) {
+
+    uint32_t value = 0;
+    
+    while (*str != ' ' && max-- > 0) {
+    
+        value *= 10;
+        value += *str++ - '0';
+    
+    }
+    
+    return value;
+
+}
diff --git a/delete.c b/delete.c
new file mode 100644 (file)
index 0000000..e190ce0
--- /dev/null
+++ b/delete.c
@@ -0,0 +1,182 @@
+/******************************************************************************
+ * @file            delete.c
+ *****************************************************************************/
+#include    <stdio.h>
+#include    <stdlib.h>
+#include    <string.h>
+
+#include    "ar.h"
+#include    "lib.h"
+#include    "report.h"
+
+void delete (char *fname) {
+
+    FILE *tfp = tmpfile ();
+    
+    char temp[17], *name, *p, *contents;
+    long bytes, len, read;
+    
+    if (fwrite ("!<arch>\x0A", 8, 1, tfp) != 1) {
+    
+        fclose (tfp);
+        
+        report_at (program_name, 0, REPORT_ERROR, "failed whist writing ar header");
+        return;
+    
+    }
+    
+    name = fname;
+    
+    if ((p = strrchr (fname, '/'))) {
+        name = (p + 1);
+    }
+    
+    len = strlen (name);
+    
+    if (len > 16) {
+        len = 16;
+    }
+    
+    memcpy (temp, name, len);
+    temp[len] = '\0';
+    
+    for (;;) {
+    
+        struct ar_header hdr;
+        
+        if (fread (&hdr, sizeof (hdr), 1, arfp) != 1) {
+        
+            if (feof (arfp)) {
+                break;
+            }
+            
+            report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", state->outfile);
+            return;
+        
+        }
+        
+        bytes = conv_dec (hdr.size, 10);
+        
+        if (bytes % 2) {
+            bytes++;
+        }
+        
+        if (memcmp (hdr.name, "/", 1) == 0) {
+        
+            fseek (arfp, bytes, SEEK_CUR);
+            continue;
+        
+        }
+        
+        if (memcmp (hdr.name, temp, len) == 0) {
+        
+            fseek (arfp, bytes, SEEK_CUR);
+            continue;
+        
+        }
+        
+        if (fwrite (&hdr, sizeof (hdr), 1, tfp) != 1) {
+        
+            fclose (tfp);
+            
+            report_at (program_name, 0, REPORT_ERROR, "failed whilst writing header");
+            exit (EXIT_FAILURE);
+        
+        }
+        
+        contents = xmalloc (512);
+        
+        for (;;) {
+        
+            if (bytes == 0 || feof (arfp)) {
+                break;
+            } else if (bytes >= 512) {
+                read = 512;
+            } else {
+                read = bytes;
+            }
+            
+            if (fread (contents, read, 1, arfp) != 1) {
+            
+                free (contents);
+                fclose (tfp);
+                
+                report_at (NULL, 0, REPORT_ERROR, "failed to read %ld bytes from %s", bytes, state->outfile);
+                exit (EXIT_FAILURE);
+            
+            }
+            
+            bytes -= read;
+            
+            if (fwrite (contents, read, 1, tfp) != 1) {
+            
+                free (contents);
+                fclose (tfp);
+                
+                report_at (NULL, 0, REPORT_ERROR, "failed to write temp file");
+                exit (EXIT_FAILURE);
+            
+            }
+        
+        }
+        
+        free (contents);
+    
+    }
+    
+    fclose (arfp);
+    remove (state->outfile);
+    
+    if ((arfp = fopen (state->outfile, "w+b")) == NULL) {
+    
+        fclose (tfp);
+        
+        report_at (program_name, 0, REPORT_ERROR, "failed to open %s for writing", state->outfile);
+        exit (EXIT_FAILURE);
+    
+    }
+    
+    contents = xmalloc (512);
+    bytes = ftell (tfp);
+    
+    fseek (arfp, 0, SEEK_SET);
+    fseek (tfp, 0, SEEK_SET);
+    
+    for (;;) {
+    
+        if (bytes == 0 || feof (tfp)) {
+            break;
+        } else if (bytes >= 512) {
+            read = 512;
+        } else {
+            read = bytes;
+        }
+        
+        if (fread (contents, read, 1, tfp) != 1) {
+            
+            free (contents);
+            fclose (tfp);
+            
+            report_at (program_name, 0, REPORT_ERROR, "failed whilst reading temp file");
+            return;
+        
+        }
+        
+        bytes -= read;
+        
+        if (fwrite (contents, read, 1, arfp) != 1) {
+        
+            free (contents);
+            fclose (tfp);
+            
+            report_at (program_name, 0, REPORT_ERROR, "failed whist writing %s", state->outfile);
+            exit (EXIT_FAILURE);
+        
+        }
+    
+    }
+    
+    free (contents);
+    fclose (tfp);
+
+}
diff --git a/display.c b/display.c
new file mode 100644 (file)
index 0000000..7038961
--- /dev/null
+++ b/display.c
@@ -0,0 +1,57 @@
+/******************************************************************************
+ * @file            display.c
+ *****************************************************************************/
+#include    <stdio.h>
+#include    <string.h>
+
+#include    "ar.h"
+#include    "report.h"
+
+void display (void) {
+
+    char temp[17] = { 0 };
+    int i;
+    
+    for (;;) {
+    
+        struct ar_header hdr;
+        long bytes;
+        
+        if (fread (&hdr, sizeof (hdr), 1, arfp) != 1) {
+        
+            if (feof (arfp)) {
+                break;
+            }
+            
+            report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", state->outfile);
+            return;
+        
+        }
+        
+        bytes = conv_dec (hdr.size, 10);
+        
+        if (bytes % 2) {
+            bytes++;
+        }
+        
+        fseek (arfp, bytes, SEEK_CUR);
+        
+        if (memcmp (hdr.name, "/", 1) == 0) {
+            continue;
+        }
+        
+        memcpy (temp, hdr.name, 16);
+        
+        for (i = 16; i >= 0; --i) {
+        
+            if (temp[i] == 0x20) {
+                temp[i] = '\0';
+            }
+        
+        }
+        
+        printf ("%s\n", temp);
+    
+    }
+
+}
diff --git a/extract.c b/extract.c
new file mode 100644 (file)
index 0000000..18fd2c6
--- /dev/null
+++ b/extract.c
@@ -0,0 +1,120 @@
+/******************************************************************************
+ * @file            extract.c
+ *****************************************************************************/
+#include    <stdio.h>
+#include    <stdlib.h>
+#include    <string.h>
+
+#include    "ar.h"
+#include    "lib.h"
+#include    "report.h"
+
+void extract (char *fname) {
+
+    FILE *ofp;
+    
+    char temp[17], *name, *p, *contents;
+    long bytes, len, read;
+    
+    name = fname;
+    
+    if ((p = strrchr (fname, '/'))) {
+        name = (p + 1);
+    }
+    
+    len = strlen (name);
+    
+    if (len > 16) {
+        len = 16;
+    }
+    
+    memcpy (temp, name, len);
+    temp[len] = '\0';
+    
+    for (;;) {
+    
+        struct ar_header hdr;
+        
+        if (fread (&hdr, sizeof (hdr), 1, arfp) != 1) {
+        
+            if (feof (arfp)) {
+                break;
+            }
+            
+            report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", state->outfile);
+            return;
+        
+        }
+        
+        bytes = conv_dec (hdr.size, 10);
+        
+        if (memcmp (hdr.name, "/", 1) == 0) {
+        
+            if (bytes % 2) {
+                bytes++;
+            }
+            
+            fseek (arfp, bytes, SEEK_CUR);
+            continue;
+        
+        }
+        
+        if (memcmp (hdr.name, temp, len) != 0) {
+        
+            if (bytes % 2) {
+                bytes++;
+            }
+            
+            fseek (arfp, bytes, SEEK_CUR);
+            continue;
+        
+        }
+        
+        if ((ofp = fopen (temp, "w+b")) == NULL) {
+        
+            report_at (program_name, 0, REPORT_ERROR, "failed to open %s for writing", temp);
+            exit (EXIT_FAILURE);
+        
+        }
+        
+        contents = xmalloc (512);
+        
+        for (;;) {
+        
+            if (bytes == 0 || feof (arfp)) {
+                break;
+            } else if (bytes >= 512) {
+                read = 512;
+            } else {
+                read = bytes;
+            }
+            
+            if (fread (contents, read, 1, arfp) != 1) {
+            
+                free (contents);
+                fclose (ofp);
+                
+                report_at (NULL, 0, REPORT_ERROR, "failed to read %ld bytes from %s", bytes, state->outfile);
+                exit (EXIT_FAILURE);
+            
+            }
+            
+            bytes -= read;
+            
+            if (fwrite (contents, read, 1, ofp) != 1) {
+            
+                free (contents);
+                fclose (ofp);
+                
+                report_at (NULL, 0, REPORT_ERROR, "failed to write %s file", temp);
+                exit (EXIT_FAILURE);
+            
+            }
+        
+        }
+        
+        free (contents);
+    
+    }
+
+}
diff --git a/lib.c b/lib.c
new file mode 100644 (file)
index 0000000..aa774d8
--- /dev/null
+++ b/lib.c
@@ -0,0 +1,200 @@
+/******************************************************************************
+ * @file            lib.c
+ *****************************************************************************/
+#include    <ctype.h>
+#include    <stddef.h>
+#include    <stdio.h>
+#include    <stdlib.h>
+#include    <string.h>
+
+#include    "ar.h"
+#include    "lib.h"
+#include    "report.h"
+#include    "stdint.h"
+
+static void print_help (void) {
+
+    if (!program_name) {
+        goto _exit;
+    }
+    
+    fprintf (stderr, "Usage: %s command archive-file file...\n", program_name);
+    fprintf (stderr, "Commands:\n\n");
+    
+    fprintf (stderr, "    d             delete file(s) from the archive\n");
+    fprintf (stderr, "    q             quick append file(s) to the archive\n");
+    fprintf (stderr, "    r             replace existing or insert new file(s) into the archive\n");
+    fprintf (stderr, "    s             act as ranlib\n");
+    fprintf (stderr, "    t             display contents of the archive\n");
+    fprintf (stderr, "    x             extract file(s) from the archive\n");
+    
+    fprintf (stderr, "\n");
+    
+_exit:
+    
+    exit (EXIT_SUCCESS);
+
+}
+
+char *xstrdup (const char *str) {
+
+    char *ptr = xmalloc (strlen (str) + 1);
+    strcpy (ptr, str);
+    
+    return ptr;
+
+}
+
+void *xmalloc (unsigned long size) {
+
+    void *ptr = malloc (size);
+    
+    if (ptr == NULL && size) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "memory full (malloc)");
+        exit (EXIT_FAILURE);
+    
+    }
+    
+    memset (ptr, 0, size);
+    return ptr;
+
+}
+
+void *xrealloc (void *ptr, unsigned long size) {
+
+    void *new_ptr = realloc (ptr, size);
+    
+    if (new_ptr == NULL && size) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "memory full (realloc)");
+        exit (EXIT_FAILURE);
+    
+    }
+    
+    return new_ptr;
+
+}
+
+void dynarray_add (void *ptab, long *nb_ptr, void *data) {
+
+    int32_t nb, nb_alloc;
+    void **pp;
+    
+    nb = *nb_ptr;
+    pp = *(void ***) ptab;
+    
+    if ((nb & (nb - 1)) == 0) {
+    
+        if (!nb) {
+            nb_alloc = 1;
+        } else {
+            nb_alloc = nb * 2;
+        }
+        
+        pp = xrealloc (pp, nb_alloc * sizeof (void *));
+        *(void ***) ptab = pp;
+    
+    }
+    
+    pp[nb++] = data;
+    *nb_ptr = nb;
+
+}
+
+void parse_args (int *pargc, char ***pargv, int optind) {
+
+    char **argv = *pargv;
+    int argc = *pargc;
+    
+    const char *r;
+    
+    if (argc < 3) {
+        print_help ();
+    }
+    
+    r = argv[optind++];
+    
+check_options:
+    
+    if (r[0] == '-') {
+        ++r;
+    }
+    
+    while (*r != '\0') {
+    
+        char ch = *r++;
+        
+        if (ch == 'd') {
+        
+            state->del++;
+            continue;
+        
+        }
+        
+        if (ch == 'm') {
+        
+            state->move++;
+            continue;
+        
+        }
+        
+        if (ch == 'p') {
+        
+            state->print++;
+            continue;
+        
+        }
+        
+        if (ch == 'q') {
+        
+            state->append++;
+            continue;
+        
+        }
+        
+        if (ch == 'r') {
+        
+            state->replace++;
+            continue;
+        
+        }
+        
+        if (ch == 's') {
+        
+            state->ranlib++;
+            continue;
+        
+        }
+        
+        if (ch == 't') {
+        
+            state->display++;
+            continue;
+        
+        }
+        
+        if (ch == 'x') {
+        
+            state->extract++;
+            continue;
+        
+        }
+        
+        print_help ();
+    
+    }
+    
+    if (*(r = argv[optind++]) == '-') { goto check_options; }
+    
+    if (state->append + state->del + state->display + state->extract + state->move + state->print + state->ranlib + state->replace != 1) {
+        print_help ();
+    }
+    
+    state->outfile = xstrdup (r);
+    
+    while (optind < argc) {
+        dynarray_add (&state->files, &state->nb_files, xstrdup (argv[optind++]));
+    }
+
+}
diff --git a/lib.h b/lib.h
new file mode 100644 (file)
index 0000000..d1adb09
--- /dev/null
+++ b/lib.h
@@ -0,0 +1,15 @@
+/******************************************************************************
+ * @file            lib.h
+ *****************************************************************************/
+#ifndef     _LIB_H
+#define     _LIB_H
+
+char *xstrdup (const char *str);
+
+void *xmalloc (unsigned long size);
+void *xrealloc (void *ptr, unsigned long size);
+
+void dynarray_add (void *ptab, long *nb_ptr, void *data);
+void parse_args (int *pargc, char ***pargv, int optind);
+
+#endif      /* _LIB_H */
diff --git a/makefile.slp b/makefile.slp
new file mode 100644 (file)
index 0000000..1749ae7
--- /dev/null
@@ -0,0 +1,26 @@
+# This builds the Linux 32-bit ELF executable
+
+AS=pdas --oformat coff
+CC=gccwin
+LD=pdld
+
+COPTS=-S -O2 -fno-common -ansi -I. -I../pdos/pdpclib \
+    -U__WIN32__ -D__NOBIVA__ -D__PDOS__ \
+    -D__gnu_linux__
+LDFLAGS=-s --no-insert-timestamp -nostdlib --oformat elf --emit-relocs
+
+COBJ=append.obj ar.obj conv.obj delete.obj display.obj extract.obj \
+    lib.obj ranlib.obj replace.obj report.obj
+
+all: clean xar.exe
+
+xar.exe: $(COBJ)
+  $(LD) $(LDFLAGS) -o xar.exe ../pdos/pdpclib/linstart.o $(COBJ) ../pdos/pdpclib/pdplinux.a
+
+.c.obj:
+  $(CC) $(COPTS) $<
+  $(AS) -o $@ $*.s
+  rm -f $*.s
+
+clean:
+  rm -f *.obj xar.exe
diff --git a/makefile.sos b/makefile.sos
new file mode 100644 (file)
index 0000000..18ae6f6
--- /dev/null
@@ -0,0 +1,29 @@
+# This builds the OS/2 32-bit version\r
+# You will need to build PDPCLIB with the USE_MEMMGR\r
+# option because this program does lots of small memory allocations\r
+\r
+AS=pdas --oformat coff\r
+CC=gccwin\r
+LD=pdld\r
+\r
+COPTS=-S -O2 -fno-common -ansi -I. -I../pdos/pdpclib \\r
+    -U__WIN32__ -D__NOBIVA__ -D__PDOS__ \\r
+    -D__HAVESYS__=_System -D__OS2__ -D__32BIT__\r
+LDFLAGS=-s --no-insert-timestamp -nostdlib --oformat lx \\r
+    --stub ../pdos/pdpclib/needpdos.exe\r
+\r
+COBJ=append.obj ar.obj conv.obj delete.obj display.obj extract.obj \\r
+    lib.obj ranlib.obj replace.obj report.obj\r
+\r
+all: clean xar.exe\r
+\r
+xar.exe: $(COBJ)\r
+  $(LD) $(LDFLAGS) -o xar.exe ../pdos/pdpclib/os2strt.obj $(COBJ) ../pdos/pdpclib/pdpos2.lib ../pdos/pdpclib/os2.lib\r
+\r
+.c.obj:\r
+  $(CC) $(COPTS) $<\r
+  $(AS) -o $@ $*.s\r
+  rm -f $*.s\r
+\r
+clean:\r
+  rm -f *.obj xar.exe\r
diff --git a/makefile.std b/makefile.std
new file mode 100644 (file)
index 0000000..ddfb016
--- /dev/null
@@ -0,0 +1,20 @@
+AS=pdas --oformat coff\r
+CC=gccwin\r
+LD=pdld\r
+\r
+COPTS=-S -O2 -fno-common -ansi -I. -I../pdos/pdpclib -D__WIN32__ -D__NOBIVA__ -D__PDOS__\r
+COBJ=append.obj ar.obj conv.obj delete.obj display.obj extract.obj \\r
+    lib.obj ranlib.obj replace.obj report.obj\r
+\r
+all: clean xar.exe\r
+\r
+xar.exe: $(COBJ)\r
+  $(LD) -s -nostdlib --no-insert-timestamp -o xar.exe ../pdos/pdpclib/w32start.obj $(COBJ) ../pdos/pdpclib/msvcrt.lib\r
+\r
+.c.obj:\r
+  $(CC) $(COPTS) $<\r
+  $(AS) -o $@ $*.s\r
+  rm -f $*.s\r
+\r
+clean:\r
+  rm -f *.o xar.exe\r
diff --git a/ranlib.c b/ranlib.c
new file mode 100644 (file)
index 0000000..3a88817
--- /dev/null
+++ b/ranlib.c
@@ -0,0 +1,541 @@
+/******************************************************************************
+ * @file            ranlib.c
+ *****************************************************************************/
+#include    <limits.h>
+#include    <stddef.h>
+#include    <stdio.h>
+#include    <stdlib.h>
+#include    <string.h>
+
+#include    "ar.h"
+#include    "lib.h"
+#include    "report.h"
+
+#define     GET_INT32(arr)              ((int32_t) arr[0] | (((int32_t) arr[1]) << 8) | (((int32_t) arr[2]) << 16) | (((int32_t) arr[3]) << 24))
+
+#define     GET_UINT16(arr)             ((uint32_t) arr[0] | (((uint32_t) arr[1]) << 8))
+#define     GET_UINT32(arr)             ((uint32_t) arr[0] | (((uint32_t) arr[1]) << 8) | (((uint32_t) arr[2]) << 16) | (((uint32_t) arr[3]) << 24))
+
+struct aout_exec {
+
+    unsigned char a_info[4];
+    unsigned char a_text[4];
+    unsigned char a_data[4];
+    unsigned char a_bss[4];
+    unsigned char a_syms[4];
+    unsigned char a_entry[4];
+    unsigned char a_trsize[4];
+    unsigned char a_drsize[4];
+
+};
+
+struct aout_nlist {
+
+    unsigned char n_strx[4];
+    unsigned char n_type;
+    
+    unsigned char n_other;
+    unsigned char n_desc[2];
+    
+    unsigned char n_value[4];
+
+};
+
+struct coff_exec {
+
+    unsigned char Machine[2];
+    unsigned char NumberOfSections[2];
+    
+    unsigned char TimeDateStamp[4];
+    unsigned char PointerToSymbolTable[4];
+    unsigned char NumberOfSymbols[4];
+    
+    unsigned char SizeOfOptionalHeader[2];
+    unsigned char Characteristics[2];
+
+};
+
+struct coff_symbol {
+
+    char Name[8];
+    unsigned char Value[4];
+    
+    unsigned char SectionNumber[2];
+    unsigned char Type[2];
+    
+    unsigned char StorageClass[1];
+    unsigned char NumberOfAuxSymbols[1];
+
+};
+
+struct strtab {
+
+    const char *name;
+    long length, offset;
+
+};
+
+struct gstrtab {
+
+    long count, max;
+    struct strtab *strtabs;
+
+};
+
+static struct gstrtab gstrtab = { 0, 64, NULL };
+
+static int add_strtab (struct gstrtab *gstrtab, struct strtab *strtab) {
+
+    if (gstrtab->strtabs == NULL) {
+    
+        if ((gstrtab->strtabs = malloc (gstrtab->max * sizeof (*strtab))) == NULL) {
+            return 1;
+        }
+    
+    }
+    
+    if (gstrtab->count >= gstrtab->max) {
+    
+        void *tmp;
+        
+        gstrtab->max *= 2;
+        
+        if ((tmp = realloc (gstrtab->strtabs, gstrtab->max * sizeof (*strtab))) == NULL) {
+            return 1;
+        }
+        
+        gstrtab->strtabs = tmp;
+    
+    }
+    
+    gstrtab->strtabs[gstrtab->count] = *strtab;
+    gstrtab->count++;
+    
+    return 0;
+
+}
+
+static void aout_get_symbols (void *object, long offset) {
+
+    struct aout_exec *hdr = (struct aout_exec *) object;
+    
+    long sym_start = sizeof (*hdr) + GET_UINT32 (hdr->a_text) + GET_UINT32 (hdr->a_data) + GET_UINT32 (hdr->a_trsize) + GET_UINT32 (hdr->a_drsize);
+    long strtab_start = sym_start + GET_UINT32 (hdr->a_syms);
+    
+    while (sym_start < strtab_start) {
+    
+        struct aout_nlist nlist;
+        memcpy (&nlist, (char *) object + sym_start, sizeof (nlist));
+        
+        if (nlist.n_type == 5 || nlist.n_type == 7 || nlist.n_type == 9) {
+        
+            struct strtab *strtab;
+            char *symname = (char *) object + strtab_start + GET_INT32 (nlist.n_strx);
+            
+            strtab = xmalloc (sizeof (*strtab));
+            strtab->length = strlen (symname);
+            
+            strtab->name = xstrdup (symname);
+            strtab->offset = offset;
+            
+            add_strtab (&gstrtab, strtab);
+        
+        }
+        
+        sym_start += sizeof (nlist);
+    
+    }
+
+}
+
+static void coff_get_symbols (void *object, long offset) {
+
+    struct coff_exec *hdr = (struct coff_exec *) object;
+    
+    long sym_start = GET_UINT32 (hdr->PointerToSymbolTable);
+    long sym_cnt = GET_UINT32 (hdr->NumberOfSymbols);
+    long string_table_start = sym_start + (sizeof (struct coff_symbol) * sym_cnt);
+    
+    while (sym_cnt--) {
+    
+        struct coff_symbol sym;
+        memcpy (&sym, (char *) object + sym_start, sizeof (sym));
+        
+        if (sym.StorageClass[0] == 2 && GET_UINT16 (sym.SectionNumber) != 0) {
+        
+            struct strtab *strtab;
+            
+            if (sym.Name[0] != 0) {
+            
+                int i, len;
+                
+                for (i = 0, len = 0; i < 8; i++) {
+                
+                    if (sym.Name[i] == '\0') {
+                        break;
+                    }
+                    
+                    len++;
+                
+                }
+                
+                strtab = xmalloc (sizeof (*strtab));
+                strtab->length = len;
+                
+                strtab->name = xstrdup (sym.Name);
+                strtab->offset = offset;
+                
+                add_strtab (&gstrtab, strtab);
+            
+            } else {
+            
+                unsigned char offset1 = (unsigned char) sym.Name[4];
+                unsigned char offset2 = (unsigned char) sym.Name[5];
+                unsigned char offset3 = (unsigned char) sym.Name[6];
+                unsigned char offset4 = (unsigned char) sym.Name[7];
+                
+                long final_offset = ((uint32_t) offset1 | (((uint32_t) offset2) << 8) | (((uint32_t) offset3) << 16) | (((uint32_t) offset4) << 24));
+                final_offset += string_table_start;
+                
+                strtab = xmalloc (sizeof (*strtab));
+                strtab->length = strlen ((char *) object + final_offset);
+                
+                strtab->name = xstrdup ((char *) object + final_offset);
+                strtab->offset = offset;
+                
+                add_strtab (&gstrtab, strtab);
+            
+            }
+        
+        }
+        
+        sym_start += sizeof (sym);
+    
+    }
+
+}
+
+void ranlib (void) {
+
+    FILE *tfp = tmpfile ();
+    long offset = 0;
+    
+    struct ar_header header;
+    long bytes, i, j, len, read, val;
+    
+    unsigned char *object;
+    void *contents;
+    
+    char temp[16];
+    int valid = 0;
+    
+    for (;;) {
+    
+        struct ar_header hdr;
+        long bytes;
+        
+        if (fread (&hdr, sizeof (hdr), 1, arfp) != 1) {
+        
+            if (feof (arfp)) {
+                break;
+            }
+            
+            report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", state->outfile);
+            return;
+        
+        }
+        
+        bytes = conv_dec (hdr.size, 10);
+        
+        if (bytes % 2) {
+            bytes++;
+        }
+        
+        if (memcmp (hdr.name, "/", 1) == 0) {
+        
+            fseek (arfp, bytes, SEEK_CUR);
+            continue;
+        
+        }
+        
+        object = xmalloc (bytes);
+        
+        if (fread (object, bytes, 1, arfp) != 1) {
+        
+            free (object);
+            
+            report_at (program_name, 0, REPORT_ERROR, "failed to read %ld bytes from %s", bytes, state->outfile);
+            exit (EXIT_FAILURE);
+            
+        
+        }
+        
+        valid = ((object[0] == 0x07 && object[1] == 0x01) || (object[0] == 0x4C && object[1] == 0x01) || (object[0] == 0x64 && object[1] == 0x86));
+        
+        if (!valid) {
+        
+            free (object);
+            
+            offset += sizeof (hdr);
+            offset += bytes;
+            
+            fseek (arfp, bytes, SEEK_CUR);
+            continue;
+        
+        }
+        
+        if (object[0] == 0x07 && object[1] == 0x01) {
+            aout_get_symbols (object, offset + 8);
+        } else {
+            coff_get_symbols (object, offset + 8);
+        }
+        
+        free (object);
+        
+        offset += sizeof (hdr);
+        offset += bytes;
+    
+    }
+    
+    fseek (arfp, 8, SEEK_SET);
+    bytes = 0;
+    
+    for (i = 0; i < gstrtab.count; ++i) {
+        bytes += gstrtab.strtabs[i].length + 5;
+    }
+    
+    for (i = 0; i < gstrtab.count; ++i) {
+    
+        gstrtab.strtabs[i].offset += bytes;
+        
+        if (bytes % 2) {
+            gstrtab.strtabs[i].offset++;
+        }
+    
+    }
+    
+    if (fwrite ("!<arch>\x0A", 8, 1, tfp) != 1) {
+    
+        fclose (tfp);
+        
+        report_at (program_name, 0, REPORT_ERROR, "failed whist writing ar header");
+        return;
+    
+    }
+    
+    memset (temp, 0x20, 16);
+    temp[0] = '0';
+    
+    len = 1;
+    memcpy (header.name, "/", len);
+    
+    while (len < 16) {
+        header.name[len++] = 0x20;
+    }
+    
+    memcpy (header.mtime, temp, 12);
+    memcpy (header.owner, temp, 6);
+    memcpy (header.group, temp, 6);
+    memcpy (header.mode, temp, 8);
+    
+    len = sprintf (temp, "%ld", bytes + 4);
+    temp[len] = 0x20;
+    
+    memcpy (header.size, temp, 10);
+    
+    header.endsig[0] = 0x60;
+    header.endsig[1] = 0x0A;
+    
+    if (fwrite (&header, sizeof (header), 1, tfp) != 1) {
+    
+        fclose (tfp);
+        
+        report_at (program_name, 0, REPORT_ERROR, "failed whilst writing header");
+        return;
+    
+    }
+    
+    val = gstrtab.count;
+    
+    for (i = 0; i < 4; ++i) {
+        temp[4 - 1 - i] = (val >> (CHAR_BIT * i)) & UCHAR_MAX;
+    }
+    
+    if (fwrite (temp, 4, 1, tfp) != 1) {
+        exit (EXIT_FAILURE);
+    }
+    
+    for (i = 0; i < gstrtab.count; ++i) {
+    
+        val = gstrtab.strtabs[i].offset + 4 + sizeof (header);
+        
+        for (j = 0; j < 4; ++j) {
+            temp[4 - 1 - j] = (val >> (CHAR_BIT * j)) & UCHAR_MAX;
+        }
+        
+        if (fwrite (temp, 4, 1, tfp) != 1) {
+            exit (EXIT_FAILURE);
+        }
+    
+    }
+    
+    for (i = 0; i < gstrtab.count; ++i) {
+    
+        const char *name = gstrtab.strtabs[i].name;
+        long length = gstrtab.strtabs[i].length;
+        
+        if (fwrite (name, length, 1, tfp) != 1) {
+            exit (EXIT_FAILURE);
+        }
+        
+        temp[0] = '\0';
+        
+        if (fwrite (temp, 1, 1, tfp) != 1) {
+            exit (EXIT_FAILURE);
+        }
+    
+    }
+    
+    if (bytes % 2) {
+    
+        temp[0] = '\0';
+        
+        if (fwrite (temp, 1, 1, tfp) != 1) {
+            exit (EXIT_FAILURE);
+        }
+    
+    }
+    
+    for (;;) {
+    
+        struct ar_header hdr;
+        
+        if (fread (&hdr, sizeof (hdr), 1, arfp) != 1) {
+        
+            if (feof (arfp)) {
+                break;
+            }
+            
+            report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", state->outfile);
+            return;
+        
+        }
+        
+        bytes = conv_dec (hdr.size, 10);
+        
+        if (bytes % 2) {
+            bytes++;
+        }
+        
+        if (memcmp (hdr.name, "/", 1) == 0) {
+        
+            fseek (arfp, bytes, SEEK_CUR);
+            continue;
+        
+        }
+        
+        if (fwrite (&hdr, sizeof (hdr), 1, tfp) != 1) {
+        
+            fclose (tfp);
+            
+            report_at (program_name, 0, REPORT_ERROR, "failed whilst writing header");
+            exit (EXIT_FAILURE);
+        
+        }
+        
+        contents = xmalloc (512);
+        
+        for (;;) {
+        
+            if (bytes == 0 || feof (arfp)) {
+                break;
+            } else if (bytes >= 512) {
+                read = 512;
+            } else {
+                read = bytes;
+            }
+            
+            if (fread (contents, read, 1, arfp) != 1) {
+            
+                free (contents);
+                fclose (tfp);
+                
+                report_at (NULL, 0, REPORT_ERROR, "failed to read %ld bytes from %s", bytes, state->outfile);
+                exit (EXIT_FAILURE);
+            
+            }
+            
+            bytes -= read;
+            
+            if (fwrite (contents, read, 1, tfp) != 1) {
+            
+                free (contents);
+                fclose (tfp);
+                
+                report_at (NULL, 0, REPORT_ERROR, "failed to write temp file");
+                exit (EXIT_FAILURE);
+            
+            }
+        
+        }
+        
+        free (contents);
+    
+    }
+    
+    fclose (arfp);
+    remove (state->outfile);
+    
+    if ((arfp = fopen (state->outfile, "w+b")) == NULL) {
+    
+        fclose (tfp);
+        
+        report_at (program_name, 0, REPORT_ERROR, "failed to open %s for writing", state->outfile);
+        exit (EXIT_FAILURE);
+    
+    }
+    
+    contents = xmalloc (512);
+    bytes = ftell (tfp);
+    
+    fseek (arfp, 0, SEEK_SET);
+    fseek (tfp, 0, SEEK_SET);
+    
+    for (;;) {
+    
+        if (bytes == 0 || feof (tfp)) {
+            break;
+        } else if (bytes >= 512) {
+            read = 512;
+        } else {
+            read = bytes;
+        }
+        
+        if (fread (contents, read, 1, tfp) != 1) {
+            
+            free (contents);
+            fclose (tfp);
+            
+            report_at (program_name, 0, REPORT_ERROR, "failed whilst reading temp file");
+            return;
+        
+        }
+        
+        bytes -= read;
+        
+        if (fwrite (contents, read, 1, arfp) != 1) {
+        
+            free (contents);
+            fclose (tfp);
+            
+            report_at (program_name, 0, REPORT_ERROR, "failed whist writing %s", state->outfile);
+            exit (EXIT_FAILURE);
+        
+        }
+    
+    }
+    
+    free (contents);
+    fclose (tfp);
+
+}
diff --git a/replace.c b/replace.c
new file mode 100644 (file)
index 0000000..3df068c
--- /dev/null
+++ b/replace.c
@@ -0,0 +1,192 @@
+/******************************************************************************
+ * @file            replace.c
+ *****************************************************************************/
+#include    <stdio.h>
+#include    <stdlib.h>
+#include    <string.h>
+
+#include    "ar.h"
+#include    "lib.h"
+#include    "report.h"
+
+void replace (char *fname) {
+
+    FILE *tfp = tmpfile ();
+    
+    char temp[17], *name, *p, *contents;
+    long bytes, len, read;
+    
+    if (fwrite ("!<arch>\x0A", 8, 1, tfp) != 1) {
+    
+        fclose (tfp);
+        
+        report_at (program_name, 0, REPORT_ERROR, "failed whist writing ar header");
+        return;
+    
+    }
+    
+    name = fname;
+    
+    if ((p = strrchr (fname, '/'))) {
+        name = (p + 1);
+    }
+    
+    len = strlen (name);
+    
+    if (len > 16) {
+        len = 16;
+    }
+    
+    memcpy (temp, name, len);
+    temp[len] = '\0';
+    
+    state->append = 1;
+    
+    for (;;) {
+    
+        struct ar_header hdr;
+        
+        if (fread (&hdr, sizeof (hdr), 1, arfp) != 1) {
+        
+            if (feof (arfp)) {
+                break;
+            }
+            
+            report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", state->outfile);
+            return;
+        
+        }
+        
+        bytes = conv_dec (hdr.size, 10);
+        
+        if (bytes % 2) {
+            bytes++;
+        }
+        
+        if (memcmp (hdr.name, "/", 1) == 0) {
+        
+            fseek (arfp, bytes, SEEK_CUR);
+            continue;
+        
+        }
+        
+        if (memcmp (hdr.name, temp, len) == 0) {
+        
+            state->append = 0;
+            append (tfp, fname);
+            
+            fseek (arfp, bytes, SEEK_CUR);
+            continue;
+        
+        }
+        
+        if (fwrite (&hdr, sizeof (hdr), 1, tfp) != 1) {
+        
+            fclose (tfp);
+            
+            report_at (program_name, 0, REPORT_ERROR, "failed whilst writing header");
+            exit (EXIT_FAILURE);
+        
+        }
+        
+        contents = xmalloc (512);
+        
+        for (;;) {
+        
+            if (bytes == 0 || feof (arfp)) {
+                break;
+            } else if (bytes >= 512) {
+                read = 512;;
+            } else {
+                read = bytes;
+            }
+            
+            if (fread (contents, read, 1, arfp) != 1) {
+            
+                free (contents);
+                
+                report_at (NULL, 0, REPORT_ERROR, "failed to read %ld bytes from %s", bytes, state->outfile);
+                exit (EXIT_FAILURE);
+            
+            }
+            
+            bytes -= read;
+            
+            if (fwrite (contents, read, 1, tfp) != 1) {
+            
+                free (contents);
+                
+                report_at (NULL, 0, REPORT_ERROR, "failed to write temp file");
+                exit (EXIT_FAILURE);
+            
+            }
+        
+        }
+        
+        free (contents);
+    
+    }
+    
+    if (state->append) {
+    
+        state->append = 0;
+        append (tfp, fname);
+    
+    }
+    
+    fclose (arfp);
+    remove (state->outfile);
+    
+    if ((arfp = fopen (state->outfile, "w+b")) == NULL) {
+    
+        fclose (tfp);
+        
+        report_at (program_name, 0, REPORT_ERROR, "failed to open %s", state->outfile);
+        exit (EXIT_FAILURE);
+    
+    }
+    
+    contents = xmalloc (512);
+    bytes = ftell (tfp);
+    
+    fseek (arfp, 0, SEEK_SET);
+    fseek (tfp, 0, SEEK_SET);
+    
+    for (;;) {
+    
+        if (bytes == 0 || feof (tfp)) {
+            break;
+        } else if (bytes >= 512) {
+            read = 512;
+        } else {
+            read = bytes;
+        }
+        
+        if (fread (contents, read, 1, tfp) != 1) {
+            
+            free (contents);
+            fclose (tfp);
+            
+            report_at (program_name, 0, REPORT_ERROR, "failed whilst reading temp file");
+            return;
+        
+        }
+        
+        bytes -= read;
+        
+        if (fwrite (contents, read, 1, arfp) != 1) {
+        
+            free (contents);
+            fclose (tfp);
+            
+            report_at (program_name, 0, REPORT_ERROR, "failed whist writing %s", state->outfile);
+            exit (EXIT_FAILURE);
+        
+        }
+    
+    }
+    
+    free (contents);
+    fclose (tfp);
+
+}
diff --git a/report.c b/report.c
new file mode 100644 (file)
index 0000000..14ad2f6
--- /dev/null
+++ b/report.c
@@ -0,0 +1,125 @@
+/******************************************************************************
+ * @file            report.c
+ *****************************************************************************/
+#include    <stdarg.h>
+#include    <stdio.h>
+
+#include    "report.h"
+
+#ifndef     __PDOS__
+#if     defined (_WIN32)
+# include   <windows.h>
+static int OriginalConsoleColor = -1;
+#endif
+
+static void reset_console_color (void) {
+
+#if     defined (_WIN32)
+
+    HANDLE hStdError = GetStdHandle (STD_ERROR_HANDLE);
+    
+    if (OriginalConsoleColor == -1) { return; }
+    
+    SetConsoleTextAttribute (hStdError, OriginalConsoleColor);
+    OriginalConsoleColor = -1;
+
+#else
+
+    fprintf (stderr, "\033[0m");
+
+#endif
+
+}
+
+static void set_console_color (int color) {
+
+#if     defined (_WIN32)
+
+    HANDLE hStdError = GetStdHandle (STD_ERROR_HANDLE);
+    WORD wColor;
+    
+    if (OriginalConsoleColor == -1) {
+    
+        CONSOLE_SCREEN_BUFFER_INFO csbi;
+        
+        if (!GetConsoleScreenBufferInfo (hStdError, &csbi)) {
+            return;
+        }
+        
+        OriginalConsoleColor = csbi.wAttributes;
+    
+    }
+    
+    wColor = (OriginalConsoleColor & 0xF0) + (color & 0xF);
+    SetConsoleTextAttribute (hStdError, wColor);
+
+#else
+
+    fprintf (stderr, "\033[%dm", color);
+
+#endif
+
+}
+#endif
+
+void report_at (const char *filename, unsigned long line_number, int type, const char *fmt, ...) {
+
+    va_list ap;
+    
+    if (filename) {
+    
+        if (line_number == 0) {
+            fprintf (stderr, "%s: ", filename);
+        } else {
+            fprintf (stderr, "%s:", filename);
+        }
+    
+    }
+    
+    if (line_number > 0) {
+        fprintf (stderr, "%lu: ", line_number);
+    }
+    
+    if (type == REPORT_ERROR || type == REPORT_FATAL_ERROR) {
+    
+#ifndef     __PDOS__
+        set_console_color (COLOR_ERROR);
+#endif
+        
+        if (type == REPORT_ERROR) {
+            fprintf (stderr, "error:");
+        } else {
+            fprintf (stderr, "fatal error:");
+        }
+    
+    } else if (type == REPORT_INTERNAL_ERROR) {
+    
+#ifndef     __PDOS__
+        set_console_color (COLOR_INTERNAL_ERROR);
+#endif
+        
+        fprintf (stderr, "internal error:");
+    
+    } else if (type == REPORT_WARNING) {
+    
+#ifndef     __PDOS__
+        set_console_color (COLOR_WARNING);
+#endif
+        
+        fprintf (stderr, "warning:");
+    
+    }
+    
+#ifndef     __PDOS__
+    reset_console_color ();
+#endif
+    
+    fprintf (stderr, " ");
+    
+    va_start (ap, fmt);
+    vfprintf (stderr, fmt, ap);
+    va_end (ap);
+    
+    fprintf (stderr, "\n");
+
+}
diff --git a/report.h b/report.h
new file mode 100644 (file)
index 0000000..bdd121e
--- /dev/null
+++ b/report.h
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * @file            report.h
+ *****************************************************************************/
+#ifndef     _REPORT_H
+#define     _REPORT_H
+
+enum {
+
+    REPORT_ERROR = 0,
+    REPORT_FATAL_ERROR,
+    REPORT_INTERNAL_ERROR,
+    REPORT_WARNING
+
+};
+
+#if     defined (_WIN32)
+# define    COLOR_ERROR                 12
+# define    COLOR_WARNING               13
+# define    COLOR_INTERNAL_ERROR        19
+#else
+# define    COLOR_ERROR                 91
+# define    COLOR_INTERNAL_ERROR        94
+# define    COLOR_WARNING               95
+#endif
+
+void report_at (const char *filename, unsigned long line_number, int type, const char *fmt, ...);
+
+#endif      /* _REPORT_H */
diff --git a/stdint.h b/stdint.h
new file mode 100644 (file)
index 0000000..f4b18c0
--- /dev/null
+++ b/stdint.h
@@ -0,0 +1,23 @@
+/******************************************************************************
+ * @file            stdint.h
+ *****************************************************************************/
+#ifndef     _STDINT_H
+#define     _STDINT_H
+
+#include    <limits.h>
+
+typedef     signed char                 int8_t;
+typedef     unsigned char               uint8_t;
+
+typedef     signed short                int16_t;
+typedef     unsigned short              uint16_t;
+
+#if     INT_MAX == 32767
+typedef     signed long                 int32_t;
+typedef     unsigned long               uint32_t;
+#else
+typedef     signed int                  int32_t;
+typedef     unsigned int                uint32_t;
+#endif
+
+#endif      /* _STDINT_H */