/*chelp.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. */ #include #include #include #include /* TV 980115 */ #include "macros.h" #include "os.h" #include "lookup.h" #include "def.h" #include "chelp.h" /*Prints a declaration of |v| as an object of type |t|, using |tag| as the structure tag.*/ static int Print_Decl ( 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 (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, 17 + 3*nest, " " ): fprintf ( file, "%s\n%*s{ ", t->tag == def_TYPE_STRUCT? "struct": t->tag == def_TYPE_UNION? "union": "list", 17 + 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, "(%s) [%s]", t->data AS list.members [i]->name, !var? "...": "N")) < 0) goto finish; if ((rc = Print_Decl (file, t->data AS list.members [i], NULL, v1, FALSE, nest + 1)) < 0) goto finish; } else if ((rc = Print_Decl (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", 17 + 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", 17 + 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, "(%s) [%d]", v, t->data AS row.count)) < 0) goto finish; } if ((rc = Print_Decl (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]; def_as_extern (c_name, t->data AS id); if ((rc = fprintf (file, v == NULL? "%s": "%s %s", c_name, v)) < 0) goto finish; } break; } finish: return rc; } /*-----------------------------------------------------------------------*/ os_error *chelp_output ( FILE *file, 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]; void *context; int i, rc = 0; NOT_USED (needses) NOT_USED (author) def_as_extern (c_title, title); /*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) { if ((rc = fprintf (file, "%%%s\n" "Defined in: %s.h\n" "Declaration: typedef%s", c_name, c_title, t->tag == def_TYPE_STRUCT || t->tag == def_TYPE_UNION? "\n ": " ")) < 0) goto finish; if ((rc = Print_Decl (file, t, NULL, c_name, FALSE, 0)) < 0) goto finish; if ((rc = fprintf (file, ";\n\n")) < 0) goto finish; } else { if ((rc = fprintf (file, "%%%s\n" "Defined in: %s.h\n" "Declaration: typedef struct {...} *%s;\n\n", c_name, c_title, c_name)) < 0) goto finish; } } /*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 ( file, "%%%s\n" "Defined in: %s.h\n" "Declaration: #define %s ", c_name, c_title, c_name)) < 0) goto finish; switch (c->type->tag) { case def_TYPE_INT: if ((rc = fprintf (file, "%s%d%s", c->value < 0? "(": "", c->value, c->value < 0? ")": "")) < 0) goto finish; break; case def_TYPE_SHORT: if ((rc = fprintf (file, "((short) %d)", c->value)) < 0) goto finish; break; case def_TYPE_BYTE: if ((rc = fprintf (file, "((byte) %d)", c->value)) < 0) goto finish; break; case def_TYPE_CHAR: if (isprint (c->value)) { if ((rc = fprintf (file, "((char) '%c')", c->value)) < 0) goto finish; } else { if ((rc = fprintf (file, "((char) '\\x%.2X')", c->value)) < 0) goto finish; } break; case def_TYPE_BITS: if ((rc = fprintf (file, "0x%Xu", c->value)) < 0) goto finish; break; case def_TYPE_BYTES: if ((rc = fprintf (file, "((bytes) 0x%Xu)", c->value)) < 0) goto finish; break; case def_TYPE_BOOL: if ((rc = fprintf (file, "%s", WHETHER (c->value))) < 0) goto finish; break; default: if ((rc = fprintf (file, "((")) < 0) goto finish; if ((rc = Print_Decl (file, c->type, NULL, NULL, FALSE, 0)) < 0) goto finish; if ((rc = fprintf (file, ") %d)", c->value)) < 0) goto finish; break; } if ((rc = fprintf (file, "\n\n")) < 0) goto finish; } /*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) { 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'; first = TRUE; if ((rc = fprintf (file, "%%%s\n" "Defined in: %s.h\n" "Declaration: extern ", c_name, c_title)) < 0) goto finish; if (!nonx) { if ((rc = fprintf (file, "os_error *%s (", c_name)) < 0) goto finish; } else { if (s->value == NONE) { /*No return value.*/ if ((rc = fprintf (file, "void %s (", c_name)) < 0) goto finish; } else if (s->value == 1 << def_FLAGS) { /*Return value is |bits|.*/ if ((rc = fprintf (file, "bits %s (", c_name)) < 0) goto finish; } else { /*Return value of type |s->outputs [r]|.*/ if ((s->ro & s->value) != NONE) /*Prepend a star.*/ memmove (c_name + 1, c_name, strlen (c_name) + 1), c_name [0] = '*'; if ((rc = Print_Decl (file, s->outputs [result], NULL, c_name, FALSE, 0)) < 0) goto finish; if ((rc = fprintf (file, " (")) < 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 (file, ",\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 (file, 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 (file, ",\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 (file, 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 (file, ",\n ")) < 0) goto finish; } else first = FALSE; t.tag = def_TYPE_BITS; if ((rc = Print_Decl (file, &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 (file, ",\n" " ")) < 0) goto finish; } else first = FALSE; if ((rc = Print_Decl (file, 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 (file, first? "void);\n": ");\n")) < 0) goto finish; if ((rc = fprintf (file, "Summary: %s\n\n", s->description)) < 0) goto finish; } } } finish: if (rc < 0) error = (os_error*)_kernel_last_oserror (); /* TV 980115 */ return error; }