@L}5 _$% l0$)$$Hȱ$ UhL" `e$$%`$%`  R@P!( L(1   Y I`  d  Ld M * @  $ % CC$$)%1 Udߥ$9%: !0 S$% DD˙`  }J)Lr  /* This software is copyright 1989 by John Dunning. See the file 'COPYLEFT.JRD' for the full copyright notice. */} /* A65: a macro assembler for 6502's. a65 [-o foo.obj] [-l foo.l] f1.m65 f2.m65... */ #define VERSION "1.}0" #include #include "symtab.h" #include "parse.h" #include "util.h" #define MAIN 1 #include "global.h" } /* #define LIST ... turn this on for listing code */ /* #define EITHER .. turn this if ever get around to making the }assembler produce either rel or abs files */ FILE * inf; FILE * outf; char * in_name[16]; int n_files; char * out_name }; #ifdef DEBUG char * sym_name; #endif extern int _start; /* util fun for grokking arglist */ char * arg_value(ar }gs, arg_idx, n_args) char * args[]; int * arg_idx; /* we might increment this */ int n_args; { int i; i = *ar }g_idx; if (args[i][2]) /* was there something after the '-x'? */ return(args[i] + 2); /* yes, just return that */ }i++; /* try the next arg */ if (i >= n_args) /* no next arg? */ return(NULL); if (*args[i] == '-') /* next arg } not a value? */ return(NULL); *arg_idx = i; /* put updated value back */ return(args[i]); /* and return this ar}g */ } #ifdef M6502 char argbuf[80]; #endif main(argc, argv) int argc; char ** argv; { int i, local_pass, fidx}, code, class; /* printf("base = %X\n", &_start); */ n_files = 0; /* no files yet */ #ifdef LIST list_p = 0; }/* no listing */ #endif #ifdef DEBUG sym_name = 0; /* no sym file name yet */ #endif #ifdef EITHER rel_p = 0; /* }no relocatable output */ #endif verbose = 0; #ifdef M6502 /* if no args, prompt for 'em */ if (argc < 2) argc = }readargs("RA65>", argbuf, argv + 1) + 1; #endif for (i = 1 ; i < argc ; i++) { /* printf("considering arg %d '%s'\n"}, i, argv[i]); */ if (argv[i][0] == '-') { switch (argv[i][1]) { #ifdef LIST case 'l': case 'L': { } list_p = 1; list_name = arg_value(argv, &i, argc); break; } #endif case 'o': case 'O': { out_n}ame = arg_value(argv, &i, argc); break; } #ifdef DEBUG case 's': case 'S': { sym_name = arg_value(ar}gv, &i, argc); if (!sym_name) sym_name = "foo.sym"; break; } #endif #ifdef EITHER /* this is always o}n for this version of the assembler */ case 'r': case 'R': { rel_p = 1; if (verbose) printf("Relocat}able output\n"); break; } #endif case 'v': case 'V': { verbose++; break; } } } } else { in_name[n_files] = frob_name(argv[i]); n_files++; if (verbose) printf("Input file %d %s\n", n_files,} argv[i]); } } if (verbose) printf("RA65 v %s\n", VERSION); if (n_files < 1) { printf("Try A65 ...}\n"); exit(1); } if (verbose) printf("RA65 v %s\n", VERSION); init_sym(); #ifdef LIST init_list(); #endi}f init_gen(); for (local_pass = 0 ; local_pass < gen_n_passes() ; local_pass++) { errcount = 0; pass = local_pa}ss; pc = 0; disabled = 0; output_p = (pass == (gen_n_passes() - 1)); if (output_p != 0) { gen_o_open(out_name, }in_name[0]); } for (fidx = 0 ; fidx < n_files ; fidx++) { end_file = 0; inf = fopen(in_name[fidx], "r"); /* pr}intf("open('%s')->%X\n", in_name[fidx], inf); */ line_nbr = 0; while (!end_file && read_line(inf, line)) { if ( }verbose) printf("%4d: '%s'\n", line_nbr, line); line_nbr++; #ifdef LIST line_listed_p = 0; #endif obj_coun!}t = 0; parse_line(line, &p); if (p.opcode) { if (opcode_p(p.opcode, &code, &class)) { if (!disa"}bled) assemble_op(code, class, &p.arg[0]); } else if (!do_pseudo()) barf("Bogus lin#}e"); } else if (!disabled) gen_label(); #ifdef LIST list_line(0); #endif } fclose(inf); $} } #ifdef DEBUG if (sym_name) dump_syms(); #endif if (output_p) gen_o_close(); if (errcount) printf("%d er%}rors"); } } UG if (sym_name) dump_syms(); #endif if (output_p) gen_o_close(); if (errcount) printf("%d er CC65 ---- This is the (c) copyright notice for RA65, LINK65, LIBR65, and other Atari 8-bit programs. Said programs a'}re Copyright 1989, by John R. Dunning. All rights reserved, with the following exceptions: Anyone may copy or redistrib(}ute these programs, provided that: 1: You don't charge anything for the copy. It is permissable to charge a no)}minal fee for media, etc. 2: All source code and documentation for the programs is made available as part o*}f the distribution. 3: This copyright notice is preserved verbatim, and included in the distribution. You+} are allowed to modify these programs, and redistribute the modified versions, provided that the modifications are clearly,} noted. There is NO WARRANTY with this software, it comes as is, and is distributed in the hope that it may be useful.-} This copyright notice is based on the one published by the Free Software Foundation, sometimes known as the GNU project..} The idea is the same as theirs, ie the software is free, and is intended to stay that way. Everybody has the right to c/}opy, modify, and redistribute this software. Nobody has the right to prevent anyone else from copying, modifying or redis0}tributing it.d redistribute this software. Nobody has the right to prevent anyone else from copying, modifying or redis /* This software is copyright 1989 by John Dunning. See the file 'COPYLEFT.JRD' for the full copyright notice. */2} /* error stuff */ #include #include "global.h" #ifdef M6502 barf() { int * arg; arg = &arg; 3} /* point at self */ arg += arg[1] + 1; /* add next word; arg count, plus 1 */ fprintf(stderr, *arg, *--arg, *--arg, *-4}-arg); fprintf(stderr, "\n"); exit(1); } #else barf(msg, arg1, arg2, arg3) char * msg; int arg1, arg2, arg3; { 5} list_line(1); printf("Error: "); printf(msg, arg1, arg2, arg3); printf("\n"); errcount++; } #endif 3; { w /* This software is copyright 1989 by John Dunning. See the file 'COPYLEFT.JRD' for the full copyright notice. */ 7} /* expression evaluator */ #include "eval.h" #include "symtab.h" #include "global.h" char tbuf[32]; char * eva 8}l_internal(); /* forward decl */ int digit(c) char c; { if ((c >= '0') && (c <= '9')) return(c - '0'); else 9} if ((c >= 'A') && (c <= 'F')) return(c - 'A' + 10); else return(-1); } char * grok_fixnum(str, base, result) :} char * str; int base; int * result; { int d; char * s; int neg; s = str; *result = 0; neg = 0; ;}if (*s == '-') { neg = 1; s++; } while (((d = digit(toupper(*s))) >= 0) && (d <= base)) { *result = *result * <}base + d; s++; } if (neg) { *result = -(*result); } return(s); } /* eval one q, return updated string p =}tr */ char * eval_q(str, val, expr_flags, sym_ref) char * str; int * val; int * expr_flags; struct sym ** sym_ref; { >} char c; char * p; struct sym * sy; int i; while((c = *str) && white_p(c)) str++; if (id_start_p(c)) { ?}/* symbol */ p = tbuf; *p++ = *str++; while(id_char_p(*str)) *p++ = *str++; *p = '\0'; if ((tbuf[0] == '.') && ( @}tbuf[1] == '\0')) *val = pc; else { sy = find_sym(tbuf, 1); if ((!(sy->flags & DEFINED)) && (pass == 1)) A} barf("undefined symbol '%s'", tbuf); if (!(sy->flags & DEFINED)) *expr_flags |= E_UNDEF; if (!(sy->flags & ABS)) B} *expr_flags |= E_REL; *sym_ref = sy; *val = sy->value; } } else if (c == '$') /* hex constant */ st C}r = grok_fixnum(str + 1, 16, val); else if (c == '0') /* octal constant */ str = grok_fixnum(str, 8, val); el D}se if (c == '@') /* octal constant */ str = grok_fixnum(str + 1, 8, val); else if (c == '%') /* binary constan E}t */ str = grok_fixnum(str + 1, 2, val); else if (c == '^') /* constant with radix */ { switch(str[1]) { F} case 'o': { str = grok_fixnum(str + 2, 8, val); break; }; case 'x': { str = grok_fixnum(str + 2, 16, val); break; }; c G}ase 'd': { str = grok_fixnum(str + 2, 10, val); break; }; } } else if (((c > '0') && (c <= '9')) || (c == '-')) H}/* decimal constant */ str = grok_fixnum(str, 10, val); else if (c == '\'') { *val = str[1]; str += 2; } I} else if (c == '*') { *val = pc; str++; } else if (c == '<') str = eval_internal(str + 1, val, expr_fl J}ags, sym_ref); else barf("eval error: bogus operand '%c'", c); return(str); } char * binop(str, accum, expr_ K}flags, sym_ref) char * str; int * accum; int * expr_flags; struct sym ** sym_ref; { int val; char c; c = *str L}++; str = eval_q(str, &val, expr_flags, sym_ref); switch (c) { case '+': { *accum += val; break; } case '-': { *a M}ccum -= val; break; } case '*': { *accum *= val; break; } case '/': { *accum /= val; break; } case '&': { *accum &= val N}; break; } case '|': case '!': { *accum |= val; break; } } return(str); } char * eval_internal(str, val, expr_fl O}ags, sym_ref) char * str; int * val; int * expr_flags; struct sym ** sym_ref; { int accum; str = eval_q(str, &ac P}cum, expr_flags, sym_ref); while (white_p(*str)) str++; while (*str) /* more expr? */ switch(*str) { case Q}'+': case '-': case '*': case '/': case '&': case '|': case '!': { str = binop(str, &accum, expr_flags, sym_ref); R} break; } case '\\': { (*expr_flags) |= E_LO_BYTE; accum &= 0xFF; str++; break; } case ' S}^': { (*expr_flags) |= E_HI_BYTE; accum >>= 8; str++; break; } case '>': /* end recursive eval */ T} { *val = accum; return(++str); } default: str++; }; *val = accum; return(str); } int eval U}(str, expr_flags, sym_ref) char * str; int * expr_flags; struct sym ** sym_ref; { int accum; *expr_flags = 0; V} *sym_ref = (struct sym *)0; eval_internal(str, &accum, expr_flags, sym_ref); #ifdef DEBUG printf("eval('%s')->%X fl W}ags %X sym %X\n", str, accum, *expr_flags, *sym_ref); #endif return(accum); } #ifdef DEBUG printf("eval('%s')->%X fl T /* This software is copyright 1989 by John Dunning. See the file 'COPYLEFT.JRD' for the full copyright notice. */Y} /* defs for the evaluator */ /* these are bits in the 'expr_flags' byte returned from eval */ #define E_UNDEF 1 /Z}* expr contains an undefined sym */ #define E_REL 2 /* expr contains a relative reference */ #define E_HI_BYTE 8 /* hi part[} of some value */ #define E_LO_BYTE 16 /* lo part */ expr contains a relative reference */ #define E_HI_BYTE 8 /* hi part7 /* This software is copyright 1989 by John Dunning. See the file 'COPYLEFT.JRD' for the full copyright notice. */]} /* entry pts for code generator */ extern genlit(); extern genbyte(); extern genword(); extern gen_label(); extern^} gen_n_passes(); or code generator */ extern genlit(); extern genbyte(); extern genword(); extern gen_label(); extern /* This software is copyright 1989 by John Dunning. See the file 'COPYLEFT.JRD' for the full copyright notice. */`} /* global vars for a65 */ #ifdef MAIN #define ID #else #define ID extern #endif ID char line[256]; /* line bufa}fer */ ID struct parse p; /* parsed line */ ID int line_nbr; /* current line number */ ID char * list_name; /* name ob}f file we're listing to, if any */ ID int list_pc; /* pc before read line */ ID char list_pc_p; /* lsit pc even if no obc}ject bytes */ ID char obj[4]; /* generated code */ ID int obj_count; /* n valid bytes */ ID char line_listed_p; /* if d}text this line has been printed */ ID int list_v; /* other value to show up in listing */ ID char list_v_p; /* use that e}instead of obj bytes */ ID char page_title[64]; /* page title string */ ID char page_subttl[64]; /* subtitle */ ID int f}page_nbr; /* page number */ ID int line_in_page; ID int errcount; ID char output_p; /* flag for generating output */ g} /* conditional stuff */ ID char disabled; /* if we've evaluated an IF that was false */ /* global assembler state */h} ID unsigned int pc; /* pc for assembler */ #define SEG_ABS 0 /* we're doing absolute defs */ #define SEG_REL 1 /* i}we're doing relative defs */ ID int curr_seg; /* current state; one of the above values */ ID unsigned int abs_pc, rel_pc;j} /* last known pc, each seg */ ID char rel_p; /* if relocatable output */ ID int pass; /* what pass we're doing */ Ik}D int end_file; /* if we saw a .end pseudo */ ID char list_p; /* generating listing */ ID char verbose; /* various vl}erbosities */ /* if we saw a .end pseudo */ ID char list_p; /* generating listing */ ID char verbose; /* various v /* This software is copyright 1989 by John Dunning. See the file 'COPYLEFT.JRD' for the full copyright notice. */n} /* defs for library files #ifndef _TYPES_ #include "types.h" #endif A library file consists of a header lump, as o}described below, some number of module descriptors, and images of files. magic number identifies library files */ #definp}e LIBR_HEADER 0xFCFC struct librfile { USHORT l_header; /* magic num, as above */ USHORT type; /* type of library, q}values below */ USHORT n_modules; /* number modules this library */ USHORT l_flags; /* library flags, defined below */ r} }; /* library types */ #define LT_OLB 1 /* an object library */ /* flags for object libraries */ #define LOLB_DEF s}0x0001 /* library contains a symbol dictionary */ /* a module of the library */ struct librmod { char m_name[12]; /t}* entry name, typically file name */ USHORT m_nbytes; /* n bytes in entry */ }; uct librmod { char m_name[12]; /X /* This software is copyright 1989 by John Dunning. See the file 'COPYLEFT.JRD' for the full copyright notice. */ v} /* object library maintainer for atari 8-bit .obj files. later, maybe random other kinds of files too. */ #defin w}e VERSION "1.0" #include #include #include #ifdef M6502 /* lots of things in here are d x}efined to use 16-bit values */ #define USHORT int /* other stuff might as well go here */ #define unlink delete #define m y}alloc xmalloc #else #define USHORT unsigned short #endif #include "symtab.h" #include "obj.h" #include "libr.h" z}#ifdef M6502 /* do this part differently on 800 */ #else #include #include /* for _dta, for file size {} */ #endif char * lfname; /* name of the file we've got open */ int in_lfd; /* fd of the file we've got open */ int |} out_lfd; /* fd output, if writing */ int obj_lfd; /* fd for .obj files */ struct librfile lfile; /* header of the f }}ile we've got open */ int input_fd; /* fd of obj files we read */ #ifdef __GNUC__ int _stksize = 16384; #endif / ~}* defs for keeping track of what we're doing when maintaining a library */ /* we build a linked list of these when adding/ }deleting etc. If we were writing this in a real language, we'd do this with included defstructs, but since we must u }se C, we make the first part of this look just like the def of a librmod, in libr.h. */ struct entry { char e_nam }e[12]; /* the file name of this entry */ USHORT e_nbytes; /* nbytes this entry */ struct entry * e_next; /* next entry */ } int new; /* if this is a new entry */ int skip; /* this is an old entry being skipped */ }; #define SKIP_REPLACE }1 #define SKIP_DELETE 2 char * skip_names[] = { "", "Replacing", "Deleting" }; struct entry * lfile_components; } #ifdef M6502 /* debug code */ char * xmalloc(n) int n; { char * foo; foo = pmalloc(n); /* printf("xm }alloc(%d)->%x; sp %x\n", n, foo, &foo); */ bzero(foo, n); return(foo); } #endif /* util routines */ min(x, y) }int x,y; { if (x < y) return(x); else return(y); } #ifndef M6502 unsigned #endif char read8(input_f }d) int input_fd; { #ifdef M6502 unsigned #endif char foo; read(input_fd, &foo, 1); return(foo); } USHORT }read16(input_fd) int input_fd; { return(read8(input_fd) | (read8(input_fd) << 8)); } write8(ch) char ch; { writ }e(out_lfd, &ch, 1); } write16(sh) USHORT sh; { write8(sh & 0xFF); write8(sh >> 8); } int open_carefully(name, } mode, must_exist) char * name; int mode; int must_exist; { int fd; #ifdef M6502 char buf[64]; /* prepend a D: if } necessary */ if (!strchr(name, ':')) { strcpy(buf, "D:"); strcat(buf, name); name = buf; } #endif printf("o }pen('%s', %x)->", name, mode); fd = open(name, mode); if ((fd < 0) && must_exist) barf("Can't open '%s'\n", name); } printf("%d\n", fd); return(fd); } read_header(fd) int fd; { lfile.l_header = read16(fd); lfile.type = read1 }6(fd); lfile.n_modules = read16(fd); lfile.flags = read16(fd); /* #ifdef M6502 printf("read_header: %x %x %x %x\n" }, lfile.l_header, lfile.type, lfile.n_modules, lfile.flags); #endif */ } read_mdesc(fd, mod) int fd; struct librmo }d * mod; { read(fd, mod->m_name, 12); mod->m_nbytes = read16(fd); } /* build the module list for an existing file. } assume the next byte to be read is the first one of the module structs. assume lfile is valid */ build_modlist(f }d) int fd; { int i; struct entry * elt; struct entry * prev_elt; lfile_components = elt = #ifdef M6502 } 0; #else (struct entry * )NULL; #endif for (i = 0 ; i < lfile.n_modules ; i++) { prev_elt = elt; elt = #if }def M6502 malloc(sizeof(struct entry)); #else (struct entry *)malloc(sizeof(struct entry)); #endif read(fd, elt->e_ }name, 12); elt->e_nbytes = read16(fd); /* #ifdef M6502 printf("build_modlist: got name '%s' nbytes %d\n", elt->e_na }me, elt->e_nbytes); #endif */ elt->new = 0; elt->skip = 0; if (prev_elt) prev_elt->e_next = elt; else lfi }le_components = elt; } } string_upcase(str) char * str; { for ( ; *str ; str++) if (islower(*str)) *str = to }upper(*str); } int string_equal(str1, str2) char * str1, * str2; { for ( ; *str1 || *str2 ; str1++, str2++) if (*s }tr1 != *str2) return(0); return(1); } /* not needed? char * string_copy(str) char * str; { char * t = (char * )m }alloc(strlen(str) + 1); strcpy(t, str); return(t); } */ string_pad(target, source, nbytes) char * target; char * } source; int nbytes; { int i; for (i = nbytes ; (i > 0) && (*source) ; i--) *target++ = *source++; for ( ; i } > 0 ; i--) *target++ = ' '; } string_trim(target, source, nbytes) char * target; char * source; int nbytes; { f }or ( ; ((nbytes > 0) && (*source != ' ')) ; nbytes--) *target++ = *source++; *target = '\0'; } /* maintaining entry }list */ struct entry * last_entry() { struct entry * elt; for (elt = lfile_components ; elt && elt->e_next ; el }t = elt->e_next) ; return(elt); } /* delete an entry. return 1 if found it */ int del_entry(name, why) char * n }ame; int why; { struct entry * elt; char buf[80]; int found; found = 0; string_upcase(name); for (elt = } lfile_components ; elt ; ) { string_trim(buf, elt->e_name, 12); if (string_equal(name, buf)) { /* set skip bit i }n this one; we always add new entries at the end */ elt->skip = why; found++; } if (elt) elt = elt->e_ne }xt; } return(found); } /* return 1 if replaced old entry */ int add_entry(name, nbytes) char * name; int nbytes; } { struct entry * elt; struct entry * prev_elt; int replaced; char buf[14]; prev_elt = #ifdef M6502 NUL }L; #else (struct entry *)NULL; #endif replaced = del_entry(name, SKIP_REPLACE); prev_elt = last_entry(); /* n }ow make the new one */ elt = #ifdef M6502 malloc(sizeof(struct entry)); #else (struct entry *)malloc(sizeof(struct }entry)); #endif #ifdef M6502 /* dump drivespec if any */ { char * p; if (p = strchr(name, ':')) } name = p + 1; } #endif /* elt->e_name = string_copy(name); */ string_pad(elt->e_name, name, 12); elt->new = 1; } /* get this from file, not libr */ elt->e_nbytes = nbytes; if (prev_elt) prev_elt->e_next = elt; else lfil }e_components = elt; return(replaced); } /* on 800, this will have to read and count the whole file, unless we're u }sing Spartados */ int file_nbytes(name) char * name; { #ifdef M6502 char buf[64]; int fd; int siz, total; } fd = open_carefully(name, O_RDONLY, 1); for (total = 0 ; ((siz = read(fd, buf, 64)) > 0) ; ) total += siz; printf("c }lose->%x\n", close(fd)); printf("%s is %d bytes long\n", name, total); return(total); #else struct stat st; }if (stat(name, &st) < 0) return(-1); else return(st.st_size); #endif } /* zzz */ #ifdef M6502 barf() { }int * arg; arg = &arg; /* point at self */ arg += arg[1] + 1; /* add next word; arg count, plus 1 */ fprintf(st }derr, *arg, *--arg, *--arg, *--arg); fprintf(stderr, "\n"); exit(1); } #else barf(msg, arg1, arg2, arg3) { fpr }intf(stderr, msg, arg1, arg2, arg3); fprintf(stderr, "\n"); exit(1); } #endif /* open libr and generate the initia }l components list */ read_library(must_exist) int must_exist; { int i; lfile_components = #ifdef M6502 NULL; } #else (struct entry * )NULL; #endif in_lfd = open_carefully(lfname, O_RDONLY, must_exist); /* #ifdef M6502 pri }ntf("read_lib: fd %x\n", fd); #endif */ if (in_lfd > 0) /* open it ok? */ { read_header(in_lfd); /* read header * }/ build_modlist(in_lfd); return; } else { if (must_exist) barf("Can't open %s", lfname); else { } fprintf(stderr, "Creating library %s\n", lfname); in_lfd = 0; lfile_components = (struct entry * )NULL; } } } } /* using the components_list, write a new library */ write_library() { struct entry * elt; int copy_lfd; char b }uf[64]; int size; out_lfd = open_carefully("libr65.tmp", O_WRONLY | O_CREAT | O_TRUNC, 0); lfile.l_header }= LIBR_HEADER; lfile.type = LT_OLB; /* fixed, for now */ lfile.flags = 0; /* refresh module count */ lfile.n_modul }es = 0; for (elt = lfile_components ; elt ; elt = elt->e_next) if (!elt->skip) /* not skipping this one? */ lfile }.n_modules++; /* then count it */ /* write the header */ write16(lfile.l_header); write16(lfile.type); write16(lf }ile.n_modules); write16(lfile.flags); /* write the dictionary */ for (elt = lfile_components ; elt ; elt = elt->e_ne }xt) if (!elt->skip) { write(out_lfd, elt->e_name, 12); write16(elt->e_nbytes); } /* write the modules themse }lves */ for (elt = lfile_components ; elt ; elt = elt->e_next) { string_trim(buf, elt->e_name, 12); if (elt->skip) } { /* skip this entry in the original library */ fprintf(stderr, "%s %s\n", skip_names[elt->skip], buf); size = elt }->e_nbytes; for ( ; size > 0 ; size -= 64) read(in_lfd, buf, min(size, 64)); } else { if (elt->new) } { /* new file. open the obj file */ fprintf(stderr, "Adding %s\n", buf); obj_lfd = open_carefully(buf, O_RDONLY }, 1); copy_lfd = obj_lfd; } else { fprintf(stderr, "Copying %s\n", buf); copy_lfd = in_lfd; } } /* run the copy loop */ for (size = elt->e_nbytes ; size > 0 ; size -= 64) { read(copy_lfd, buf, min(size, 64)) }; write(out_lfd, buf, min(size, 64)); } /* if have an obj file open, close it */ if (obj_lfd > 0) { clo }se(obj_lfd); obj_lfd = 0; } } } /* copy writing. close libr file */ close(out_lfd); printf("closing in }_lfd %d\n", in_lfd); if (in_lfd > 0) close(in_lfd); printf("del '%s'->%x\n", lfname, unlink(lfname)); printf("re }n '%s','%s'->%x\n", "libr65.tmp", lfname, rename("libr65.tmp", lfname)); out_lfd = 0; printf("New library written\n" }); } /* routines to really do things */ add_files(argc, argv) int argc; char ** argv; { int i, nbytes, found; } if (argc <= 3) barf("Add what files?"); found = 0; read_library(0); /* read the library */ for (i = 3 ; i < } argc ; i++) { nbytes = file_nbytes(argv[i]); if (nbytes < 0) fprintf(stderr, "%s not found", argv[i]); else } { found++; add_entry(argv[i], nbytes); } } if (found = 0) fprintf(stderr, "No files added"); else wr }ite_library(); printf("Finished adding files\n"); } /* delete some library members */ del_files(argc, argv) int argc }; char ** argv; { struct entry * elt; int i, deleted; if (argc <= 3) barf("Delete what files?"); read_lib }rary(1); for (i = 3, deleted = 0 ; i < argc ; i++) if (del_entry(argv[i], SKIP_DELETE)) deleted++; else fpri }ntf(stderr, "Library contains no member %s\n", argv[i]); if (deleted) write_library(); else fprintf(stderr, "No m }embers matched"); close(in_lfd); } list_library() { struct entry * elt; char buf[80]; int i; read_li }brary(1); close(in_lfd); strcpy(buf, lfname); string_upcase(buf); printf(" Library %s\n", buf); printf(" --- }--------- -----\n"); for (elt = lfile_components ; elt ; elt = elt->e_next) { buf[12] = '\0'; for (i = 0 ; i < 12 ; } i++) { buf[i] = elt->e_name[i]; /* printf("idx %d chr %c buf '%s'\n", i, elt->e_name[i], buf); */ } printf(" }%12s %5d\n", buf, elt->e_nbytes); } } print_version() { printf("Libr65 v %s\n", VERSION); } /* main body */ } #ifdef M6502 char cmdline[80]; #endif main(argc, argv) int argc; char ** argv; { char op; /* what we're doing t }o a file */ #ifdef M6502 /* might not be able to get cmd line from os, so prompt for it */ if (argc == 0) argc = rea }dargs("LIBR65>", cmdline, argv + 1) + 1; #endif if (argc < 3) barf("Try LIBR65