| /* | 
 |  * From: @(#)rpc_util.c 1.11 89/02/22 | 
 |  * | 
 |  * Copyright (c) 2010, Oracle America, Inc. | 
 |  * Redistribution and use in source and binary forms, with or without | 
 |  * modification, are permitted provided that the following conditions are | 
 |  * met: | 
 |  * | 
 |  *     * Redistributions of source code must retain the above copyright | 
 |  *       notice, this list of conditions and the following disclaimer. | 
 |  *     * Redistributions in binary form must reproduce the above | 
 |  *       copyright notice, this list of conditions and the following | 
 |  *       disclaimer in the documentation and/or other materials | 
 |  *       provided with the distribution. | 
 |  *     * Neither the name of the "Oracle America, Inc." nor the names of its | 
 |  *       contributors may be used to endorse or promote products derived | 
 |  *       from this software without specific prior written permission. | 
 |  * | 
 |  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
 |  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
 |  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | 
 |  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | 
 |  *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | 
 |  *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
 |  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | 
 |  *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 
 |  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | 
 |  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | 
 |  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
 |  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
 |  */ | 
 |  | 
 | /* | 
 |  * rpc_util.c, Utility routines for the RPC protocol compiler | 
 |  */ | 
 | #include <stdio.h> | 
 | #include <ctype.h> | 
 | #include <string.h> | 
 | #include <unistd.h> | 
 | #include "rpc_scan.h" | 
 | #include "rpc_parse.h" | 
 | #include "rpc_util.h" | 
 | #include "proto.h" | 
 |  | 
 | #define ARGEXT "argument" | 
 |  | 
 | char curline[MAXLINESIZE];	/* current read line */ | 
 | const char *where = curline;	/* current point in line */ | 
 | int linenum = 0;		/* current line number */ | 
 |  | 
 | const char *infilename;		/* input filename */ | 
 |  | 
 | #define NFILES 7 | 
 | const char *outfiles[NFILES];	/* output file names */ | 
 | int nfiles; | 
 |  | 
 | FILE *fout;			/* file pointer of current output */ | 
 | FILE *fin;			/* file pointer of current input */ | 
 |  | 
 | list *defined;			/* list of defined things */ | 
 |  | 
 | static int findit (const definition * def, const char *type); | 
 | static const char *fixit (const char *type, const char *orig); | 
 | static int typedefed (const definition * def, const char *type); | 
 | static const char *toktostr (tok_kind kind); | 
 | static void printbuf (void); | 
 | static void printwhere (void); | 
 |  | 
 | /* | 
 |  * Reinitialize the world | 
 |  */ | 
 | void | 
 | reinitialize (void) | 
 | { | 
 |   memset (curline, 0, MAXLINESIZE); | 
 |   where = curline; | 
 |   linenum = 0; | 
 |   defined = NULL; | 
 | } | 
 |  | 
 | /* | 
 |  * string equality | 
 |  */ | 
 | int | 
 | streq (const char *a, const char *b) | 
 | { | 
 |   return strcmp (a, b) == 0; | 
 | } | 
 |  | 
 | /* | 
 |  * find a value in a list | 
 |  */ | 
 | definition * | 
 | findval (list *lst, const char *val, | 
 | 	 int (*cmp) (const definition *, const char *)) | 
 | { | 
 |  | 
 |   for (; lst != NULL; lst = lst->next) | 
 |     { | 
 |       if (cmp (lst->val, val)) | 
 | 	{ | 
 | 	  return lst->val; | 
 | 	} | 
 |     } | 
 |   return NULL; | 
 | } | 
 |  | 
 | /* | 
 |  * store a value in a list | 
 |  */ | 
 | void | 
 | storeval (list **lstp, definition *val) | 
 | { | 
 |   list **l; | 
 |   list *lst; | 
 |  | 
 |  | 
 |   for (l = lstp; *l != NULL; l = (list **) & (*l)->next); | 
 |   lst = ALLOC (list); | 
 |   lst->val = val; | 
 |   lst->next = NULL; | 
 |   *l = lst; | 
 | } | 
 |  | 
 | static int | 
 | findit (const definition * def, const char *type) | 
 | { | 
 |   return streq (def->def_name, type); | 
 | } | 
 |  | 
 | static const char * | 
 | fixit (const char *type, const char *orig) | 
 | { | 
 |   definition *def; | 
 |  | 
 |   def = findval (defined, type, findit); | 
 |   if (def == NULL || def->def_kind != DEF_TYPEDEF) | 
 |     { | 
 |       return orig; | 
 |     } | 
 |   switch (def->def.ty.rel) | 
 |     { | 
 |     case REL_VECTOR: | 
 |       if (streq (def->def.ty.old_type, "opaque")) | 
 | 	return ("char"); | 
 |       else | 
 | 	return (def->def.ty.old_type); | 
 |     case REL_ALIAS: | 
 |       return (fixit (def->def.ty.old_type, orig)); | 
 |     default: | 
 |       return orig; | 
 |     } | 
 | } | 
 |  | 
 | const char * | 
 | fixtype (const char *type) | 
 | { | 
 |   return fixit (type, type); | 
 | } | 
 |  | 
 | const char * | 
 | stringfix (const char *type) | 
 | { | 
 |   if (streq (type, "string")) | 
 |     { | 
 |       return "wrapstring"; | 
 |     } | 
 |   else | 
 |     { | 
 |       return type; | 
 |     } | 
 | } | 
 |  | 
 | void | 
 | ptype (const char *prefix, const char *type, int follow) | 
 | { | 
 |   if (prefix != NULL) | 
 |     { | 
 |       if (streq (prefix, "enum")) | 
 | 	{ | 
 | 	  f_print (fout, "enum "); | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  f_print (fout, "struct "); | 
 | 	} | 
 |     } | 
 |   if (streq (type, "bool")) | 
 |     { | 
 |       f_print (fout, "bool_t "); | 
 |     } | 
 |   else if (streq (type, "string")) | 
 |     { | 
 |       f_print (fout, "char *"); | 
 |     } | 
 |   else | 
 |     { | 
 |       f_print (fout, "%s ", follow ? fixtype (type) : type); | 
 |     } | 
 | } | 
 |  | 
 | static int | 
 | typedefed (const definition * def, const char *type) | 
 | { | 
 |   if (def->def_kind != DEF_TYPEDEF || def->def.ty.old_prefix != NULL) | 
 |     { | 
 |       return 0; | 
 |     } | 
 |   else | 
 |     { | 
 |       return streq (def->def_name, type); | 
 |     } | 
 | } | 
 |  | 
 | int | 
 | isvectordef (const char *type, relation rel) | 
 | { | 
 |   definition *def; | 
 |  | 
 |   for (;;) | 
 |     { | 
 |       switch (rel) | 
 | 	{ | 
 | 	case REL_VECTOR: | 
 | 	  return !streq (type, "string"); | 
 | 	case REL_ARRAY: | 
 | 	  return 0; | 
 | 	case REL_POINTER: | 
 | 	  return 0; | 
 | 	case REL_ALIAS: | 
 | 	  def = findval (defined, type, typedefed); | 
 | 	  if (def == NULL) | 
 | 	    { | 
 | 	      return 0; | 
 | 	    } | 
 | 	  type = def->def.ty.old_type; | 
 | 	  rel = def->def.ty.rel; | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | char * | 
 | locase (const char *str) | 
 | { | 
 |   char c; | 
 |   static char buf[100]; | 
 |   char *p = buf; | 
 |  | 
 |   while ((c = *str++) != 0) | 
 |     { | 
 |       *p++ = (c >= 'A' && c <= 'Z') ? (c - 'A' + 'a') : c; | 
 |     } | 
 |   *p = 0; | 
 |   return buf; | 
 | } | 
 |  | 
 | void | 
 | pvname_svc (const char *pname, const char *vnum) | 
 | { | 
 |   f_print (fout, "%s_%s_svc", locase (pname), vnum); | 
 | } | 
 |  | 
 | void | 
 | pvname (const char *pname, const char *vnum) | 
 | { | 
 |   f_print (fout, "%s_%s", locase (pname), vnum); | 
 | } | 
 |  | 
 | /* | 
 |  * print a useful (?) error message, and then die | 
 |  */ | 
 | void | 
 | error (const char *msg) | 
 | { | 
 |   printwhere (); | 
 |   f_print (stderr, "%s, line %d: ", infilename, linenum); | 
 |   f_print (stderr, "%s\n", msg); | 
 |   crash (); | 
 | } | 
 |  | 
 | /* | 
 |  * Something went wrong, unlink any files that we may have created and then | 
 |  * die. | 
 |  */ | 
 | void | 
 | crash (void) | 
 | { | 
 |   int i; | 
 |  | 
 |   for (i = 0; i < nfiles; i++) | 
 |     { | 
 |       unlink (outfiles[i]); | 
 |     } | 
 |   exit (1); | 
 | } | 
 |  | 
 | void | 
 | record_open (const char *file) | 
 | { | 
 |   if (nfiles < NFILES) | 
 |     { | 
 |       outfiles[nfiles++] = file; | 
 |     } | 
 |   else | 
 |     { | 
 |       f_print (stderr, "too many files!\n"); | 
 |       crash (); | 
 |     } | 
 | } | 
 |  | 
 | static char expectbuf[100]; | 
 |  | 
 | /* | 
 |  * error, token encountered was not the expected one | 
 |  */ | 
 | void | 
 | expected1 (tok_kind exp1) | 
 | { | 
 |   s_print (expectbuf, "expected '%s'", | 
 | 	   toktostr (exp1)); | 
 |   error (expectbuf); | 
 | } | 
 |  | 
 | /* | 
 |  * error, token encountered was not one of two expected ones | 
 |  */ | 
 | void | 
 | expected2 (tok_kind exp1, tok_kind exp2) | 
 | { | 
 |   s_print (expectbuf, "expected '%s' or '%s'", | 
 | 	   toktostr (exp1), | 
 | 	   toktostr (exp2)); | 
 |   error (expectbuf); | 
 | } | 
 |  | 
 | /* | 
 |  * error, token encountered was not one of 3 expected ones | 
 |  */ | 
 | void | 
 | expected3 (tok_kind exp1, tok_kind exp2, tok_kind exp3) | 
 | { | 
 |   s_print (expectbuf, "expected '%s', '%s' or '%s'", | 
 | 	   toktostr (exp1), | 
 | 	   toktostr (exp2), | 
 | 	   toktostr (exp3)); | 
 |   error (expectbuf); | 
 | } | 
 |  | 
 | void | 
 | tabify (FILE * f, int tab) | 
 | { | 
 |   while (tab--) | 
 |     { | 
 |       (void) fputc ('\t', f); | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | static const token tokstrings[] = | 
 | { | 
 |   {TOK_IDENT, "identifier"}, | 
 |   {TOK_CONST, "const"}, | 
 |   {TOK_RPAREN, ")"}, | 
 |   {TOK_LPAREN, "("}, | 
 |   {TOK_RBRACE, "}"}, | 
 |   {TOK_LBRACE, "{"}, | 
 |   {TOK_LBRACKET, "["}, | 
 |   {TOK_RBRACKET, "]"}, | 
 |   {TOK_STAR, "*"}, | 
 |   {TOK_COMMA, ","}, | 
 |   {TOK_EQUAL, "="}, | 
 |   {TOK_COLON, ":"}, | 
 |   {TOK_SEMICOLON, ";"}, | 
 |   {TOK_UNION, "union"}, | 
 |   {TOK_STRUCT, "struct"}, | 
 |   {TOK_SWITCH, "switch"}, | 
 |   {TOK_CASE, "case"}, | 
 |   {TOK_DEFAULT, "default"}, | 
 |   {TOK_ENUM, "enum"}, | 
 |   {TOK_TYPEDEF, "typedef"}, | 
 |   {TOK_INT, "int"}, | 
 |   {TOK_SHORT, "short"}, | 
 |   {TOK_LONG, "long"}, | 
 |   {TOK_UNSIGNED, "unsigned"}, | 
 |   {TOK_DOUBLE, "double"}, | 
 |   {TOK_FLOAT, "float"}, | 
 |   {TOK_CHAR, "char"}, | 
 |   {TOK_STRING, "string"}, | 
 |   {TOK_OPAQUE, "opaque"}, | 
 |   {TOK_BOOL, "bool"}, | 
 |   {TOK_VOID, "void"}, | 
 |   {TOK_PROGRAM, "program"}, | 
 |   {TOK_VERSION, "version"}, | 
 |   {TOK_EOF, "??????"} | 
 | }; | 
 |  | 
 | static const char * | 
 | toktostr (tok_kind kind) | 
 | { | 
 |   const token *sp; | 
 |  | 
 |   for (sp = tokstrings; sp->kind != TOK_EOF && sp->kind != kind; sp++); | 
 |   return sp->str; | 
 | } | 
 |  | 
 | static void | 
 | printbuf (void) | 
 | { | 
 |   char c; | 
 |   int i; | 
 |   int cnt; | 
 |  | 
 | #define TABSIZE 4 | 
 |  | 
 |   for (i = 0; (c = curline[i]) != 0; i++) | 
 |     { | 
 |       if (c == '\t') | 
 | 	{ | 
 | 	  cnt = 8 - (i % TABSIZE); | 
 | 	  c = ' '; | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  cnt = 1; | 
 | 	} | 
 |       while (cnt--) | 
 | 	{ | 
 | 	  (void) fputc (c, stderr); | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | static void | 
 | printwhere (void) | 
 | { | 
 |   int i; | 
 |   char c; | 
 |   int cnt; | 
 |  | 
 |   printbuf (); | 
 |   for (i = 0; i < where - curline; i++) | 
 |     { | 
 |       c = curline[i]; | 
 |       if (c == '\t') | 
 | 	{ | 
 | 	  cnt = 8 - (i % TABSIZE); | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  cnt = 1; | 
 | 	} | 
 |       while (cnt--) | 
 | 	{ | 
 | 	  (void) fputc ('^', stderr); | 
 | 	} | 
 |     } | 
 |   (void) fputc ('\n', stderr); | 
 | } | 
 |  | 
 | char * | 
 | make_argname (const char *pname, const char *vname) | 
 | { | 
 |   char *name; | 
 |  | 
 |   name = malloc (strlen (pname) + strlen (vname) + strlen (ARGEXT) + 3); | 
 |   if (!name) | 
 |     { | 
 |       fprintf (stderr, "failed in malloc"); | 
 |       exit (1); | 
 |     } | 
 |   sprintf (name, "%s_%s_%s", locase (pname), vname, ARGEXT); | 
 |   return name; | 
 | } | 
 |  | 
 | bas_type *typ_list_h; | 
 | bas_type *typ_list_t; | 
 |  | 
 | void | 
 | add_type (int len, const char *type) | 
 | { | 
 |   bas_type *ptr; | 
 |  | 
 |  | 
 |   if ((ptr = malloc (sizeof (bas_type))) == NULL) | 
 |     { | 
 |       fprintf (stderr, "failed in malloc"); | 
 |       exit (1); | 
 |     } | 
 |  | 
 |   ptr->name = type; | 
 |   ptr->length = len; | 
 |   ptr->next = NULL; | 
 |   if (typ_list_t == NULL) | 
 |     { | 
 |  | 
 |       typ_list_t = ptr; | 
 |       typ_list_h = ptr; | 
 |     } | 
 |   else | 
 |     { | 
 |  | 
 |       typ_list_t->next = ptr; | 
 |       typ_list_t = ptr; | 
 |     } | 
 |  | 
 | } | 
 |  | 
 |  | 
 | bas_type * | 
 | find_type (const char *type) | 
 | { | 
 |   bas_type *ptr; | 
 |  | 
 |   ptr = typ_list_h; | 
 |  | 
 |  | 
 |   while (ptr != NULL) | 
 |     { | 
 |       if (strcmp (ptr->name, type) == 0) | 
 | 	return ptr; | 
 |       else | 
 | 	ptr = ptr->next; | 
 |     }; | 
 |   return NULL; | 
 | } |