@@ 1,39 1,36 @@
-/* Lin6
- Version 1.2
+/*
+ Lin6
+ Version 1.3
https://wiki.xxiivv.com/lin6
-*/
-/* Rules:
Variable names must always be lowercase.
+ Variable names are always padded to tab1.
Variable length are always padded to col25.
Variable comments are always padded to col32.
Constant names must always be uppercase.
+ Constant names are always padded to tab1.
Constant length are always padded to col21.
Constant comments are always padded to col32.
Label names must always be capitalized.
- Label names aalways end with :.
+ Label names always end with :.
Label names are always preceeded with a linebreak.
Label comments are never padded.
- Directive names are always padded to col2.
+ Directive names are always padded to tab1.
+ Directive names are always lowercase.
Directive comments are never padded.
Opcode names are always uppercase.
- Opcode names are always padded to col2.
+ Opcode names are always padded to tab1.
Opcode comments are always padded to col32.
- Inline comments are always padded to col2.
+ Inline comments are always padded to tab1.
Spacing comments are always preceeded and followed with a linebreak.
*/
-#include <ctype.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#define VERSION "1.2"
+#define VERSION "1.3"
#define BUFLEN 512
-typedef enum { false, true } bool;
-
-char *OPCODES[] = {"ADC", "AND", "ASL", "BCC", "BCS", "BEQ", "BIT", "BMI",
+char* OPCODES[] = {"ADC", "AND", "ASL", "BCC", "BCS", "BEQ", "BIT", "BMI",
"BNE", "BPL", "BRK", "BVC", "BVS", "CLC", "CLD", "CLI",
"CLV", "CMP", "CPX", "CPY", "DEC", "DEX", "DEY", "EOR",
"INC", "INX", "INY", "JMP", "JSR", "LDA", "LDX", "LDY",
@@ 41,410 38,397 @@ char *OPCODES[] = {"ADC", "AND", "ASL", "BCC", "BCS", "BEQ", "BIT", "BMI",
"ROR", "RTI", "RTS", "SBC", "SEC", "SED", "SEI", "STA",
"STX", "STY", "TAX", "TAY", "TSX", "TXA", "TXS", "TYA"};
-void substr(char *src, char *dest, int from, int to) {
- memcpy(dest, src + from, to);
- dest[to] = '\0';
-}
-
-void trimstr(char *src, char *dest) {
- /* leading whitespace */
- int a, b, len = strlen(src) + 1;
- for (a = 0; a < len; a++) {
- if (src[a] != ' ' && src[a] != '\t') {
- break;
- }
- }
- /* traling whitespace */
- for (b = 2; b < len; b++) {
- if (src[len - b] != ' ' && src[len - b] != '\n') {
- break;
- }
- }
- substr(src, dest, a, len - b - a + 1);
-}
-
-void fillstr(char *src, int limit, char c) {
- int i, len = strlen(src);
- for (i = len; i < limit; i++) {
- src[i] = c;
- }
- src[limit] = '\0';
-}
-
-void swapcstr(char *src, char a, char b) {
- int i, len = strlen(src);
- for (i = 0; i < len; i++) {
- src[i] = src[i] == a ? b : src[i];
- }
-}
-
-void cpystr(char *src, char *dest) {
- int i, len = strlen(src);
- for (i = 0; i < len; i++) {
- dest[i] = src[i];
- }
- dest[len] = '\0';
-}
-
-void ucstr(char *src) {
- int i, len = strlen(src);
- for (i = 0; i < len; i++) {
- src[i] = toupper(src[i]);
- }
-}
-
-void lcstr(char *src) {
- int i, len = strlen(src);
- for (i = 0; i < len; i++) {
- src[i] = tolower(src[i]);
- }
-}
-
-int index_of_comment(char *src) {
- int i, len = strlen(src);
- for (i = 0; i < len; i++) {
- if (src[i] == ';') {
- return i;
- }
- }
- return -1;
-}
-
-bool opcode_exists(char *opcode) {
- int i;
- for (i = 0; i < 56; i++) {
- if (strcmp(OPCODES[i], opcode) == 0) {
- return true;
- }
- }
- return false;
-}
-
-bool file_exists(char *filename) {
- FILE *file = fopen(filename, "r");
- if (file != NULL) {
- fclose(file);
- return true;
- }
- return false;
-}
-
-void set_line_key(char *src, char *dest) {
- int i, len = strlen(src);
- for (i = 0; i < len; i++) {
- if (src[i] == ' ') {
- break;
- }
- }
- substr(src, dest, 0, i);
- trimstr(dest, dest);
-}
-
-void set_line_value(char *src, char *dest) {
- bool step = false;
- int i, comment = index_of_comment(src), len = strlen(src);
- if (comment > -1) {
- len = comment;
- }
- for (i = 0; i < len; i++) {
- if (src[i] != ' ' && step == true) {
- break;
- } else if (src[i] == ' ') {
- step = true;
- }
- }
- substr(src, dest, i, len - i);
- trimstr(dest, dest);
-}
-
-void set_line_comment(char *src, char *dest) {
- int i, len = strlen(src);
- for (i = 0; i < len; i++) {
- if (src[i] == ';') {
- break;
- }
- }
- substr(src, dest, i, len - i);
- trimstr(dest, dest);
-}
-
-bool has_comment(char *line) {
- int i, len = strlen(line);
- for (i = 0; i < len; i++) {
- if (line[i] == ';') {
- return true;
- }
- }
- return false;
-}
-
-bool is_capital(char *str) { return str[0] == toupper(str[0]); }
-
-bool is_lower(char *str) {
- int i, len = strlen(str);
- for (i = 0; i < len; i++) {
- if (str[i] != tolower(str[i])) {
- return false;
- }
- }
- return true;
-}
-
-bool is_upper(char *str) {
- int i, len = strlen(str);
- for (i = 0; i < len; i++) {
- if (str[i] != toupper(str[i])) {
- return false;
- }
- }
- return true;
-}
-
-bool is_label(char *line) {
- int i, len = strlen(line);
- for (i = 0; i < len; i++) {
- if (line[i] == ' ' || line[i] == ';') {
- return false;
- }
- if (line[i] == ':') {
- return true;
- }
- }
- return false;
-}
-
-bool is_opcode(char *line) {
- char opcode[4];
- substr(line, opcode, 0, 3);
- ucstr(opcode);
- return opcode_exists(opcode);
-}
-
-bool is_directive(char *line) { return line[0] == '.'; }
-
-bool is_spacer_comment(char *line) { return line[0] == ';' && line[1] == ';'; }
-
-bool is_inline_comment(char *line) { return line[0] == ';' && line[1] == ' '; }
-
-bool is_variable(char *line) {
- int i, len = strlen(line);
- for (i = 0; i < len; i++) {
- if (line[i] == '.' && line[i + 1] == 'd' && line[i + 2] == 's' &&
- line[i + 3] == 'b') {
- return true;
- }
- }
- return false;
-}
-
-bool is_constant(char *line) {
- int i, len = strlen(line);
- for (i = 0; i < len; i++) {
- if (line[i] == '.' && line[i + 1] == 'e' && line[i + 2] == 'q' &&
- line[i + 3] == 'u') {
- return true;
- }
- }
- return false;
-}
-
-void save(char *filepath, char *output, bool do_inplace) {
- if (do_inplace) {
- FILE *fw = fopen(filepath, "w");
- fprintf(fw, "%s", output);
- fclose(fw);
- } else {
- printf("%s\n", output);
- }
-}
-
-void lint(char *filepath, char *output, bool do_debug) {
- FILE *fr = fopen(filepath, "r");
- int id = 0, len, count = 0, opcodes = 0, directives = 0, spacers = 0,
- labels = 0, variables = 0, constants = 0, comments = 0;
- bool skipped_last = false;
- char line[BUFLEN];
- char trimed[BUFLEN];
- while (fgets(line, BUFLEN, fr)) {
- id++;
- trimstr(line, trimed);
- swapcstr(trimed, '\t', ' ');
- len = strlen(trimed);
- if (len < 3) {
- continue;
- }
- if (is_label(trimed)) {
- char key[BUFLEN];
- char comment[BUFLEN];
- set_line_key(trimed, key);
- set_line_comment(trimed, comment);
- if (!is_capital(key)) {
- printf("Lin6: Label %s not capitalized, at %s:%d.\n", key, filepath,
- id);
- }
- if (key[0] != '@' && !skipped_last) {
- strcat(output, "\n");
- }
- if (has_comment(line)) {
- strcat(output, key);
- strcat(output, " ");
- strcat(output, comment);
- } else {
- strcat(output, key);
- }
- skipped_last = false;
- labels++;
- } else if (is_opcode(trimed)) {
- char key[BUFLEN];
- char value[BUFLEN];
- char comment[BUFLEN];
- set_line_key(trimed, key);
- set_line_value(trimed, value);
- set_line_comment(trimed, comment);
- ucstr(key);
- strcat(output, "\t");
- strcat(output, key);
- strcat(output, " ");
- if (has_comment(line)) {
- fillstr(value, 24, ' ');
- strcat(output, value);
- strcat(output, " ");
- strcat(output, comment);
- } else {
- strcat(output, value);
- }
- skipped_last = false;
- opcodes++;
- } else if (is_directive(trimed)) {
- char key[BUFLEN];
- char value[BUFLEN];
- char comment[BUFLEN];
- set_line_key(trimed, key);
- set_line_value(trimed, value);
- set_line_comment(trimed, comment);
- strcat(output, "\t");
- strcat(output, key);
- strcat(output, " ");
- if (has_comment(line)) {
- strcat(output, value);
- strcat(output, " ");
- strcat(output, comment);
- } else {
- strcat(output, value);
- }
- skipped_last = false;
- directives++;
- } else if (is_inline_comment(trimed)) {
- strcat(output, "\t");
- strcat(output, trimed);
- skipped_last = false;
- comments++;
- } else if (is_spacer_comment(trimed)) {
- strcat(output, "\n");
- strcat(output, trimed);
- strcat(output, "\n");
- skipped_last = true;
- spacers++;
- } else if (is_variable(trimed)) {
- char key[BUFLEN];
- char value[BUFLEN];
- char comment[BUFLEN];
- set_line_key(trimed, key);
- set_line_value(trimed, value);
- set_line_comment(trimed, comment);
- fillstr(key, 24, ' ');
- if (!is_lower(key)) {
- printf("Lin6: Variable %s not lowercase, at %s:%d.\n", key, filepath,
- id);
- }
- strcat(output, key);
- strcat(output, value);
- strcat(output, " ");
- strcat(output, comment);
- skipped_last = false;
- variables++;
- } else if (is_constant(trimed)) {
- char key[BUFLEN];
- char value[BUFLEN];
- char comment[BUFLEN];
- set_line_key(trimed, key);
- set_line_value(trimed, value);
- set_line_comment(trimed, comment);
- fillstr(key, 20, ' ');
- if (!is_upper(key)) {
- printf("Lin6: Constant %s not uppercase, at %s:%d.\n", key, filepath,
- id);
- }
- strcat(output, key);
- strcat(output, value);
- strcat(output, " ");
- strcat(output, comment);
- skipped_last = false;
- constants++;
- } else {
- printf("Lin6: Unknown line-type, at %s:%d.\n", filepath, id);
- strcat(output, line);
- }
- strcat(output, "\n");
- count++;
- }
- if (do_debug) {
- printf("Lin6 debug: %d lines: \n", count);
- printf("\t%d labels\n", labels);
- printf("\t%d opcodes\n", opcodes);
- printf("\t%d directives\n", directives);
- printf("\t%d spacers\n", spacers);
- printf("\t%d variables\n", variables);
- printf("\t%d constants\n", constants);
- }
- fclose(fr);
-}
-
-void show_version(void) { puts("Lin6 " VERSION); }
-
-void show_help(void) {
- show_version();
- puts("");
- puts("A tool to format 6502 assembly code.\n");
- puts("Usage: Lin6 [-options] [<file> ...]\n");
- puts("\t-?\tShow this help");
- puts("\t-v\tShow version");
- puts("\t-i\tInplace edit files");
- puts("\t-d\tShow debug\n");
- puts("See README for more info.\n");
-}
-
-int main(int argc, char *argv[]) {
- bool do_debug = false, do_inplace = false;
- int i;
- if (argc < 2) {
- show_help();
- exit(0);
- }
- for (i = 1; i < argc; i++) {
- if (argv[i][1] == '?') {
- show_help();
- exit(0);
- } else if (argv[i][1] == 'v') {
- show_version();
- exit(0);
- }
- /* read flags */
- if (argv[i][1] == 'd') {
- do_debug = true;
- } else if (argv[i][1] == 'i') {
- do_inplace = true;
- }
- /* do files */
- else {
- char linted[51200];
- if (!file_exists(argv[i])) {
- printf("Lin6: File %s not found\n", argv[i]);
- exit(0);
- }
- lint(argv[i], linted, do_debug);
- save(argv[i], linted, do_inplace);
- }
- }
- return 0;
-}>
\ No newline at end of file
+int skipped = 0;
+
+int
+cisp(char c)
+{
+ return c == ' ' || c == '\t' || c == '\n' || c == '\r';
+}
+
+int
+clca(int c)
+{
+ return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
+}
+
+int
+cuca(char c)
+{
+ return c >= 'a' && c <= 'z' ? c - ('a' - 'A') : c;
+}
+
+int
+ciuc(char c)
+{
+ return c == cuca(c);
+}
+
+int
+cilc(char c)
+{
+ return c == clca(c);
+}
+
+char*
+sstr(char* src, char* dest, int from, int to)
+{
+ int i;
+ char *a = (char*)src + from, *b = (char*)dest;
+ for(i = 0; i < to; i++)
+ b[i] = a[i];
+ dest[to] = '\0';
+ return dest;
+}
+
+int
+slen(char* s)
+{
+ int n = 0;
+ while(s[n] != '\0' && s[++n])
+ ;
+ return n;
+}
+
+int
+silc(char* s)
+{
+ int i;
+ for(i = 0; i < slen(s); i++)
+ if(!cilc(s[i]))
+ return 0;
+ return 1;
+}
+
+int
+siuc(char* s)
+{
+ int i;
+ for(i = 0; i < slen(s); i++)
+ if(!ciuc(s[i]))
+ return 0;
+ return 1;
+}
+
+int
+cpos(char* s, char c)
+{
+ int i;
+ for(i = 0; i < slen(s); i++)
+ if(s[i] == c)
+ return i;
+ return -1;
+}
+
+char*
+scat(char* dest, const char* src)
+{
+ char* ptr = dest + slen(dest);
+ while(*src != '\0')
+ *ptr++ = *src++;
+ *ptr = '\0';
+ return dest;
+}
+
+int
+scmp(char* a, char* b)
+{
+ int i, l = slen(a);
+ if(l != slen(b))
+ return 0;
+ for(i = 0; i < l; ++i)
+ if(a[i] != b[i])
+ return 0;
+ return 1;
+}
+
+char*
+suca(char* s)
+{
+ int i;
+ for(i = 0; i < slen(s); i++)
+ s[i] = cuca(s[i]);
+ return s;
+}
+
+char*
+slca(char* s)
+{
+ int i;
+ for(i = 0; i < slen(s); i++)
+ s[i] = clca(s[i]);
+ return s;
+}
+
+char*
+strm(char* s)
+{
+ char* end;
+ while(cisp(*s))
+ s++;
+ if(*s == 0)
+ return s;
+ end = s + slen(s) - 1;
+ while(end > s && cisp(*end))
+ end--;
+ end[1] = '\0';
+ return s;
+}
+
+int
+spos(char* a, char* b)
+{
+ int i, j, alen = slen(a), blen = slen(b);
+ for(i = 0; i < alen; i++) {
+ for(j = 0; j < blen; j++) {
+ if(a[i + j] == '\0')
+ return -1;
+ if(a[i + j] != b[j])
+ break;
+ if(j == blen - 1)
+ return i;
+ }
+ }
+ return -1;
+}
+
+char*
+scpy(char* src, char* dest)
+{
+ int i = 0;
+ while((dest[i] = src[i]) != '\0')
+ i++;
+ return dest;
+}
+
+/* old */
+
+void
+setkey(char* src, char* dst)
+{
+ sstr(src, dst, 0, cpos(src, ' ') > 0 ? cpos(src, ' ') : slen(src));
+}
+
+void
+setval(char* src, char* dst)
+{
+ int step = 0, i, comment = cpos(src, ';'), len = slen(src);
+ if(comment > -1)
+ len = comment;
+ for(i = 0; i < len; i++) {
+ if(src[i] != ' ' && step == 1)
+ break;
+ else if(src[i] == ' ')
+ step = 1;
+ }
+ sstr(src, dst, i, len - i);
+ scpy(strm(dst), dst);
+}
+
+void
+setcmt(char* src, char* dst)
+{
+ if(cpos(src, ';') > 0)
+ sstr(src, dst, cpos(src, ';'), slen(src) - cpos(src, ';'));
+ else
+ scpy("", dst);
+ scpy(strm(dst), dst);
+}
+
+int
+islabel(char* line)
+{
+ int i;
+ for(i = 0; i < slen(line); i++) {
+ if(line[i] == ' ' || line[i] == ';')
+ return 0;
+ if(line[i] == ':')
+ return 1;
+ }
+ return 0;
+}
+
+int
+isopcode(char* line)
+{
+ int i;
+ char opcode[4];
+ suca(sstr(line, opcode, 0, 3));
+ for(i = 0; i < 56; i++)
+ if(scmp(OPCODES[i], opcode))
+ return 1;
+ return 0;
+}
+
+int
+iscomment(char* line)
+{
+ return line[0] == ';';
+}
+
+int
+isdirective(char* line)
+{
+ return line[0] == '.';
+}
+
+int
+isvariable(char* line)
+{
+ return spos(line, ".dsb") > 0;
+}
+
+int
+isconstant(char* line)
+{
+ return spos(line, ".equ") > 0;
+}
+
+void
+dolabel(char* src)
+{
+ char key[BUFLEN], cmt[BUFLEN];
+ setkey(src, key);
+ setcmt(src, cmt);
+ key[0] = cuca(key[0]);
+ if(key[0] == '@' || skipped)
+ printf("%s %s\n", key, cmt);
+ else
+ printf("\n%s %s\n", key, cmt);
+ skipped = 0;
+}
+
+void
+doopcode(char* src)
+{
+ char key[BUFLEN], val[BUFLEN], cmt[BUFLEN];
+ setkey(src, key);
+ suca(key);
+ setval(src, val);
+ setcmt(src, cmt);
+ if(slen(cmt) > 1)
+ printf("\t%s %-30s %s\n", key, val, cmt);
+ else
+ printf("\t%s %s\n", key, val);
+ skipped = 0;
+}
+
+void
+docomment(char* src)
+{
+ if(src[0] == src[1]) {
+ printf("\n%s\n\n", src);
+ skipped = 1;
+ } else {
+ printf("\t%s\n", src);
+ skipped = 0;
+ }
+}
+
+void
+dodirective(char* src)
+{
+ char key[BUFLEN], val[BUFLEN], cmt[BUFLEN];
+ setkey(src, key);
+ slca(key);
+ setval(src, val);
+ setcmt(src, cmt);
+ if(slen(cmt) > 1)
+ printf("\t%s %-28s %s\n", key, val, cmt);
+ else
+ printf("\t%s %s %s\n", key, val, cmt);
+ skipped = 0;
+}
+
+void
+dovariable(char* src)
+{
+ char key[BUFLEN], val[BUFLEN], cmt[BUFLEN];
+ setkey(src, key);
+ slca(key);
+ setval(src, val);
+ setcmt(src, cmt);
+ printf("\t%-23s %-10s %s\n", key, val, cmt);
+ skipped = 0;
+}
+
+void
+doconstant(char* src)
+{
+ char key[BUFLEN], val[BUFLEN], cmt[BUFLEN];
+ setkey(src, key);
+ suca(key);
+ setval(src, val);
+ setcmt(src, cmt);
+ printf("\t%-23s %-10s %s\n", key, val, cmt);
+ skipped = 0;
+}
+
+/* IO */
+
+void
+lint(FILE* f)
+{
+ char line[BUFLEN], trimed[BUFLEN];
+ while(fgets(line, BUFLEN, f)) {
+ scpy(strm(line), trimed);
+ if(slen(trimed) < 3)
+ continue;
+ if(islabel(trimed))
+ dolabel(trimed);
+ else if(isopcode(trimed))
+ doopcode(trimed);
+ else if(iscomment(trimed))
+ docomment(trimed);
+ else if(isdirective(trimed))
+ dodirective(trimed);
+ else if(isvariable(trimed))
+ dovariable(trimed);
+ else if(isconstant(trimed))
+ doconstant(trimed);
+ else
+ printf("%s\n", line);
+ }
+ fclose(f);
+}
+
+int
+version(void)
+{
+ puts("Lin6 " VERSION);
+ return 0;
+}
+
+int
+help(void)
+{
+ version();
+ puts("");
+ puts("A tool to format 6502 assembly code.\n");
+ puts("Usage: Lin6 [-options] [<file> ...]\n");
+ puts("\t-?\tShow this help");
+ puts("\t-v\tShow version");
+ puts("See README for more info.\n");
+ return 0;
+}
+
+int
+main(int argc, char* argv[])
+{
+ FILE* f;
+ int i;
+ if(argc < 2)
+ return help();
+ for(i = 1; i < argc; i++) {
+ if(argv[i][1] == '?')
+ return help();
+ else if(argv[i][1] == 'v')
+ return version();
+ else {
+ f = fopen(argv[i], "r");
+ if(f != NULL)
+ lint(f);
+ }
+ }
+ return 0;
+}