소스 검색

tools: add blkunpack

and remove cfspack, which will not ever be used again.
pull/102/head
Virgil Dupras 4 년 전
부모
커밋
79ce88c12c
41개의 변경된 파일250개의 추가작업 그리고 361개의 파일을 삭제
  1. +12
    -0
      blk/001
  2. +4
    -0
      blk/003
  3. +1
    -0
      blk/004
  4. +2
    -0
      blk/009
  5. +12
    -0
      blk/016
  6. +7
    -0
      blk/018
  7. +5
    -0
      blk/030
  8. +6
    -0
      blk/032
  9. +13
    -0
      blk/035
  10. +10
    -0
      blk/038
  11. +1
    -0
      blk/043
  12. +0
    -0
      blk/044
  13. +5
    -0
      blk/046
  14. +9
    -0
      blk/048
  15. +6
    -0
      blk/052
  16. +2
    -0
      blk/054
  17. +8
    -0
      blk/056
  18. +6
    -0
      blk/058
  19. +7
    -0
      blk/062
  20. +10
    -0
      blk/064
  21. +10
    -0
      blk/070
  22. +5
    -0
      blk/071
  23. +2
    -0
      blk/075
  24. +4
    -0
      blk/078
  25. +10
    -0
      blk/084
  26. +10
    -0
      blk/087
  27. +9
    -0
      blk/091
  28. +14
    -0
      blk/101
  29. +3
    -0
      blk/102
  30. +6
    -0
      blk/103
  31. +3
    -0
      blk/104
  32. +1
    -0
      tools/.gitignore
  33. +3
    -1
      tools/Makefile
  34. +44
    -0
      tools/blkunpack.c
  35. +0
    -2
      tools/cfspack/.gitignore
  36. +0
    -16
      tools/cfspack/Makefile
  37. +0
    -33
      tools/cfspack/README.md
  38. +0
    -10
      tools/cfspack/cfs.h
  39. +0
    -54
      tools/cfspack/cfspack.c
  40. +0
    -93
      tools/cfspack/cfsunpack.c
  41. +0
    -152
      tools/cfspack/libcfs.c

+ 12
- 0
blk/001 파일 보기

@@ -2,3 +2,15 @@ MASTER INDEX

3 Usage 30 Dictionary
70 Implementation notes 100 Block editor













+ 4
- 0
blk/003 파일 보기

@@ -10,3 +10,7 @@ Contents
4 DOES> 6 Compilation vs meta-comp.
8 I/O 11 Chained comparisons
14 Addressed devices 18 Signed-ness





+ 1
- 0
blk/004 파일 보기

@@ -13,3 +13,4 @@ At compile time, colon definition stops processing words when
reaching the DOES>.

Example: ": CONSTANT CREATE HERE @ ! DOES> @ ;"


+ 2
- 0
blk/009 파일 보기

@@ -12,3 +12,5 @@ new "(parse)" word.

This way, we have a full-featured (and extensible) parsing with
a tiny native core.



+ 12
- 0
blk/016 파일 보기

@@ -2,3 +2,15 @@
kind of ad-hoc way to have some kind of mapping function, but
what you'll mostly want to to is to plug device drivers into
those words.













+ 7
- 0
blk/018 파일 보기

@@ -7,3 +7,10 @@ support the "-" prefix, but under the hood, it's all unsigned.
This leads to some oddities. For example, "-1 0 <" is false.
To compare whether something is negative, use the "<0" word
which is the equivalent to "0x7fff >".








+ 5
- 0
blk/030 파일 보기

@@ -9,3 +9,8 @@ Be sure to read usage guide (B3) first.
52 Addressed devices 54 Arithmetic / Bits
56 Logic 58 Strings
60 I/O 64 Disk






+ 6
- 0
blk/032 파일 보기

@@ -8,3 +8,9 @@ Words between "()" are "support words" that aren't really meant
to be used directly, but as part of another word.

"*I*" in description indicates an IMMEDIATE word.







+ 13
- 0
blk/035 파일 보기

@@ -1,3 +1,16 @@
(cont.)
~ - Container for native code. Usually not an executable word.
? - Is it ...? (example: IMMED?)














+ 10
- 0
blk/038 파일 보기

