/*cstrong.c - output an help file given a module defn*/ /*OSLib---efficient, type-safe, transparent, extensible,\n" register-safe A P I coverage of RISC O S*/ /*Copyright © 1994 Jonathan Coxhead*/ /* OSLib is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. OSLib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this programme; if not, write to the Free Software Foundation, Inc, 675 Mass Ave, Cambridge, MA 02139, U S A. */ /*From CLib*/ #include #include #include #include #include /* TV 990127 */ /*From OSLib*/ #include "macros.h" #include "os.h" #include "osfile.h" #include "territory.h" /*From Support*/ #include "lookup.h" #include "trace.h" /*local*/ #include "def.h" #include "cstrong.h" #define TRUNCATION_LIMIT 19 typedef struct cstrong_entry { int name; int page; int size; bits flags; } cstrong_entry; static int Entry_Count, String_Offset, Data_Offset; static cstrong_entry Entries [3000]; static char *Strings [3000]; /*Creates a new record in the array of index entries, preparatory to writing the index file.*/ static void index_entry ( FILE *help_data, char *entry ) { int file_offset; tracef ("index_entry (0x%X)\n" _ entry); tracef ("entry -> \"%s\"\n" _ entry); file_offset = (int) ftell (help_data); Strings [Entry_Count] = qstrdup (entry); Entries [Entry_Count].name = String_Offset; Entries [Entry_Count].page = Data_Offset; Entries [Entry_Count].size = file_offset - Data_Offset; Entries [Entry_Count].flags = 0; Data_Offset = file_offset; String_Offset += strlen (Strings [Entry_Count]) + 1; Entry_Count++; } static int Cmp ( void const *v0, void const *v1 ) { cstrong_entry *e0 = (cstrong_entry *) v0, *e1 = (cstrong_entry *) v1; int i0, i1, len, cmp; char *cc, *s0, *s1; /*This is silly, but what we do is count along the strings until we get to the one whose offset is the one we have. It would be faster to build an indirection table, but ...*/ for (i0 = 0, len = 0; len != e0->name; len += strlen (Strings [i0++]) + 1) ; for (i1 = 0, len = 0; len != e1->name; len += strlen (Strings [i1++]) + 1) ; /*Before comparison, convert the string to lower case.*/ for (cc = s0 = qstrdup (Strings [i0]); *cc != '\0'; cc++) *cc = tolower (*cc); for (cc = s1 = qstrdup (Strings [i1]); *cc != '\0'; cc++) *cc = tolower (*cc); cmp = strcmp (s0, s1); free (s0); free (s1); return cmp; } /*Prints a declaration of |v| as an object of type |t|, using |tag| as the structure tag.*/ static int Print_Decl ( char *title, FILE *file, def_t t, char *tag, char *v, bool var, int nest ) { int rc = 0; switch (t->tag) { case def_TYPE_INT: if ((rc = fprintf (file, v == NULL? "int": "int %s", v)) < 0) goto finish; break; case def_TYPE_SHORT: if ((rc = fprintf (file, v == NULL? "short": "short %s", v)) < 0) goto finish; break; case def_TYPE_BYTE: if ((rc = fprintf (file, v == NULL? "byte": "byte %s", v)) < 0) goto finish; break; case def_TYPE_CHAR: if ((rc = fprintf (file, v == NULL? "char": "char %s", v)) < 0) goto finish; break; case def_TYPE_BITS: if ((rc = fprintf (file, v == NULL? "bits": "bits %s", v)) < 0) goto finish; break; case def_TYPE_BYTES: if ((rc = fprintf (file, v == NULL? "bytes": "bytes %s", v)) < 0) goto finish; break; case def_TYPE_BOOL: if ((rc = fprintf (file, v == NULL? "bool": "bool %s", v)) < 0) goto finish; break; case def_TYPE_REF: { char v1 [def_ID_LIMIT + 1]; if (v == NULL || v [0] == '/') { if (v != NULL) { if ((rc = sprintf (v1, "*%s", v)) < 0) goto finish; } else { if ((rc = sprintf (v1, "*")) < 0) goto finish; } } else { if ((rc = sprintf (v1, "*%s", v)) < 0) goto finish; } if ((rc = Print_Decl (title, file, t->data AS ref, NULL, v1, FALSE, nest + 1)) < 0) goto finish; } break; case def_TYPE_STRING: if ((rc = fprintf (file, "char %s", v)) < 0) goto finish; /*v != NULL*/ break; case def_TYPE_ASM: if ((rc = fprintf (file, "void %s", v)) < 0) goto finish; /*v != NULL*/ break; case def_TYPE_DATA: if ((rc = fprintf (file, "byte %s", v)) < 0) goto finish; /*v != NULL*/ break; case def_TYPE_STRUCT: case def_TYPE_UNION: { int i; if ( ( rc = tag != NULL? fprintf ( file, "%s %s\n%*s{ ", t->tag == def_TYPE_STRUCT? "struct": t->tag == def_TYPE_UNION? "union": "list", tag, 21 + 3*nest, " " ): fprintf ( file, "%s\n%*s{ ", t->tag == def_TYPE_STRUCT? "struct": t->tag == def_TYPE_UNION? "union": "list", 21 + 3*nest, " " ) ) < 0 ) goto finish; if (t->tag == def_TYPE_STRUCT && t->data AS list.base) { char base [def_ID_LIMIT + 1]; def_as_macro (base, t->data AS list.base->data AS id); if ((rc = fprintf (file, "%s_MEMBERS\n%*s ", base, 21 + 3*nest, " ")) < 0) goto finish; } for (i = 0; i < t->data AS list.count; i++) { if (i == t->data AS list.count - 1 && t->tag == def_TYPE_STRUCT && t->data AS list.ellipsis) { char v1 [def_ID_LIMIT + 1]; if ((rc = sprintf (v1, t->data AS list.members [i]->name [0] == '*'? "(%s) [%s]": "%s [%s]", t->data AS list.members [i]->name, !var? "...": "N")) < 0) goto finish; if ((rc = Print_Decl (title, file, t->data AS list.members [i], NULL, v1, FALSE, nest + 1)) < 0) goto finish; } else if ((rc = Print_Decl (title, file, t->data AS list.members [i], NULL, t->data AS list.members [i]->name, FALSE, nest + 1)) < 0) goto finish; if ((rc = fprintf (file, ";\n%*s", 21 + 3*nest, " ")) < 0) goto finish; if (i != t->data AS list.count - 1) if ((rc = fprintf (file, " ")) < 0) goto finish; } if ((rc = fprintf (file, "}\n%*s%s", 21 + 3*nest, " ", v)) < 0) goto finish; } break; case def_TYPE_ROW: { char v1 [def_ID_LIMIT + 1]; if (v == NULL || v [0] == '/') if (v != NULL) { if ((rc = sprintf (v1, "%s [%d]", v, t->data AS row.count)) < 0) goto finish; } else { if ((rc = sprintf (v1, "[%d]", t->data AS row.count)) < 0) goto finish; } else if ((rc = sprintf (v1, v [0] == '*'? "(%s) [%d]": "%s [%d]", v, t->data AS row.count)) < 0) goto finish; if ((rc = Print_Decl (title, file, t->data AS row.base, NULL, v1, FALSE, nest + 1)) < 0) goto finish; } break; case def_TYPE_VOID: if ((rc = fprintf (file, v == NULL? "void": "void %s", v)) < 0) goto finish; break; case def_TYPE_ID: { char c_name [def_ID_LIMIT + 1], *ul; def_as_extern (c_name, t->data AS id); if (strncmp (c_name, title, strlen (title)) == 0) { /*Type name is of the form <other stuff>, so this will definitely work. Note that we don't require an underscore - this means that type names of the form <title><prefix>_<name> are assumed to be defined locally.*/ if ((rc = fprintf (file, v == NULL? "<%s>": "<%s> %s", c_name, v)) < 0) goto finish; } else if ((ul = strchr (c_name, '_')) != NULL) { /*Type name is not one of ours, but it has an underscore in it: assume it comes from a module called whatever its prefix is.*/ if ((rc = fprintf (file, v == NULL? "<%s=>%.*s.%s>": "<%s=>%.*s.%s> %s", c_name, MIN (ul - c_name, 10), c_name, c_name, v)) < 0) goto finish; } else { /*We have no idea. It's probably 'void'.*/ if ((rc = fprintf (file, v == NULL? "%s": "%s %s", c_name, v)) < 0) goto finish; } } break; } finish: return rc; } os_error *cstrong_output ( char *output, char *title, char *author, lookup_t needses, lookup_t consts, lookup_t types, lookup_t swis ) { os_error *error = NULL; char *cnst, *type, *swi; def_c c; def_t t; def_s s; char c_name [def_ID_LIMIT + 1], c_title [def_ID_LIMIT + 1], data_name [FILENAME_MAX + 1], index_name [FILENAME_MAX + 1]; void *context; int rc = 0, i; FILE *index = NULL, *help_data = NULL; NOT_USED (author) NOT_USED (needses) def_as_extern (c_title, title); /*Ensure the directory exists.*/ if ((error = xosfile_create_dir (output, 0)) != NULL) goto finish; if ((rc = sprintf (data_name, "%s.%s", output, "HelpData")) < 0) goto finish; if ((help_data = fopen (data_name, "wb")) == NULL) { rc = -1; goto finish; } Entry_Count = 0; Data_Offset = 0; String_Offset = 0; /*Emit the TYPE declarations.*/ context = 0; while (TRUE) { if ((error = lookup_enumerate (types, &type, (void **) &t, &context)) != NULL) goto finish; if (context == 0) break; def_as_extern (c_name, type); if (t == NULL || t->tag == def_TYPE_ABSTRACT) { if ((rc = fprintf (help_data, "%s\n" "Defined in: <%s=>%." STR (TRUNCATION_LIMIT) "s.$>.h\n" "Declaration: typedef struct {...} *%s;", c_name, c_title, c_title, c_name)) < 0) goto finish; } else { if ((rc = fprintf (help_data, "%s\n" "Defined in: <%s=>%." STR (TRUNCATION_LIMIT) "s.$>.h\n" "Declaration: typedef%s", c_name, c_title, c_title, t->tag == def_TYPE_STRUCT || t->tag == def_TYPE_UNION? "\n ": " ")) < 0) goto finish; if ((rc = Print_Decl (c_title, help_data, t, NULL, c_name, FALSE, 0)) < 0) goto finish; if ((rc = fprintf (help_data, ";")) < 0) goto finish; } if (t != NULL) { if (t->description != NULL) if ((rc = fprintf (help_data, "\nDescription: %s", t->description)) < 0) goto finish; if (t->tag == def_TYPE_STRUCT || t->tag == def_TYPE_UNION) { bool first = TRUE; int i; for (i = 0; i < t->data AS list.count; i++) if (t->data AS list.members [i]->description != NULL) { if ((rc = fprintf (help_data, "\n%-17s %s - %s", first? "Fields:": "", t->data AS list.members [i]->name, t->data AS list.members [i]->description)) < 0) goto finish; first = FALSE; } } } { /*Additionally supply a list of constants with values of that type.*/ void *context; bool first = TRUE; context = NULL; while (TRUE) { if ((error = lookup_enumerate (consts, &cnst, (void **) &c, &context)) != NULL) goto finish; if (context == 0) break; /*loop invariant: we are at the end of the previous line*/ if (c->type->tag == def_TYPE_ID && strcmp (c->type->data AS id, type) == 0) { char c_name [def_ID_LIMIT + 1]; if (first) { fprintf (help_data, "\nValues: "); first = FALSE; } else fprintf (help_data, "\n "); def_as_macro (c_name, cnst); fprintf (help_data, "<%s>", c_name); } } } index_entry (help_data, c_name); } /*Emit the CONST declarations.*/ context = 0; while (TRUE) { if ((error = lookup_enumerate (consts, &cnst, (void **) &c, &context)) != NULL) goto finish; if (context == 0) break; def_as_macro (c_name, cnst); if ((rc = fprintf ( help_data, "%s\n" "Defined in: <%s=>%." STR (TRUNCATION_LIMIT) "s.$>.h\n" "Declaration: #define %s ", c_name, c_title, c_title, c_name )) < 0) goto finish; switch (c->type->tag) { case def_TYPE_INT: if ((rc = fprintf (help_data, "%s%d%s", c->value < 0? "(": "", c->value, c->value < 0? ")": "")) < 0) goto finish; break; case def_TYPE_SHORT: if ((rc = fprintf (help_data, "((short) %d)", c->value)) < 0) goto finish; break; case def_TYPE_BYTE: if ((rc = fprintf (help_data, "((byte) %d)", c->value)) < 0) goto finish; break; case def_TYPE_CHAR: if (isprint (c->value)) { if ((rc = fprintf (help_data, "((char) '%c')", c->value)) < 0) goto finish; } else { if ((rc = fprintf (help_data, "((char) '\\\\x%.2X')", c->value)) < 0) goto finish; } break; case def_TYPE_BITS: if ((rc = fprintf (help_data, "0x%Xu", c->value)) < 0) goto finish; break; case def_TYPE_BYTES: if ((rc = fprintf (help_data, "((bytes) 0x%Xu)", c->value)) < 0) goto finish; break; case def_TYPE_BOOL: if ((rc = fprintf (help_data, "%s", WHETHER (c->value))) < 0) goto finish; break; default: if ((rc = fprintf (help_data, "((")) < 0) goto finish; if ((rc = Print_Decl (c_title, help_data, c->type, NULL, NULL, FALSE, 0)) < 0) goto finish; if ((rc = fprintf (help_data, ") 0x%Xu)", c->value)) < 0) /*was %d 19th Apr 1995*/ goto finish; break; } if (c->description != NULL) if ((rc = fprintf (help_data, "\nDescription: %s", c->description)) < 0) goto finish; index_entry (help_data, c_name); } /*Emit the SWI declarations.*/ context = 0; while (TRUE) { bool nonx, first; if ((error = lookup_enumerate (swis, &swi, (void **) &s, &context)) != NULL) goto finish; if (context == 0) break; if (s->absent) for (nonx = FALSE; nonx <= TRUE; nonx++) { def_as_extern (c_name + (!nonx? 1: 0), swi); if (!nonx) c_name [0] = 'x'; if (s->description != NULL) { if ((rc = fprintf (help_data, "%s\n%s", c_name, s->description)) < 0) goto finish; } else { if ((rc = fprintf (help_data, "%s\nSWI 0x%X - not " "directly callable", c_name, s->swi)) < 0) goto finish; } index_entry (help_data, c_name); } else { int result = s->value != NONE? def_bit_index (s->value, 0): -1; /*number of register returned as result*/ for (nonx = FALSE; nonx <= TRUE; nonx++) { def_as_extern (c_name + (!nonx? 1: 0), swi); if (!nonx) c_name [0] = 'x'; tracef ("starting %s ...\n" _ c_name); first = TRUE; if ((rc = fprintf (help_data, "%s\n" "Defined in: <%s=>%." STR (TRUNCATION_LIMIT) "s.$>.h\n" "Declaration: extern ", c_name, c_title, c_title)) < 0) goto finish; if (!nonx) { if ((rc = fprintf (help_data, "<os_error=>os.os_error> *%s (", c_name)) < 0) goto finish; } else { if (s->value == NONE) { /*No return value.*/ if ((rc = fprintf (help_data, "void %s (", c_name)) < 0) goto finish; } else if (s->value == 1 << def_FLAGS) { /*Return value is |bits|.*/ if ((rc = fprintf (help_data, "bits %s (", c_name)) < 0) goto finish; } else { /*Return value of type |s->outputs [r]|.*/ char decl_name [def_ID_LIMIT + 1]; /*Prepend a star if the return value is a REFERENCES.*/ sprintf (decl_name, (s->ro & s->value) != NONE? "*%s": "%s", c_name); if ((rc = Print_Decl (c_title, help_data, s->outputs [result], NULL, decl_name, FALSE, 0)) < 0) goto finish; if ((rc = fprintf (help_data, " (")) < 0) goto finish; } } if (!def_using_block (s)) { for (i = 0; i < 10; i++) if ((s->i & 1 << i) != 0) { char arg_name [def_ID_LIMIT + 1]; if (!first) { if ((rc = fprintf (help_data, ",\n" " ")) < 0) goto finish; } else first = FALSE; if ((s->ri & 1 << i) == 0) { if ((rc = sprintf (arg_name, "%s", s->inputs [i]->name)) < 0) goto finish; } else { if ((rc = sprintf (arg_name, "const *%s", s->inputs [i]->name)) < 0) goto finish; } if ((rc = Print_Decl (c_title, help_data, s->inputs [i], NULL, arg_name, FALSE, 0)) < 0) goto finish; } for (i = 0; i < 10; i++) if ((s->o & 1 << i) != 0 && (!nonx || i != result)) { char arg_name [def_ID_LIMIT + 1]; if (!first) { if ((rc = fprintf (help_data, ",\n" " ")) < 0) goto finish; } else first = FALSE; if ((s->ro & 1 << i) == 0) { if ((rc = sprintf (arg_name, "*%s", s->outputs [i]->name)) < 0) goto finish; } else { if ((rc = sprintf (arg_name, "**%s", s->outputs [i]->name)) < 0) goto finish; } if ((rc = Print_Decl (c_title, help_data, s->outputs [i], NULL, arg_name, FALSE, 0)) < 0) goto finish; } if (s->f_out && (!nonx || def_FLAGS != result)) { struct def_t t; if (!first) { if ((rc = fprintf (help_data, ",\n" " ")) < 0) goto finish; } else first = FALSE; t.tag = def_TYPE_BITS; if ((rc = Print_Decl (c_title, help_data, &t, NULL, "*psr", FALSE, 0)) < 0) goto finish; } } else { /*First locate the register pointing to the block.*/ for (i = 0; i < 10; i++) if ((s->i & 1 << i) != 0) { int cpt; for (cpt = 0; cpt < s->inputs [i]->data AS list.count; cpt++) { if (!first) { if ((rc = fprintf (help_data, ",\n" " ")) < 0) goto finish; } else first = FALSE; if ((rc = Print_Decl (c_title, help_data, s->inputs [i]->data AS list.members [cpt], NULL, s->inputs [i]->data AS list.members [cpt]->name, FALSE, 0)) < 0) goto finish; } break; } } if ((rc = fprintf (help_data, first? "void);": ");")) < 0) goto finish; tracef ("describing %s ...\n" _ c_name); if (s->description != NULL) if ((rc = fprintf (help_data, "\nDescription: %s", s->description)) < 0) goto finish; if (!def_using_block (s)) { bool first; int i; tracef ("inputs ...\n"); first = TRUE; for (i = 0; i < 10; i++) if ((s->i & 1 << i) != NONE) { if ((rc = fprintf (help_data, "\n%-18s", first? "Entry:": "")) < 0) goto finish; if ((rc = fprintf (help_data, "%s", s->inputs [i]->name)) < 0) goto finish; if (s->inputs [i]->description != NULL) if ((rc = fprintf (help_data, " - %s", s->inputs [i]->description)) < 0) goto finish; if ((rc = fprintf (help_data, " (R%d)", i)) < 0) goto finish; first = FALSE; } tracef ("outputs ...\n"); first = TRUE; for (i = 0; i < 10; i++) if ((s->o & 1 << i) != NONE && (i != result || !nonx)) { if ((rc = fprintf (help_data, "\n%-18s", first? "Exit:": "")) < 0) goto finish; if ((rc = fprintf (help_data, "%s", s->outputs [i]->name)) < 0) goto finish; if (s->outputs [i]->description != NULL) if ((rc = fprintf (help_data, " - %s", s->outputs [i]->description)) < 0) goto finish; if ((rc = fprintf (help_data, " (R%d)", i)) < 0) goto finish; first = FALSE; } tracef ("returns ...\n"); if (nonx && result != -1) { if (result == def_FLAGS) { if ((rc = fprintf (help_data, "\n%-18s%s", "Returns:", "processor status register")) < 0) goto finish; } else { if ((rc = fprintf (help_data, "\n%-18s%s (R%d)", "Returns:", s->outputs [result]->description != NULL? s->outputs [result]->description: s->outputs [result]->name, result)) < 0) goto finish; } } } index_entry (help_data, c_name); } } } /*Emit the index page.*/ if ((rc = fprintf (help_data, "%s", title)) < 0) goto finish; for (i = 0; i < Entry_Count; i++) if ((rc = fprintf (help_data, "\n<%s>", Strings [i])) < 0) goto finish; index_entry (help_data, "$"); /*Now we have to sort the index.*/ qsort (Entries, Entry_Count, sizeof Entries [0], &Cmp); if ((rc = sprintf (index_name, "%s.%s", output, "Index")) < 0) goto finish; if ((index = fopen (index_name, "wb")) == NULL) { rc = -1; goto finish; } /*Relocate name offsets.*/ for (i = 0; i < Entry_Count; i++) Entries [i].name += sizeof Entry_Count + sizeof Entries [0]*Entry_Count; if ((rc = fwrite (&Entry_Count, sizeof Entry_Count, 1, index)) < 0) goto finish; if ((rc = fwrite (Entries, sizeof Entries [0], Entry_Count, index)) < 0) goto finish; for (i = 0; i < Entry_Count; i++) if ((rc = fwrite (Strings [i], 1, strlen (Strings [i]) + 1, index)) < 0) goto finish; finish: if (help_data != NULL) fclose (help_data); if (index != NULL) fclose (index); for (i = 0; i < Entry_Count; i++) free (Strings [i]); if (rc < 0) error = (os_error*)_kernel_last_oserror (); /* TV 990127 */ return error; }