/* * CDE - Common Desktop Environment * * Copyright (c) 1993-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these librararies and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /* $XConsortium: ab_func_strings.c /main/4 1996/10/02 15:13:50 drk $ */ /* * ab_mk_func_strings */ #ifndef _POSIX_SOURCE #define _POSIX_SOURCE 1 #endif #include #include #include #include #include #include #include #include #include /* Internationalization defines */ nl_catd Dtb_project_catd; /* Workaround for XPG4 API compatibility */ #if !defined(NL_CAT_LOCALE) #define NL_CAT_LOCALE 0 #endif /* * Buffered file */ typedef struct { FILE *stream; BOOL reverse; BOOL eof; } B_FILE, *BFile; static int bfile_construct(BFile, FILE *file); static int bfile_destruct(BFile); static BOOL bfile_is_forward(BFile file); static BOOL bfile_is_reverse(BFile file); static int bfile_get_char(BFile); static int bfile_backup(BFile, long numBytes); static long bfile_get_off(BFile); static int bfile_set_off(BFile, long off); static BOOL bfile_eof(BFile); static int bfile_set_file(BFile, FILE *stream); static int bfile_reverse(BFile); static int bfile_forward(BFile); typedef enum { COMMENT_UNDEF = 0, COMMENT_SLASH_STAR, COMMENT_SLASH_SLASH, COMMENT_TYPE_NUM_VALUES } COMMENT_TYPE; typedef struct { STRING funcCode; STRING funcProto; STRING funcName; } FileFuncInfoRec, *FileFuncInfo; static int write_func_var_decl(FILE *file, FileFuncInfo funcInfo); static int write_func_as_strings(FILE *file, FileFuncInfo funcInfo); static int get_func(FILE *file, FileFuncInfo funcInfo); static int skip_white(BFile file); static int skip_white_and_comment(BFile file); static int write_c_string(FILE *file, STRING value); static int find_func_name( BFile file, long funcOff, long bodyOff, long *nameOffPtr, long *nameLenPtr); static int find_func_proto( BFile file, long funcOff, long nameOff, long bodyOff, long *protoOff, long *protoLen); static int trim_opening_comment( BFile file, long *funcOffPtr, long *funcLenPtr, long protoOff ); static int grab_string_from_file( STRING *stringPtr, BFile file, long stringOff, long stringLen); static int find_matching(BFile file, int matchChar, long *matchOffPtr); static BOOL char_is_legal_for_ident(int iChar); static int format_func_name(STRING *name); static int format_func_proto(STRING *proto); static int format_func_def(STRING *def); static int skip_comment(BFile file, COMMENT_TYPE type); static int skip_slash_star_comment(BFile file); static int skip_slash_slash_comment(BFile file); static int skip_slash_slash_comment_fwd(BFile file); static int skip_slash_slash_comment_bwd(BFile file); static int get_char_from_c_file(BFile file); static COMMENT_TYPE find_comment_start(BFile file, long *commentOffOut); int main (int argc, char *argv[]) { STRING inFilename = NULL; FILE *inFile = NULL; FileFuncInfoRec funcInfo; FileFuncInfo funcs = NULL; int numFuncs = 0; int i = 0; /* ** We haven't internationalized this utility program, but it uses ** libraries which are I18N-ized. To resolve this we just set the ** message catalog descriptor to -1 here so we get default messages ** from library routines. */ Dtb_project_catd = (nl_catd) -1; util_init(&argc, &argv); if (argc < 2) { fprintf(stderr, "Usage %s \n", argv[0]); exit(1); } inFilename = argv[1]; inFile = util_fopen_locked(inFilename, "r"); if (inFile == NULL) { perror(inFilename); return -1; } memset(&funcInfo, 0, sizeof(funcInfo)); while (get_func(inFile, &funcInfo) >= 0) { fprintf(stderr, "Function: %s\n", util_strsafe(funcInfo.funcName)); ++numFuncs; funcs = (FileFuncInfo)realloc( funcs, numFuncs * sizeof(FileFuncInfoRec)); if (funcs == NULL) { fprintf(stderr, "Out of memory!\n"); exit(1); } funcs[numFuncs-1] = funcInfo; memset(&funcInfo, 0, sizeof(funcInfo)); } fprintf(stderr, "Functions found in file: %d\n", numFuncs); if (numFuncs < 1) { exit(0); } for (i = 0; i < numFuncs; ++i) { write_func_var_decl(stdout, &(funcs[i])); } abio_puts(stdout, "\n\n\n"); for (i = 0; i < numFuncs; ++i) { write_func_as_strings(stdout, &(funcs[i])); } return 0; } static int write_func_var_decl(FILE *file, FileFuncInfo funcInfo) { char ptrVarName[256]; STRING funcNamePtr = NULL; funcNamePtr = funcInfo->funcName; if (strncmp(funcNamePtr, "dtb_", 4) == 0) { funcNamePtr += 4; } sprintf(ptrVarName, "abmfP_lib_%s", funcNamePtr); abio_printf(file, "extern LibFunc %s;\n", ptrVarName); return 0; } static int write_func_as_strings(FILE *file, FileFuncInfo funcInfo) { char recVarName[256]; char ptrVarName[256]; char *funcNamePtr = NULL; funcNamePtr = funcInfo->funcName; if (strncmp(funcNamePtr, "dtb_", 4) == 0) { funcNamePtr += 4; } sprintf(recVarName, "%abmfP_lrc_%s", funcNamePtr); sprintf(ptrVarName, "%abmfP_lib_%s", funcNamePtr); abio_puts(file, "\n"); abio_puts(file, "/*\n"); abio_printf(file, " * %s\n", ptrVarName); abio_puts(file, " */\n"); abio_printf(file, "static LibFuncRec %s = \n", recVarName); abio_printf(file, "{\n"); abio_indent(file); abio_puts(file, "/* name */\n"); write_c_string(file, funcInfo->funcName); abio_puts(file, ",\n"); abio_puts(file, "\n"); abio_printf(file, "/* proto */\n"); write_c_string(file, funcInfo->funcProto); abio_puts(file, ",\n"); abio_puts(file, "\n"); abio_printf(file, "/* def */\n"); write_c_string(file, funcInfo->funcCode); abio_puts(file, "\n"); abio_outdent(file); abio_printf(file, "}; /* %s */\n", recVarName); abio_printf(file, "LibFunc %s = &(%s);\n", ptrVarName, recVarName); return 0; } static int write_c_string(FILE *file, STRING value) { BOOL done = FALSE; char *nlPtr = NULL; char *lineStart = value; int oldNlChar = -1; while (!done) { nlPtr = strchr(lineStart, '\n'); oldNlChar = -1; if (nlPtr != NULL) { ++nlPtr; oldNlChar = *nlPtr; *nlPtr = 0; } abio_put_string(file, lineStart); if (nlPtr != NULL) { *nlPtr = (char)oldNlChar; oldNlChar = -1; } if (nlPtr == NULL) { done = TRUE; } else { lineStart = nlPtr; abio_puts(file, "\n"); } } return 0; } static BOOL char_is_legal_for_ident(int iChar) { return (isalnum(iChar) || (iChar == '_')); } static int find_func( BFile file, long *funcOffPtr, long *funcLenPtr, long *bodyOffPtr, long *bodyLenPtr ) { #define funcOff (*funcOffPtr) #define funcLen (*funcLenPtr) #define bodyOff (*bodyOffPtr) #define bodyLen (*bodyLenPtr) int returnValue = 0; long openingBraceOff = 0; long closingBraceOff = 0; int iChar = -1; skip_white(file); /* * Scan, looking for opening { */ /* } vi hack */ funcOff = bfile_get_off(file); openingBraceOff = -1; while ((openingBraceOff < 0) && (!bfile_eof(file))) { iChar = get_char_from_c_file(file); switch (iChar) { case ';': /* function must start after one of these chars */ funcOff = bfile_get_off(file); break; case '{': /* } vi hack */ openingBraceOff = bfile_get_off(file) - 1; break; } } if ((openingBraceOff < 0) || (openingBraceOff <= funcOff)) { return -1; } /* printf("opening brace %ld\n", openingBraceOff); */ if (find_matching(file, '}', &closingBraceOff) < 0) { fprintf(stderr, "Mismatched braces {}.\nn"); return -1; } /* printf("closing brace %ld\n", closingBraceOff); */ bodyOff = openingBraceOff; bodyLen = (closingBraceOff - openingBraceOff) + 1; funcLen = (closingBraceOff - funcOff + 1); if ((bodyLen < 0) || (funcLen < 0)) { returnValue = -1; } return returnValue; #undef funcOff #undef funcLen #undef bodyOff #undef bodyLen } static int trim_opening_comment( BFile file, long *funcOffPtr, long *funcLenPtr, long protoOff ) { #define funcOff (*funcOffPtr) #define funcLen (*funcLenPtr) long startOff = bfile_get_off(file); long newCommentOff = -1; long commentOff = -1; long funcLenDiff = 0; long newFuncOff = 0; COMMENT_TYPE commentType; BOOL done = FALSE; bfile_set_off(file, funcOff); bfile_forward(file); while (!done) { commentType = find_comment_start(file, &newCommentOff); if ( (commentType == COMMENT_UNDEF) || (newCommentOff >= protoOff) ) { done = TRUE; } else { commentOff = newCommentOff; skip_comment(file, commentType); } } if (commentOff > 0) { funcLenDiff = (funcOff - commentOff); funcOff = commentOff; funcLen += funcLenDiff; } /* * trim white space */ bfile_set_off(file, funcOff); skip_white(file); newFuncOff = bfile_get_off(file); funcLenDiff = (funcOff - newFuncOff); funcOff = newFuncOff; funcLen += funcLenDiff; bfile_set_off(file, startOff); return 0; #undef funcOff #undef funcLen } static int find_func_name( BFile file, long funcOff, long bodyOff, long *nameOffPtr, long *nameLenPtr ) { #define nameOff (*nameOffPtr) #define nameLen (*nameLenPtr) int returnValue = 0; int iChar = EOF; long nameEndOff = 0; bfile_forward(file); bfile_set_off(file, bodyOff); bfile_reverse(file); get_char_from_c_file(file); /* skip '{' */ skip_white_and_comment(file); if ((iChar = get_char_from_c_file(file)) != ')') { fprintf(stderr, "Syntax error near function name.\n"); return -1; } if (find_matching(file, '(', NULL) < 0) { fprintf(stderr, "Unbalanced parens.\n"); return -1; } skip_white_and_comment(file); nameEndOff = bfile_get_off(file); iChar = get_char_from_c_file(file); while ((iChar != EOF) && (char_is_legal_for_ident(iChar))) { iChar = bfile_get_char(file); } nameOff = bfile_get_off(file) + 2; if ((nameOff < funcOff) || (nameOff > nameEndOff)) { returnValue = -1; } else { nameLen = (nameEndOff - nameOff + 1); } return returnValue; #undef nameOff #undef nameLen } static int find_func_proto( BFile file, long funcOff, long nameOff, long bodyOff, long *protoOffPtr, long *protoLenPtr ) { #define protoOff (*protoOffPtr) #define protoLen (*protoLenPtr) int returnValue = 0; long protoEndOff = -1; int iChar = -1; long lastValidOff = -1; COMMENT_TYPE commentType = COMMENT_UNDEF; long commentOff; BOOL done = FALSE; bfile_forward(file); /* * find start of type info (first non-space, non-comment chars) */ protoOff = funcOff; bfile_set_off(file, protoOff); done = FALSE; while (!done) { commentType = find_comment_start(file, &commentOff); if ((commentType == COMMENT_UNDEF) || (commentOff >= bodyOff)) { done = TRUE; } else { protoOff = commentOff; } } bfile_set_off(file, protoOff); skip_white_and_comment(file); protoOff = bfile_get_off(file); /* * Look for end of prototype */ bfile_forward(file); bfile_set_off(file, bodyOff); bfile_reverse(file); get_char_from_c_file(file); skip_white_and_comment(file); protoEndOff = bfile_get_off(file); if (protoEndOff <= protoOff) { returnValue = -1; } else { protoLen = (protoEndOff - protoOff + 1); } return returnValue; #undef protoOff #undef protoLen } static int get_func(FILE *file, FileFuncInfo funcInfo) { int rc = 0; /* return code */ B_FILE bfileRec; BFile bfile = &bfileRec; long funcOff = -1; long funcLen = -1; long bodyOff = -1; long bodyLen = -1; long nameOff = -1; long nameLen = -1; long protoOff = -1; long protoLen = -1; BOOL foundFunc = FALSE; BOOL abort = FALSE; BOOL err = FALSE; long off = 0; bfile_construct(bfile, file); abort = FALSE; foundFunc = FALSE; while ((!abort) && (!foundFunc) && (!bfile_eof(bfile))) { err = FALSE; if (!err) { rc = find_func(bfile, &funcOff, &funcLen, &bodyOff, &bodyLen); if (rc < 0) { err = TRUE; abort = TRUE; } /* printf("find_func: %ld %ld %ld\n", funcOff, bodyOff, bodyLen); */ } if (!err) { rc = find_func_name(bfile, funcOff, bodyOff, &nameOff, &nameLen); if (rc < 0) { err = TRUE; } /* printf("func_name: %ld %ld\n", nameOff, nameLen); */ } if (!err) { rc = find_func_proto(bfile, funcOff, nameOff, bodyOff, &protoOff, &protoLen); if (rc < 0) { err = TRUE; } /* printf("proto: %ld %ld\n", protoOff, protoLen); */ } if (!err) { rc = trim_opening_comment(bfile, &funcOff, &funcLen, protoOff); if (rc < 0) { err = TRUE; } } if (!err) { foundFunc = TRUE; } /* printf("new offset %ld\n", funcOff + funcLen + 1); */ bfile_set_off(bfile, funcOff + funcLen + 1); bfile_forward(bfile); } /* * Put the info into the func structure */ if (foundFunc) { grab_string_from_file(&(funcInfo->funcName), bfile, nameOff, nameLen); format_func_name(&(funcInfo->funcName)); grab_string_from_file(&(funcInfo->funcProto), bfile, protoOff, protoLen); format_func_proto(&(funcInfo->funcProto)); grab_string_from_file(&(funcInfo->funcCode), bfile, funcOff, funcLen); format_func_def(&(funcInfo->funcCode)); } bfile_destruct(bfile); return foundFunc?0:-1; } static int grab_string_from_file( STRING *stringPtr, BFile file, long stringOff, long stringLen ) { #define string (*stringPtr) int returnValue = 0; string = (STRING)util_malloc((size_t)(stringLen + 1)); bfile_set_off(file, stringOff); fread(string, 1, (size_t)stringLen, file->stream); string[stringLen]= 0; return returnValue; #undef string } static int find_matching(BFile file, int matchChar, long *matchOffPtr) { int returnValue = 0; int iChar = -1; BOOL foundMatching = FALSE; BOOL quit = FALSE; long startOff = bfile_get_off(file); /* printf("find_matching(%c) at %ld\n", matchChar, startOff); */ while ((!quit) && (!bfile_eof(file))) { iChar = get_char_from_c_file(file); if (iChar == matchChar) { quit = TRUE; foundMatching = TRUE; } else { switch (iChar) { case EOF: quit = TRUE; break; case '{': if (find_matching(file, '}', NULL) < 0) { fprintf(stderr, "Unbalanced braces {}.\n"); quit = TRUE; returnValue = -1; } break; case '}': if (find_matching(file, '{', NULL) < 0) { fprintf(stderr, "Unbalanced braces {}\n"); quit = TRUE; returnValue = -1; } break; case '(': if (find_matching(file, ')', NULL) < 0) { fprintf(stderr, "Unbalanced parens ()\n"); quit = TRUE; returnValue = -1; } break; case ')': if (find_matching(file, '(', NULL) < 0) { fprintf(stderr, "Unbalanced parens ()\n"); quit = TRUE; returnValue = -1; } break; } } } if (foundMatching) { /* printf("<>\n", matchChar, startOff); */ if (matchOffPtr != NULL) { *matchOffPtr = bfile_get_off(file); if (file->reverse) { ++(*matchOffPtr); } else { --(*matchOffPtr); } } } if ((returnValue >=0) && (!foundMatching)) { returnValue = -1; } return returnValue; } static int skip_white(BFile file) { int iChar = bfile_get_char(file); while ((iChar != EOF) && (isspace(iChar))) { iChar = bfile_get_char(file); } if (iChar != EOF) { bfile_backup(file, 1); } return 0; } static int skip_white_and_comment(BFile file) { int iChar = get_char_from_c_file(file); while ((iChar != EOF) && (isspace(iChar))) { iChar = get_char_from_c_file(file); } if (iChar != EOF) { bfile_backup(file, 1); } return 0; } static int format_func_name(STRING *namePtr) { #define name (*namePtr) return 0; #undef name } static int format_func_proto(STRING *protoPtr) { #define proto (*protoPtr) int protoLen = strlen(proto); int i = 0; /* * Add ; */ proto = (STRING)realloc(proto, protoLen+2); strcat(proto, ";"); ++protoLen; /* * Remove preceding space */ while ((protoLen > 0) && isspace(proto[0])) { memmove(proto, proto+1, protoLen--); } for (i = 0; i < protoLen; ++i) { if (proto[i] == '(') { break; } if (proto[i] == '\n') { proto[i] = ' '; } } return 0; #undef proto } static int format_func_def(STRING *defPtr) { #define def (*defPtr) return 0; #undef def } /* * Gets a char from a C source file, skipping comments */ static int get_char_from_c_file(BFile file) { int iChar = EOF; BOOL done = FALSE; while (!done) { iChar = bfile_get_char(file); switch (iChar) { case EOF: done = TRUE; break; case '\n': if (bfile_is_forward(file)) { done = TRUE; } else { if (skip_slash_slash_comment(file) < 0) { /* no comment */ done = TRUE; } } break; case '/': if (bfile_is_forward(file)) { iChar = bfile_get_char(file); if (iChar == '/') { skip_slash_slash_comment(file); } else if (iChar == '*') { skip_slash_star_comment(file); } else { bfile_backup(file, 1); } } else { /* reversed file */ if ((iChar = bfile_get_char(file)) == '*') { skip_slash_star_comment(file); } else { bfile_backup(file, 1); } } break; default: done = TRUE; break; } } /* while !done */ return iChar; } static COMMENT_TYPE find_comment_start(BFile file, long *commentOffOutPtr) { #define commentOffOut (*commentOffOutPtr) COMMENT_TYPE commentType = COMMENT_UNDEF; int iChar = -1; BOOL done = FALSE; long commentOff = 0; while (!done) { commentOff = bfile_get_off(file); iChar = bfile_get_char(file); if (iChar == EOF) { done = TRUE; } else if (iChar == '/') { iChar = bfile_get_char(file); if (iChar == EOF) { done = TRUE; } else if (iChar == '*') { commentType = COMMENT_SLASH_STAR; done = TRUE; } else if (iChar == '/') { commentType = COMMENT_SLASH_SLASH; done = TRUE; } else { bfile_backup(file, 1); } } } if (commentType != COMMENT_UNDEF) { commentOffOut = commentOff; } return commentType; #undef commentOffOut } static int skip_comment(BFile file, COMMENT_TYPE commentType) { int return_value = -1; switch(commentType) { case COMMENT_SLASH_STAR: return_value = skip_slash_star_comment(file); break; case COMMENT_SLASH_SLASH: return_value = skip_slash_slash_comment(file); break; } return return_value; } static int skip_slash_slash_comment(BFile file) { int return_value = -1; if (bfile_is_forward(file)) { return_value = skip_slash_slash_comment_fwd(file); } else { return_value = skip_slash_slash_comment_bwd(file); } return return_value; } static int skip_slash_slash_comment_fwd(BFile file) { int iChar = 0; while ((iChar != EOF) && (iChar != '\n')) { iChar = bfile_get_char(file); } return 0; } static int skip_slash_slash_comment_bwd(BFile file) { long startOffset = bfile_get_off(file); BOOL foundCommentStart = FALSE; BOOL done = FALSE; int iChar = 0; while (!done) { iChar = bfile_get_char(file); switch (iChar) { case '\n': case EOF: done = TRUE; break; case '/': if ((iChar = bfile_get_char(file)) == '/') { foundCommentStart = TRUE; done = TRUE; } else { bfile_backup(file, 1); } break; } } if (!foundCommentStart) { bfile_set_off(file, startOffset); } return (foundCommentStart? 0:-1); } static int skip_slash_star_comment(BFile file) { int iChar = 0; BOOL done = FALSE; BOOL foundCommentEnd = FALSE; while (!done) { iChar = bfile_get_char(file); if (iChar == '*') { if ((iChar = bfile_get_char(file)) == '/') { foundCommentEnd = TRUE; done = TRUE; } else { bfile_backup(file, 1); } } } return (foundCommentEnd? 0:-1); } /************************************************************************* ** ** ** BFile ** ** ** *************************************************************************/ static BOOL bfileP_set_eof(BFile file); static int bfile_construct(BFile file, FILE *stream) { file->stream = NULL; file->reverse = FALSE; file->eof = TRUE; return bfile_set_file(file, stream); } static int bfile_destruct(BFile file) { return bfile_set_file(file, NULL); } static BOOL bfile_eof(BFile file) { return file->eof; } static BOOL bfile_is_forward(BFile file) { return (!(file->reverse)); } static BOOL bfile_is_reverse(BFile file) { return file->reverse; } static int bfile_get_char(BFile file) { int iChar = EOF; if (file->eof) { goto epilogue; } iChar = fgetc(file->stream); if (iChar == EOF) { if (file->reverse) { if (fseek(file->stream, -1, SEEK_END) == 0) { iChar = fgetc(file->stream); } else { goto epilogue; } } else { goto epilogue; } } if (file->reverse) { if (fseek(file->stream, -2, SEEK_CUR) != 0) { file->eof = TRUE; } } epilogue: /* if ((iChar != EOF) && (!(file->reverse))) { printf("%c", iChar); } */ if (iChar == EOF) { file->eof = TRUE; } return iChar; } static int bfile_backup(BFile file, long numBytes) { int returnValue = 0; long posChange = 0; if (file->reverse) { posChange = numBytes; } else { posChange = -1 * numBytes; } if (fseek(file->stream, posChange, SEEK_CUR) == 0) { file->eof = FALSE; } else { file->eof = TRUE; returnValue = -1; } return returnValue; } static int bfile_set_file(BFile file, FILE *stream) { file->stream = stream; file->reverse = FALSE; bfileP_set_eof(file); return 0; } static int bfile_reverse(BFile file) { file->reverse = TRUE; bfileP_set_eof(file); return 0; } static int bfile_forward(BFile file) { file->reverse = FALSE; bfileP_set_eof(file); return 0; } static long bfile_get_off(BFile file) { long off = -1; if (file->reverse) { if (file->eof) { off = -1; } else { off = ftell(file->stream); } } else { off = ftell(file->stream); } return off; } static int bfile_set_off(BFile file, long off) { int returnValue = 0; if (fseek(file->stream, off, SEEK_SET) != 0) { returnValue = -1; } bfileP_set_eof(file); return returnValue; } /******************* PRIVATE METHODS **********************/ static BOOL bfileP_set_eof(BFile file) { file->eof = FALSE; if (file->stream == NULL) { file->eof = TRUE; goto epilogue; } if (file->reverse) { /* dunno... */ } else { file->eof = (feof(file->stream) || ferror(file->stream)); } epilogue: return 0; }