@@ -4,3 +4,13 @@ FORGET x -- Rewind the dictionary (both CURRENT and HERE)
PREV a -- a Return a wordref's previous entry.
WHLEN a -- n Get word header length from wordref. That is,
name length + 3. a is a wordref











+ 1
- 0
blk/043 파일 보기

@@ -13,3 +13,4 @@ INTERPRET -- Get a line from stdin, compile it in tmp memory,
then execute the compiled contents.
QUIT -- Return to interpreter prompt immediately
EXIT! -- Exit current INTERPRET loop.


+ 0
- 0
blk/044 파일 보기


+ 5
- 0
blk/046 파일 보기

@@ -9,3 +9,8 @@ SWAP a b -- b a
2DUP a b -- a b a b
2OVER a b c d -- a b c d a b
2SWAP a b c d -- c d a b






+ 9
- 0
blk/048 파일 보기

@@ -5,3 +5,12 @@ R> R:n -- n Pops RS and push to PS
I -- n Copy RS TOS to PS
I' -- n Copy RS second item to PS
J -- n Copy RS third item to PS










+ 6
- 0
blk/052 파일 보기

@@ -8,3 +8,9 @@ A! c a -- Indirect C!
A@* -- a Address for A@ word
A!* -- a Address for A! word
AMOVE src dst u -- Same as MOVE, but with A@ and A!







+ 2
- 0
blk/054 파일 보기

@@ -12,3 +12,5 @@ OR a b -- c a | b -> c
XOR a b -- c a ^ b -> c

Shortcuts: 1+ 2+ 1- 2-



+ 8
- 0
blk/056 파일 보기

@@ -6,3 +6,11 @@ Logic
CMP n1 n2 -- n Compare n1 and n2 and set n to -1, 0, or 1.
n=0: a1=a2. n=1: a1>a2. n=-1: a1<a2.
NOT f -- f Push the logical opposite of f









+ 6
- 0
blk/058 파일 보기

@@ -8,3 +8,9 @@ LITS a -- Write word at addr a as a atring literal.
S= a1 a2 -- f Returns whether string a1 == a2.
SCPY a -- Copy string at addr a into HERE.
SLEN a -- n Push length of str at a.







+ 7
- 0
blk/062 파일 보기

@@ -7,3 +7,10 @@ SPC











+ 10
- 0
blk/064 파일 보기

@@ -4,3 +4,13 @@ BLK> -- a Address of the current block variable.
LIST n -- Prints the contents of the block n on screen in the
form of 16 lines of 64 columns.
LOAD n -- Interprets Forth code from block n











+ 10
- 0
blk/070 파일 보기

@@ -4,3 +4,13 @@ Implementation notes
75 Stack management 77 Dictionary
80 System variables 85 Word routines
89 Initialization sequence











+ 5
- 0
blk/071 파일 보기

@@ -9,3 +9,8 @@ it. As a general rule, we go like this:
4. Is it a number?
5. If yes, push that number to PS, goto 1
6. Error: undefined word.






+ 2
- 0
blk/075 파일 보기

@@ -12,3 +12,5 @@ IX always points to RS' Top Of Stack (TOS)
This return stack contain "Interpreter pointers", that is a
pointer to the address of a word, as seen in a compiled list of
words.



+ 4
- 0
blk/078 파일 보기

@@ -10,3 +10,7 @@ chain). There are also "special words", for example NUMBER,
LIT, FBR, that have a slightly different structure. They're
also a pointer to an executable, but as for the other fields,
the only one they have is the "flags" field.





+ 10
- 0
blk/084 파일 보기

@@ -4,3 +4,13 @@ DRIVERS section is reserved for recipe-specific
drivers. Here is a list of known usages:

* 0x70-0x78: ACIA buffer pointers in RC2014 recipes.











+ 10
- 0
blk/087 파일 보기

@@ -4,3 +4,13 @@ being followed by a 2 byte number, it is followed by a
null-terminated string. Upon execution, the address of that
null-terminated string is pushed on the PSP and IP is advanced
to the address following the null.











+ 9
- 0
blk/091 파일 보기

@@ -5,3 +5,12 @@ for space with HERE: New entries to the dict will overwrite
that code! Also, because we're barebone, we can't have
comments. This can lead to peculiar code in this area where we
try to "waste" space in initialization code.










+ 14
- 0
blk/101 파일 보기

@@ -1,2 +1,16 @@
T ( n -- ): select line n for editing.
P xxx(return): put typed line on selected line.















+ 3
- 0
blk/102 파일 보기

@@ -11,3 +11,6 @@
ENDCASE
AGAIN
;




+ 6
- 0
blk/103 파일 보기

@@ -8,3 +8,9 @@ VARIABLE ACC
: L BLK> @ _LIST ;
: B BLK> @ 1- BLK> ! L ;
: N BLK> @ 1+ BLK> ! L ;







+ 3
- 0
blk/104 파일 보기

@@ -11,3 +11,6 @@ VARIABLE EDPOS
DUP IF DROP C< THEN
LOOP
;




+ 1
- 0
tools/.gitignore 파일 보기

@@ -9,3 +9,4 @@
/bin2c
/exec
/blkpack
/blkunpack

+ 3
- 1
tools/Makefile 파일 보기

@@ -9,9 +9,10 @@ STRIPFC_TGT = stripfc
BIN2C_TGT = bin2c
EXEC_TGT = exec
BLKPACK_TGT = blkpack
BLKUNPACK_TGT = blkunpack
TARGETS = $(MEMDUMP_TGT) $(BLKDUMP_TGT) $(UPLOAD_TGT) $(FONTCOMPILE_TGT) \
$(TTYSAFE_TGT) $(PINGPONG_TGT) $(SLATEST_TGT) $(STRIPFC_TGT) \
$(BIN2C_TGT) $(EXEC_TGT) $(BLKPACK_TGT)
$(BIN2C_TGT) $(EXEC_TGT) $(BLKPACK_TGT) $(BLKUNPACK_TGT)
OBJS = common.o

all: $(TARGETS)
@@ -31,6 +32,7 @@ $(STRIPFC_TGT): $(STRIPFC_TGT).c
$(BIN2C_TGT): $(BIN2C_TGT).c
$(EXEC_TGT): $(EXEC_TGT).c
$(BLKPACK_TGT): $(BLKPACK_TGT).c
$(BLKUNPACK_TGT): $(BLKUNPACK_TGT).c
$(TARGETS): $(OBJS)
$(CC) $(CFLAGS) $@.c $(OBJS) -o $@



+ 44
- 0
tools/blkunpack.c 파일 보기

@@ -0,0 +1,44 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>

void usage()
{
fprintf(stderr, "Usage: blkunpack dirname\n");
}

int main(int argc, char *argv[])
{
char buf[1024];
int blkid = 0;
if (argc != 2) {
usage();
return 1;
}
while (fread(buf, 1024, 1, stdin) == 1) {
char fullpath[0x200];
sprintf(fullpath, "%s/%03d", argv[1], blkid);
char c = 0;
for (int i=0; i<1024; i++) {
c |= buf[i];
}
if (c) {
// not an empty block
printf("%s\n", fullpath);
FILE *fp = fopen(fullpath, "w");
for (int i=0; i<16; i++) {
int len = strlen(&buf[i*64]);
fwrite(&buf[i*64], len, 1, fp);
fputc('\n', fp);
}
fclose(fp);
} else {
// empty block, delete
unlink(fullpath);
}
blkid++;
}
return 0;
}

+ 0
- 2
tools/cfspack/.gitignore 파일 보기

@@ -1,2 +0,0 @@
/cfspack
/cfsunpack

+ 0
- 16
tools/cfspack/Makefile 파일 보기

@@ -1,16 +0,0 @@
TARGETS = cfspack cfsunpack

CFSPACK_OBJS = cfspack.o libcfs.o

.PHONY: all
all: $(TARGETS)

cfspack: $(CFSPACK_OBJS)
$(CC) $(LDFLAGS) -o $@ $(CFSPACK_OBJS)

cfsunpack: cfsunpack.c
$(CC) $(CFLAGS) -o $@ cfsunpack.c

.PHONY: clean
clean:
rm -f $(TARGETS)

+ 0
- 33
tools/cfspack/README.md 파일 보기

@@ -1,33 +0,0 @@
# cfspack

A tool/library to pack files into a CFS blob and unpack a CFS blob into
a directory.

## Usage

To pack a directory into a CFS blob, run:

cfspack /path/to/directory

The blob is spit to stdout. If there are subdirectories, they will be prefixes
to the filenames under it.

`cfspack` takes optional -p pattern arguments. If specified, only files
matching at least one of the patterns ("fnmatch" style") will be included.

If path is a file, a CFS with a single file will be spit and its name will
exclude the directory part of that filename.

The chain being spitted is always ended with a "stop block" (a zero-allocation
block that stops the CFS chain). You can call `cfspack` with no argument to get
only a stop block.

The program errors out if a file name is too long (> 26 bytes) or too big
(> 0x10000 - 0x20 bytes).

To unpack a blob to a directory:

cfsunpack /path/to/dest < blob

If destination exists, files are created alongside existing ones. If a file to
unpack already exists, it is overwritten.

+ 0
- 10
tools/cfspack/cfs.h 파일 보기

@@ -1,10 +0,0 @@
#define BLKSIZE 0x100
#define HEADERSIZE 0x20
#define MAX_FN_LEN 25 // 26 - null char
#define MAX_FILE_SIZE (BLKSIZE * 0x100) - HEADERSIZE

void set_spit_stream(FILE *stream);
int is_regular_file(char *path);
void spitempty();
int spitblock(char *fullpath, char *fn);
int spitdir(char *path, char *prefix, char **patterns);

+ 0
- 54
tools/cfspack/cfspack.c 파일 보기

@@ -1,54 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <fnmatch.h>
#include <libgen.h>
#include <sys/stat.h>

#include "cfs.h"

void usage()
{
fprintf(stderr, "Usage: cfspack [-p pattern] [/path/to/dir...]\n");
}

int main(int argc, char *argv[])
{
int patterncount = 0;
char **patterns = malloc(sizeof(char**));
patterns[0] = NULL;
while (1) {
int c = getopt(argc, argv, "p:");
if (c < 0) {
break;
}
switch (c) {
case 'p':
patterns[patterncount] = optarg;
patterncount++;
patterns = realloc(patterns, sizeof(char**)*(patterncount+1));
patterns[patterncount] = NULL;
break;
default:
usage();
return 1;
}
}
int res = 0;
for (int i=optind; i<argc; i++) {
if (is_regular_file(argv[i])) {
// special case: just one file
res = spitblock(argv[i], basename(argv[i]));
} else {
res = spitdir(argv[i], "", patterns);
}
}
if (res == 0) {
spitempty();
}
free(patterns);
return res;
}


+ 0
- 93
tools/cfspack/cfsunpack.c 파일 보기

@@ -1,93 +0,0 @@
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <sys/stat.h>

#define BLKSIZE 0x100
#define HEADERSIZE 0x20
#define MAX_FN_LEN 25 // 26 - null char

bool ensuredir(char *path)
{
char *s = path;
while (*s != '\0') {
if (*s == '/') {
*s = '\0';
struct stat path_stat;
if (stat(path, &path_stat) != 0) {
if (mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) {
return false;
}
}
*s = '/';
}
s++;
}
return true;
}

bool unpackblk(char *dstpath)
{
char buf[MAX_FN_LEN+1];
if (fgets(buf, 3+1, stdin) == NULL) {
return false;
}
if (strcmp(buf, "CFS") != 0) {
return false;
}
int c = getchar();
uint8_t blkcnt = c;
if (blkcnt == 0) {
return false;
}
c = getchar();
uint16_t fsize = c & 0xff;
c = getchar();
fsize |= (c & 0xff) << 8;

if (fgets(buf, MAX_FN_LEN+1+1, stdin) == NULL) {
return false;
}
char fullpath[0x1000];
strcpy(fullpath, dstpath);
strcat(fullpath, "/");
strcat(fullpath, buf);
if (!ensuredir(fullpath)) {
return false;
}
int blksize = (BLKSIZE-HEADERSIZE)+(BLKSIZE*(blkcnt-1));
int skipcount = blksize - fsize;
FILE *fp = fopen(fullpath, "w");
while (fsize) {
c = getchar();
if (c == EOF) {
return false;
}
fputc(c, fp);
fsize--;
}
fclose(fp);
while (skipcount) {
getchar();
skipcount--;
}
return true;
}

int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "Usage: cfspack /path/to/dest\n");
return 1;
}
char *dstpath = argv[1];
// we fail if there isn't at least one block
if (!unpackblk(dstpath)) {
return 1;
}
while (unpackblk(dstpath));
return 0;
}



+ 0
- 152
tools/cfspack/libcfs.c 파일 보기

@@ -1,152 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <fnmatch.h>
#include <libgen.h>
#include <sys/stat.h>

#include "cfs.h"

#define PUTC(c) putc(c, spitstream)

static FILE *spitstream = NULL;

void set_spit_stream(FILE *stream)
{
spitstream = stream;
}

int is_regular_file(char *path)
{
struct stat path_stat;
stat(path, &path_stat);
return S_ISREG(path_stat.st_mode);
}

void spitempty()
{
if (spitstream == NULL) spitstream = stdout;
PUTC('C');
PUTC('F');
PUTC('S');
for (int i=0; i<0x20-3; i++) {
PUTC(0);
}
}

int spitblock(char *fullpath, char *fn)
{
if (spitstream == NULL) spitstream = stdout;
FILE *fp = fopen(fullpath, "r");
fseek(fp, 0, SEEK_END);
long fsize = ftell(fp);
if (fsize > MAX_FILE_SIZE) {
fclose(fp);
fprintf(stderr, "File too big: %s %ld\n", fullpath, fsize);
return 1;
}
/* Compute block count.
* We always have at least one, which contains 0x100 bytes - 0x20, which is
* metadata. The rest of the blocks have a steady 0x100.
*/
unsigned char blockcount = 1;
int fsize2 = fsize - (BLKSIZE - HEADERSIZE);
if (fsize2 > 0) {
blockcount += (fsize2 / BLKSIZE);
}
if (blockcount * BLKSIZE < fsize + HEADERSIZE) {
blockcount++;
}
PUTC('C');
PUTC('F');
PUTC('S');
PUTC(blockcount);
// file size is little endian
PUTC(fsize & 0xff);
PUTC((fsize >> 8) & 0xff);
int fnlen = strlen(fn);
for (int i=0; i<MAX_FN_LEN; i++) {
if (i < fnlen) {
PUTC(fn[i]);
} else {
PUTC(0);
}
}
// And the last FN char which is always null
PUTC(0);
char buf[MAX_FILE_SIZE] = {0};
rewind(fp);
fread(buf, fsize, 1, fp);
fclose(fp);
fwrite(buf, (blockcount * BLKSIZE) - HEADERSIZE, 1, spitstream);
fflush(spitstream);
return 0;
}

int spitdir(char *path, char *prefix, char **patterns)
{
DIR *dp;
struct dirent *ep;

int prefixlen = strlen(prefix);
dp = opendir(path);
if (dp == NULL) {
fprintf(stderr, "Couldn't open directory.\n");
return 1;
}
while ((ep = readdir(dp))) {
if ((strcmp(ep->d_name, ".") == 0) || strcmp(ep->d_name, "..") == 0) {
continue;
}
if (ep->d_type != DT_DIR && ep->d_type != DT_REG) {
fprintf(stderr, "Only regular file or directories are supported\n");
return 1;
}
int slen = strlen(ep->d_name);
if (prefixlen + slen> MAX_FN_LEN) {
fprintf(stderr, "Filename too long: %s/%s\n", prefix, ep->d_name);
return 1;
}
char fullpath[0x1000];
strcpy(fullpath, path);
strcat(fullpath, "/");
strcat(fullpath, ep->d_name);
char newprefix[MAX_FN_LEN];
strcpy(newprefix, prefix);
if (prefixlen > 0) {
strcat(newprefix, "/");
}
strcat(newprefix, ep->d_name);
if (ep->d_type == DT_DIR) {
int r = spitdir(fullpath, newprefix, patterns);
if (r != 0) {
return r;
}
} else {
char **p = patterns;
// if we have no pattern, we match all
if (p && *p) {
int matches = 0;
while (*p) {
if (fnmatch(*p, ep->d_name, 0) == 0) {
matches = 1;
break;
}
p++;
}
if (!matches) {
continue;
}
}

int r = spitblock(fullpath, newprefix);
if (r != 0) {
return r;
}
}
}
closedir(dp);
return 0;
}

불러오는 중...
취소
저장