1877 lines
37 KiB
C
1877 lines
37 KiB
C
/*
|
|
* 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: parse_c.c /main/4 1996/10/02 13:32:03 drk $ */
|
|
/*
|
|
* File: parse_c.c
|
|
*
|
|
* Parses a C file for stubs merge.
|
|
*/
|
|
|
|
#ifndef _POSIX_SOURCE
|
|
#define _POSIX_SOURCE 1
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <ab_private/AB.h>
|
|
#include <ab_private/util_err.h>
|
|
#include <ab/util_types.h>
|
|
#include <ab_private/util.h>
|
|
#include <ab_private/abio.h>
|
|
#include "parse_cP.h"
|
|
|
|
/* DTB_USER_CODE_START */
|
|
/* DTB_USER_CODE_END*/
|
|
|
|
#define MAX_USER_SEGS_PER_SEG 10
|
|
|
|
/*
|
|
* Buffered file
|
|
*/
|
|
typedef struct
|
|
{
|
|
FILE *stream;
|
|
BOOL reverse;
|
|
BOOL eof;
|
|
|
|
/* the offsets of the last 2 newlines read from the file */
|
|
long lastNewlineOff;
|
|
long lastNewlineOff2;
|
|
|
|
/* DTB_USER_CODE_START */
|
|
int userField1;
|
|
char *userField2;
|
|
/* DTB_USER_CODE_END */
|
|
} BFileRec, *BFile;
|
|
|
|
typedef struct
|
|
{
|
|
BOOL forward;
|
|
long offset;
|
|
long lastNewlineOff;
|
|
long lastNewlineOff2;
|
|
} BFileStateRec, *BFileState;
|
|
|
|
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);
|
|
static int bfile_save_state(BFile, BFileState);
|
|
static int bfile_restore_state(BFile, BFileState);
|
|
|
|
|
|
typedef enum
|
|
{
|
|
COMMENT_UNDEF = 0,
|
|
COMMENT_SLASH_STAR,
|
|
COMMENT_SLASH_SLASH,
|
|
COMMENT_TYPE_NUM_VALUES
|
|
} COMMENT_TYPE;
|
|
|
|
|
|
typedef enum
|
|
{
|
|
MAGIC_CMT_UNDEF = 0,
|
|
MAGIC_CMT_USER_START,
|
|
MAGIC_CMT_USER_END,
|
|
MAGIC_COMMENT_TYPE_NUM_VALUES /* must be last */
|
|
} MAGIC_COMMENT_TYPE;
|
|
#define MAGIC_COMMENT_MAX_LEN (20)
|
|
#define MAGIC_COMMENT_MAX_SIZE (MAGIC_COMMENT_MAX_LEN+1)
|
|
|
|
static STRING magicCommentUserStart = "DTB_USER_CODE_START";
|
|
static STRING magicCommentUserEnd = "DTB_USER_CODE_END";
|
|
|
|
|
|
static int write_func_var_decl(FILE *file, CSeg cseg);
|
|
static int write_func_as_strings(FILE *file, CSeg cseg);
|
|
static int get_seg(BFile file, CSeg cseg);
|
|
static int skip_line(BFile file);
|
|
static int skip_string_const(BFile file);
|
|
static int skip_char_const(BFile file);
|
|
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_user_seg_end(BFile file, CUserSegs userSegs);
|
|
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_seg(
|
|
|
|
BFile file,
|
|
CSEG_TYPE *csegTypePtr,
|
|
char *namePtr,
|
|
long *segOffPtr,
|
|
long *segLenPtr,
|
|
long *bodyOffPtr,
|
|
long *bodyLenPtr,
|
|
CUserSegs userSegs
|
|
);
|
|
|
|
static int find_ident(BFile file, char *buf, int bufSize);
|
|
static int find_matching(
|
|
BFile file,
|
|
int matchChar,
|
|
long *matchOffPtr,
|
|
CUserSegs userSegs
|
|
);
|
|
|
|
static BOOL char_is_legal_for_ident(int iChar, BOOL firstChar);
|
|
|
|
static int skip_comment(
|
|
BFile file,
|
|
COMMENT_TYPE type,
|
|
MAGIC_COMMENT_TYPE *magicCommentTypeOutPtr
|
|
);
|
|
static int skip_slash_star_comment(
|
|
BFile file,
|
|
MAGIC_COMMENT_TYPE *magicCommentTypeOutPtr
|
|
);
|
|
static int skip_slash_slash_comment(
|
|
BFile file,
|
|
MAGIC_COMMENT_TYPE *magicCommentTypeOutPtr
|
|
);
|
|
static int skip_slash_slash_comment_fwd(
|
|
BFile file,
|
|
MAGIC_COMMENT_TYPE *magicCommentTypeOutPtr
|
|
);
|
|
static int skip_slash_slash_comment_bwd(
|
|
BFile file,
|
|
MAGIC_COMMENT_TYPE *magicCommentTypeOutPtr
|
|
);
|
|
|
|
static MAGIC_COMMENT_TYPE determine_magic_comment_type(STRING cmt);
|
|
static int get_char_from_c_file(
|
|
BFile file,
|
|
MAGIC_COMMENT_TYPE *magicCommentTypeOutPtr
|
|
);
|
|
|
|
static COMMENT_TYPE find_comment_start(BFile file, long *commentOffOut);
|
|
static int reverse_string(STRING buf);
|
|
static int cvt_offset_to_line(BFile file, long offset);
|
|
static int set_user_seg_next_pointers(CSegArray segArray, BFile file);
|
|
static int user_seg_construct(CUserSeg userSeg);
|
|
static BOOL user_seg_is_valid(CUserSeg userSeg);
|
|
|
|
|
|
/*************************************************************************
|
|
*************************************************************************
|
|
** **
|
|
** Public Entry Points **
|
|
** **
|
|
*************************************************************************
|
|
*************************************************************************/
|
|
|
|
int
|
|
abmfP_parse_c_file(FILE *cFile, CSegArray *segmentsOutPtr)
|
|
{
|
|
int return_value = 0;
|
|
int rc = 0; /* return code */
|
|
int numSegs = 0;
|
|
CSegArray segArray = NULL;
|
|
CSegRec seg;
|
|
BFileRec bfileRec;
|
|
BFile bfile = &bfileRec;
|
|
|
|
bfile_construct(bfile, cFile);
|
|
segArray = cseg_array_create();
|
|
if (segArray == NULL)
|
|
{
|
|
return_code(ERR_NO_MEMORY);
|
|
}
|
|
|
|
memset(&seg, 0, sizeof(seg));
|
|
while ((rc = get_seg(bfile, &seg)) >= 0)
|
|
{
|
|
/*
|
|
if (debugging())
|
|
{
|
|
int i = 0;
|
|
util_dprintf(1, "Seg: %s lines:%d-%d length:%ld userSegs:%d\n",
|
|
seg.type == CSEG_GLOBAL? "[GLOBAL]": util_strsafe(seg.name),
|
|
cvt_offset_to_line(bfile, seg.offset),
|
|
cvt_offset_to_line(bfile, seg.offset + seg.length
|
|
+ (seg.length==0? 0:-1)),
|
|
seg.length,
|
|
seg.userSegs.numSegs);
|
|
|
|
for (i = 0; i < seg.userSegs.numSegs; ++i)
|
|
{
|
|
STRING string = NULL;
|
|
util_dprintf(1, " =>UserSeg: %d-%ld [%ld+%ld bytes]\n",
|
|
cvt_offset_to_line(bfile, seg.userSegs.segs[i].offset),
|
|
cvt_offset_to_line(bfile, seg.userSegs.segs[i].offset +
|
|
+ seg.userSegs.segs[i].length
|
|
+ (seg.userSegs.segs[i].length<1? 0:-1)),
|
|
seg.userSegs.segs[i].offset,
|
|
seg.userSegs.segs[i].length);
|
|
grab_string_from_file(&string, bfile,
|
|
seg.userSegs.segs[i].offset,
|
|
seg.userSegs.segs[i].length);
|
|
util_dprintf(1, "|%s|\n", util_strsafe(string));
|
|
util_free(string);
|
|
}
|
|
}
|
|
*/
|
|
|
|
++numSegs;
|
|
segArray->segs = (CSeg)realloc(
|
|
segArray->segs, numSegs * sizeof(CSegRec));
|
|
if (segArray->segs == NULL)
|
|
{
|
|
cseg_array_destroy(segArray);
|
|
util_printf_err("Out of memory!\n");
|
|
return_code(-1);
|
|
}
|
|
segArray->segs[numSegs-1] = seg;
|
|
memset(&seg, 0, sizeof(seg));
|
|
}
|
|
segArray->numSegs = numSegs;
|
|
|
|
if ((rc < 0) && (rc != ERR_EOF))
|
|
{
|
|
/* failure occured */
|
|
segArray->numSegs = 0;
|
|
return_code(rc);
|
|
}
|
|
else
|
|
{
|
|
segArray->numSegs = numSegs;
|
|
}
|
|
|
|
/*
|
|
* Set up all user segment next pointers
|
|
*/
|
|
set_user_seg_next_pointers(segArray, bfile);
|
|
return_value = numSegs;
|
|
|
|
epilogue:
|
|
*segmentsOutPtr = segArray;
|
|
bfile_destruct(bfile);
|
|
return return_value;
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
** **
|
|
** PRIVATE SYMBOLS **
|
|
** **
|
|
*************************************************************************
|
|
*************************************************************************/
|
|
|
|
static int
|
|
set_user_seg_next_pointers(CSegArray segArray, BFile file)
|
|
{
|
|
CSeg curSeg = NULL;
|
|
CUserSeg curUserSeg = NULL;
|
|
CUserSeg lastUserSeg = NULL;
|
|
int segCount = 0;
|
|
int userSegCount = 0;
|
|
|
|
for (segCount = 0; segCount < segArray->numSegs; ++segCount)
|
|
{
|
|
curSeg = &(segArray->segs[segCount]);
|
|
for (userSegCount = 0; userSegCount < curSeg->userSegs.numSegs;
|
|
++userSegCount)
|
|
{
|
|
curUserSeg = &(curSeg->userSegs.segs[userSegCount]);
|
|
if (lastUserSeg == NULL)
|
|
{
|
|
/* first user segment */
|
|
segArray->firstUserSeg = curUserSeg;
|
|
}
|
|
else
|
|
{
|
|
lastUserSeg->next = curUserSeg;
|
|
}
|
|
|
|
curUserSeg->line = -1;
|
|
curUserSeg->line = cvt_offset_to_line(file, curUserSeg->offset);
|
|
lastUserSeg = curUserSeg;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static BOOL
|
|
char_is_legal_for_ident(int iChar, BOOL firstChar)
|
|
{
|
|
return
|
|
( (iChar == '_')
|
|
|| (firstChar? isalpha(iChar):isalnum(iChar)) );
|
|
}
|
|
|
|
|
|
static int
|
|
find_seg(
|
|
BFile file,
|
|
CSEG_TYPE *segTypePtr,
|
|
char *namePtr,
|
|
long *segOffPtr,
|
|
long *segLenPtr,
|
|
long *bodyOffPtr,
|
|
long *bodyLenPtr,
|
|
CUserSegs userSegs
|
|
)
|
|
{
|
|
int return_value = 0;
|
|
long segOff = 0;
|
|
long segLen = 0;
|
|
long openingParenOff = 0;
|
|
long openingBraceOff = 0;
|
|
long closingBraceOff = 0;
|
|
long identOff = 0;
|
|
int iChar = -1;
|
|
char ident[1024];
|
|
int identLen = 0;
|
|
BOOL lookForIdent = TRUE;
|
|
CSEG_TYPE segType = CSEG_UNDEF;
|
|
MAGIC_COMMENT_TYPE magicCommentType = MAGIC_CMT_UNDEF;
|
|
*ident = 0;
|
|
|
|
if (bfile_eof(file))
|
|
{
|
|
return_code(ERR_EOF);
|
|
}
|
|
|
|
*namePtr = 0;
|
|
segOff = bfile_get_off(file); /* for global segments */
|
|
|
|
while ((segType == CSEG_UNDEF) && (!bfile_eof(file)))
|
|
{
|
|
/*
|
|
* Scan, looking for opening {
|
|
*/ /* } vi hack */
|
|
openingBraceOff = -1;
|
|
while ((openingBraceOff < 0) && (!bfile_eof(file)))
|
|
{
|
|
iChar = get_char_from_c_file(file, &magicCommentType);
|
|
|
|
if (iChar == EOF)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (magicCommentType != MAGIC_CMT_UNDEF)
|
|
{
|
|
/*
|
|
* Found user seg in global segment
|
|
*/
|
|
CUserSeg userSeg = NULL;
|
|
++(userSegs->numSegs);
|
|
userSeg = &(userSegs->segs[(userSegs->numSegs)-1]);
|
|
user_seg_construct(userSeg);
|
|
if (iChar != '\n')
|
|
{
|
|
skip_line(file);
|
|
}
|
|
userSeg->offset = bfile_get_off(file);
|
|
|
|
if (find_user_seg_end(file, userSegs) < 0)
|
|
{
|
|
return_code(-1);
|
|
}
|
|
segLen = bfile_get_off(file) - segOff + 1;
|
|
}
|
|
|
|
if (iChar == '{') /* } vi hack */
|
|
{
|
|
openingBraceOff = (bfile_get_off(file)-1);
|
|
if (userSegs->numSegs > 0)
|
|
{
|
|
/* we found global segs before this object */
|
|
segType = CSEG_GLOBAL;
|
|
bfile_backup(file, 1);
|
|
segLen = bfile_get_off(file) - segOff + 1;
|
|
goto epilogue;
|
|
}
|
|
}
|
|
} /* while openingBraceOff < 0 */
|
|
if (openingBraceOff < 0)
|
|
{
|
|
/*
|
|
* Global segment, or end of file
|
|
*/
|
|
if (bfile_get_off(file) > segOff)
|
|
{
|
|
/* found segment at end of file */
|
|
segType = CSEG_GLOBAL;
|
|
}
|
|
else if (iChar == EOF)
|
|
{
|
|
return_value = ERR_EOF;
|
|
}
|
|
else
|
|
{
|
|
return_value = -1;
|
|
}
|
|
goto epilogue;
|
|
}
|
|
segOff = openingBraceOff;
|
|
|
|
/*
|
|
* Look for preceding ')', or ident
|
|
*/
|
|
bfile_set_off(file, openingBraceOff-1);
|
|
bfile_reverse(file);
|
|
|
|
openingParenOff = -1;
|
|
lookForIdent = TRUE;
|
|
identLen = 0;
|
|
while (lookForIdent)
|
|
{
|
|
iChar = get_char_from_c_file(file, NULL);
|
|
if (iChar == EOF)
|
|
{
|
|
lookForIdent = FALSE;
|
|
}
|
|
else if (iChar == ';')
|
|
{
|
|
if (openingParenOff >= 0)
|
|
{
|
|
lookForIdent = FALSE; /* end of parse */
|
|
}
|
|
else
|
|
{
|
|
/* if a ; is seen between () and {}, it should be an
|
|
* old-style parameter list declaration
|
|
*/
|
|
identLen = 0;
|
|
}
|
|
}
|
|
else if (iChar == ')')
|
|
{
|
|
/* no ident - look for () */
|
|
segType = CSEG_FUNC;
|
|
if (find_matching(file, '(', &openingParenOff, NULL)
|
|
/* ) vi hack */ >= 0)
|
|
{
|
|
segType = CSEG_FUNC;
|
|
identLen = 0;
|
|
}
|
|
else
|
|
{
|
|
util_printf_err(
|
|
"Bad function definition at or near line %d\n",
|
|
cvt_offset_to_line(file, openingBraceOff-2));
|
|
lookForIdent = FALSE;
|
|
identLen = 0;
|
|
return_code(-1);
|
|
}
|
|
}
|
|
else if (iChar == ']')
|
|
{
|
|
if (find_matching(file, '[', NULL, NULL) >= 0) /* ] vi hack */
|
|
{
|
|
segType = CSEG_AGGREGATE_VAR;
|
|
identLen = 0;
|
|
}
|
|
else
|
|
{
|
|
util_printf_err("Unbalanced '[' at or near line %d\n",
|
|
cvt_offset_to_line(file, bfile_get_off(file)));
|
|
/* ] vi hack */
|
|
lookForIdent = FALSE;
|
|
identLen = 0;
|
|
return_code(-1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (char_is_legal_for_ident(iChar, FALSE))
|
|
{
|
|
ident[identLen++] = iChar;
|
|
}
|
|
else if (identLen > 0)
|
|
{
|
|
/* found end of ident */
|
|
lookForIdent = FALSE;
|
|
}
|
|
}
|
|
} /* lookForIdent */
|
|
ident[identLen] = 0;
|
|
reverse_string(ident); /* was read backwards */
|
|
|
|
/*
|
|
* If it's a function, find the function name
|
|
* NB: bfile is reversed
|
|
*/
|
|
if (identLen < 1)
|
|
{
|
|
long off = bfile_get_off(file);
|
|
*ident = 0;
|
|
if (find_ident(file, ident, 1024) < 0)
|
|
{
|
|
util_printf_err("Syntax error at or near line %d\n",
|
|
cvt_offset_to_line(file, off));
|
|
return_code(-1);
|
|
}
|
|
else
|
|
{
|
|
segOff = identOff = (bfile_get_off(file)+1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If undef, it should be a type definition.
|
|
* NB: bfile is reversed
|
|
*/
|
|
if ((identLen > 0) && (segType == CSEG_UNDEF))
|
|
{
|
|
ident[identLen] = 0;
|
|
lookForIdent = FALSE;
|
|
|
|
if ( util_streq(ident, "struct")
|
|
|| util_streq(ident, "union")
|
|
|| util_streq(ident, "enum")
|
|
|| util_streq(ident, "class") )
|
|
{
|
|
identLen = 0;
|
|
segType = CSEG_AGGREGATE_TYPE;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* This could be a variable assignment or an aggregate
|
|
* type. The ident is the proper name for this one.
|
|
*/
|
|
segType = CSEG_AGGREGATE_TYPE;
|
|
}
|
|
} /* segType == CSEG_UNDEF */
|
|
|
|
/*
|
|
* file is reversed
|
|
* Get closing brace to find end.
|
|
*/
|
|
bfile_forward(file);
|
|
bfile_set_off(file, openingBraceOff);
|
|
bfile_get_char(file); /* skip brace */
|
|
/* { vi hack */
|
|
if (find_matching(file, '}', &closingBraceOff, userSegs) < 0)
|
|
{
|
|
util_printf_err("Unbalanced '{' at line %d.\n", /* } vi hack */
|
|
cvt_offset_to_line(file, openingBraceOff));
|
|
return_code(-1);
|
|
}
|
|
|
|
/*
|
|
* If name is still undef, it should be an aggregate type, and
|
|
* the name should follow the closing brace.
|
|
*
|
|
* file is forward.
|
|
*/
|
|
if ((identLen < 1) && (segType != CSEG_FUNC))
|
|
{
|
|
if (find_ident(file, ident, 1024) >= 0)
|
|
{
|
|
segType = CSEG_AGGREGATE_TYPE;
|
|
}
|
|
}
|
|
} /* while segType */
|
|
|
|
epilogue:
|
|
(*segTypePtr) = segType;
|
|
(*segOffPtr) = segOff;
|
|
(*segLenPtr) = segLen;
|
|
(*bodyOffPtr) = openingBraceOff;
|
|
(*bodyLenPtr) = (closingBraceOff - openingBraceOff) + 1;
|
|
util_strncpy(namePtr, ident, 1024);
|
|
if ((segType != CSEG_UNDEF) && (segType != CSEG_GLOBAL))
|
|
{
|
|
/* {} segment - calculate metrics by braces
|
|
*/
|
|
(*bodyOffPtr) = openingBraceOff;
|
|
(*bodyLenPtr) = (closingBraceOff - openingBraceOff) + 1;
|
|
(*segLenPtr) = closingBraceOff - segOff + 1;
|
|
}
|
|
|
|
if ( (return_value >= 0)
|
|
&& ((segType == CSEG_UNDEF) || ((*segOffPtr) < 0) || ((*segLenPtr) < 0))
|
|
)
|
|
{
|
|
return_value = -1;
|
|
}
|
|
|
|
return return_value;
|
|
}
|
|
|
|
|
|
/*
|
|
* Finds the end of a user segment.
|
|
* Assumes: beginning of segment as been read.
|
|
* Effects: reads past entire segment
|
|
*/
|
|
static int
|
|
find_user_seg_end(BFile file, CUserSegs userSegs)
|
|
{
|
|
int return_value = 0;
|
|
BOOL segmentIsBad = FALSE;
|
|
int iChar = -1;
|
|
MAGIC_COMMENT_TYPE magicCommentType = MAGIC_CMT_UNDEF;
|
|
CUserSeg userSeg = &(userSegs->segs[(userSegs->numSegs)-1]);
|
|
long segEndOff = -1;
|
|
|
|
if (userSegs->numSegs < 1)
|
|
{
|
|
return_code(ERR_CLIENT);
|
|
}
|
|
|
|
segEndOff = bfile_get_off(file)-1;
|
|
for (iChar = EOF+1;
|
|
(iChar != EOF) && (magicCommentType == MAGIC_CMT_UNDEF);
|
|
iChar = get_char_from_c_file(file, &magicCommentType) )
|
|
{
|
|
if (iChar == '\n')
|
|
{
|
|
segEndOff = file->lastNewlineOff;
|
|
}
|
|
}
|
|
|
|
if (magicCommentType != MAGIC_CMT_USER_END)
|
|
{
|
|
segmentIsBad = TRUE;
|
|
return_value = -1;
|
|
}
|
|
else
|
|
{
|
|
if (iChar != '\n')
|
|
{
|
|
skip_line(file);
|
|
}
|
|
/* include final newline */
|
|
userSeg->length = segEndOff - userSeg->offset + 1;
|
|
if (userSeg->length < 0)
|
|
{
|
|
userSeg->length = 0;
|
|
}
|
|
}
|
|
|
|
if (!user_seg_is_valid(userSeg))
|
|
{
|
|
segmentIsBad = TRUE;
|
|
--(userSegs->numSegs);
|
|
return_value = ERR_INTERNAL;
|
|
}
|
|
|
|
if (segmentIsBad)
|
|
{
|
|
util_printf_err("Bad DTB_USER segment, line %d\n",
|
|
cvt_offset_to_line(file, userSeg->offset));
|
|
return_code(-1);
|
|
}
|
|
|
|
epilogue:
|
|
return return_value;
|
|
}
|
|
|
|
|
|
static int
|
|
find_ident(
|
|
BFile file,
|
|
char *buf,
|
|
int bufSize
|
|
)
|
|
{
|
|
BOOL foundIdent = FALSE;
|
|
int iChar = 0;
|
|
int bufLen = 0;
|
|
|
|
*buf = 0;
|
|
skip_white_and_comment(file);
|
|
while (TRUE)
|
|
{
|
|
iChar = bfile_get_char(file);
|
|
if ((iChar == EOF) || (!char_is_legal_for_ident(iChar, FALSE)))
|
|
{
|
|
break;
|
|
}
|
|
else if (bufLen >= (bufSize-1))
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
buf[bufLen++] = iChar;
|
|
}
|
|
}
|
|
buf[bufLen] = 0;
|
|
foundIdent = ((*buf) != 0);
|
|
|
|
if (foundIdent && bfile_is_reverse(file))
|
|
{
|
|
reverse_string(buf);
|
|
}
|
|
|
|
/* if (foundIdent)
|
|
{
|
|
printf("found ident '%s'\n", buf);
|
|
}*/
|
|
|
|
return foundIdent? 0:-1;
|
|
}
|
|
|
|
|
|
static int
|
|
reverse_string(STRING buf)
|
|
{
|
|
int bufLen = strlen(buf);
|
|
int i;
|
|
int tempChar;
|
|
|
|
for (i = 0; i < (bufLen/2); ++i)
|
|
{
|
|
tempChar = buf[i];
|
|
buf[i] = buf[bufLen-1-i];
|
|
buf[bufLen-1-i] = tempChar;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Gets the next C segment from the file.
|
|
*/
|
|
|
|
get_seg(BFile file, CSeg cseg)
|
|
{
|
|
int return_value = 0;
|
|
int rc = 0; /* return code */
|
|
BOOL foundSeg = FALSE;
|
|
CSEG_TYPE segType = CSEG_UNDEF;
|
|
long segOff = -1;
|
|
long segLen = -1;
|
|
long bodyOff = -1;
|
|
long bodyLen = -1;
|
|
long nameOff = -1;
|
|
long nameLen = -1;
|
|
long protoOff = -1;
|
|
long protoLen = -1;
|
|
BOOL abort = FALSE;
|
|
BOOL err = FALSE;
|
|
long off = 0;
|
|
char segName[1024];
|
|
int i = 0;
|
|
CUserSegsRec userSegs;
|
|
|
|
userSegs.numSegs = 0;
|
|
cseg->type = CSEG_UNDEF;
|
|
rc = find_seg(file,
|
|
&segType, segName, &segOff, &segLen, &bodyOff, &bodyLen,
|
|
&userSegs);
|
|
return_if_err(rc,rc);
|
|
|
|
/*
|
|
* Put the info into the func structure
|
|
*/
|
|
cseg->type = segType;
|
|
cseg->name = strdup(segName);
|
|
cseg->offset = segOff;
|
|
cseg->length = segLen;
|
|
cseg->text = NULL;
|
|
cseg->declaration = NULL;
|
|
cseg->userSegs = userSegs;
|
|
for (i = 0; i < cseg->userSegs.numSegs; ++i)
|
|
{
|
|
grab_string_from_file(&(cseg->userSegs.segs[i].text),
|
|
file,
|
|
cseg->userSegs.segs[i].offset,
|
|
cseg->userSegs.segs[i].length);
|
|
}
|
|
|
|
epilogue:
|
|
return return_value;
|
|
}
|
|
|
|
|
|
static int
|
|
grab_string_from_file(
|
|
STRING *stringPtr,
|
|
BFile file,
|
|
long stringOff,
|
|
long stringLen
|
|
)
|
|
{
|
|
#define string (*stringPtr)
|
|
int returnValue = 0;
|
|
|
|
if (stringLen < 1)
|
|
{
|
|
string = strdup("");
|
|
}
|
|
else
|
|
{
|
|
BFileStateRec fileState;
|
|
|
|
bfile_save_state(file, &fileState);
|
|
string = (STRING)util_malloc((size_t)(stringLen + 1));
|
|
bfile_set_off(file, stringOff);
|
|
fread(string, 1, (size_t)stringLen, file->stream);
|
|
string[stringLen]= 0;
|
|
bfile_restore_state(file, &fileState);
|
|
}
|
|
|
|
return returnValue;
|
|
#undef string
|
|
}
|
|
|
|
|
|
/*
|
|
* userSegs is ignored, if it is NULL
|
|
*/
|
|
static int
|
|
find_matching(
|
|
BFile file,
|
|
int matchChar,
|
|
long *matchOffPtr,
|
|
CUserSegs userSegs
|
|
)
|
|
{
|
|
int return_value = 0;
|
|
int iChar = -1;
|
|
long lCharOff = 0;
|
|
long matchOff = -1;
|
|
BOOL foundMatching = FALSE;
|
|
BOOL quit = FALSE;
|
|
long startOff = bfile_get_off(file);
|
|
MAGIC_COMMENT_TYPE magicCommentType = MAGIC_CMT_UNDEF;
|
|
|
|
while ((!quit) && (!bfile_eof(file)))
|
|
{
|
|
iChar = get_char_from_c_file(file, &magicCommentType);
|
|
lCharOff = bfile_get_off(file);
|
|
|
|
/*
|
|
* Process magic comments
|
|
*/
|
|
if (userSegs != NULL)
|
|
{
|
|
switch (magicCommentType)
|
|
{
|
|
case MAGIC_CMT_USER_START:
|
|
if ( (userSegs->numSegs > 0)
|
|
&& (!user_seg_is_valid(
|
|
&(userSegs->segs[(userSegs->numSegs)-1]))))
|
|
{
|
|
/* last segment was not terminated */
|
|
--(userSegs->numSegs);
|
|
}
|
|
else
|
|
{
|
|
CUserSeg userSeg = NULL;
|
|
|
|
if (iChar != '\n')
|
|
{
|
|
skip_line(file);
|
|
}
|
|
++(userSegs->numSegs);
|
|
userSegs->segs[(userSegs->numSegs)-1].offset
|
|
= bfile_get_off(file);
|
|
userSegs->segs[(userSegs->numSegs)-1].length = -1;
|
|
userSeg = &(userSegs->segs[(userSegs->numSegs)-1]);
|
|
user_seg_construct(userSeg);
|
|
userSeg->offset = bfile_get_off(file);
|
|
|
|
if (find_user_seg_end(file, userSegs) < 0)
|
|
{
|
|
return_code(-1);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MAGIC_CMT_USER_END:
|
|
/*
|
|
* This should have been found by find_user_seg_end().
|
|
*/
|
|
util_printf_err("Bad DTB_USER segment at line %d\n",
|
|
cvt_offset_to_line(file, bfile_get_off(file))-1);
|
|
return_code(-1);
|
|
break;
|
|
}
|
|
} /* userSegs != NULL */
|
|
|
|
if (iChar == matchChar)
|
|
{
|
|
quit = TRUE;
|
|
foundMatching = TRUE;
|
|
}
|
|
else
|
|
{
|
|
switch (iChar)
|
|
{
|
|
case EOF:
|
|
quit = TRUE;
|
|
break;
|
|
|
|
case '"':
|
|
skip_string_const(file);
|
|
break;
|
|
|
|
case '\'':
|
|
skip_char_const(file);
|
|
break;
|
|
|
|
case '{':
|
|
if (find_matching(file, '}', NULL, userSegs) < 0)
|
|
{
|
|
util_printf_err("Unbalanced '{' at line %d.\n",
|
|
cvt_offset_to_line(file, lCharOff));
|
|
return_code(-1);
|
|
}
|
|
break;
|
|
|
|
case '}':
|
|
if (find_matching(file, '{', NULL, userSegs) < 0)
|
|
{
|
|
util_printf_err("Unbalanced '}' at line %d.\n",
|
|
cvt_offset_to_line(file, lCharOff));
|
|
return_code(-1);
|
|
}
|
|
break;
|
|
|
|
case '(':
|
|
if (find_matching(file, ')', NULL, userSegs) < 0)
|
|
{
|
|
util_printf_err("Unbalanced '(' at line %d.\n",
|
|
cvt_offset_to_line(file, lCharOff));
|
|
return_code(-1);
|
|
}
|
|
break;
|
|
|
|
case ')':
|
|
if (find_matching(file, '(', NULL, userSegs) < 0)
|
|
{
|
|
util_printf_err("Unbalanced ')' at line %d.\n",
|
|
cvt_offset_to_line(file, lCharOff));
|
|
return_code(-1);
|
|
}
|
|
break;
|
|
} /* switch iChar */
|
|
} /* ! iChar==matchChar */
|
|
} /* while !quit... */
|
|
|
|
epilogue:
|
|
if (foundMatching)
|
|
{
|
|
/* printf("<<match found(%c) for %ld>>\n", matchChar, startOff); */
|
|
if (matchOffPtr != NULL)
|
|
{
|
|
matchOff = bfile_get_off(file) + (file->reverse? 1:-1);
|
|
*matchOffPtr = matchOff;
|
|
}
|
|
}
|
|
if ((return_value >= 0) && (!foundMatching))
|
|
{
|
|
return_value = -1;
|
|
}
|
|
|
|
return return_value;
|
|
}
|
|
|
|
|
|
static int
|
|
user_seg_construct(CUserSeg userSeg)
|
|
{
|
|
memset(userSeg, 0, sizeof(*userSeg));
|
|
userSeg->offset = -1;
|
|
userSeg->length = -1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
static BOOL
|
|
user_seg_is_valid(CUserSeg userSeg)
|
|
{
|
|
return ( (userSeg->offset > -1)
|
|
&& (userSeg->length > -1) );
|
|
}
|
|
|
|
|
|
static int
|
|
skip_line(BFile file)
|
|
{
|
|
int iChar = 0;
|
|
while (((iChar = bfile_get_char(file)) != EOF) && (iChar != '\n'))
|
|
{
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Assumes: opening " has been read
|
|
*/
|
|
static int
|
|
skip_string_const(BFile file)
|
|
{
|
|
int iChar = 0;
|
|
while (((iChar = bfile_get_char(file)) != EOF)
|
|
&& (iChar != '\n')
|
|
&& (iChar != '"') )
|
|
{
|
|
if (iChar == '\\')
|
|
{
|
|
bfile_get_char(file);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Assumes: opening ' has been read
|
|
*/
|
|
static int
|
|
skip_char_const(BFile file)
|
|
{
|
|
int iChar = 0;
|
|
while (((iChar = bfile_get_char(file)) != EOF)
|
|
&& (iChar != '\n')
|
|
&& (iChar != '\'') )
|
|
{
|
|
if (iChar == '\\')
|
|
{
|
|
bfile_get_char(file);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
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, NULL);
|
|
|
|
while ((iChar != EOF) && (isspace(iChar)))
|
|
{
|
|
iChar = get_char_from_c_file(file, NULL);
|
|
}
|
|
if (iChar != EOF)
|
|
{
|
|
bfile_backup(file, 1);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Gets a char from a C source file, skipping comments
|
|
*/
|
|
static int
|
|
get_char_from_c_file(
|
|
BFile file,
|
|
MAGIC_COMMENT_TYPE *magicCommentTypeOutPtr
|
|
)
|
|
{
|
|
int iChar = EOF;
|
|
BOOL done = FALSE;
|
|
|
|
if (magicCommentTypeOutPtr != NULL)
|
|
{
|
|
*magicCommentTypeOutPtr = MAGIC_CMT_UNDEF;
|
|
}
|
|
|
|
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, magicCommentTypeOutPtr) < 0)
|
|
{
|
|
/* no comment */
|
|
done = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case '/':
|
|
if (bfile_is_forward(file))
|
|
{
|
|
iChar = bfile_get_char(file);
|
|
if (iChar == '/')
|
|
{
|
|
skip_slash_slash_comment(file, magicCommentTypeOutPtr);
|
|
}
|
|
else if (iChar == '*')
|
|
{
|
|
skip_slash_star_comment(file, magicCommentTypeOutPtr);
|
|
}
|
|
else
|
|
{
|
|
bfile_backup(file, 1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* reversed file */
|
|
if ((iChar = bfile_get_char(file)) == '*')
|
|
{
|
|
skip_slash_star_comment(file, magicCommentTypeOutPtr);
|
|
}
|
|
else
|
|
{
|
|
bfile_backup(file, 1);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
done = TRUE;
|
|
break;
|
|
}
|
|
} /* while !done */
|
|
|
|
return iChar;
|
|
}
|
|
|
|
|
|
static int
|
|
skip_comment(
|
|
BFile file,
|
|
COMMENT_TYPE commentType,
|
|
MAGIC_COMMENT_TYPE *magicCommentTypeOutPtr
|
|
)
|
|
{
|
|
int return_value = -1;
|
|
|
|
if (magicCommentTypeOutPtr != NULL)
|
|
{
|
|
*magicCommentTypeOutPtr = MAGIC_CMT_UNDEF;
|
|
}
|
|
|
|
switch(commentType)
|
|
{
|
|
case COMMENT_SLASH_STAR:
|
|
return_value = skip_slash_star_comment(
|
|
file, magicCommentTypeOutPtr);
|
|
break;
|
|
|
|
case COMMENT_SLASH_SLASH:
|
|
return_value = skip_slash_slash_comment(
|
|
file, magicCommentTypeOutPtr);
|
|
break;
|
|
}
|
|
|
|
return return_value;
|
|
}
|
|
|
|
|
|
static int
|
|
skip_slash_slash_comment(
|
|
BFile file,
|
|
MAGIC_COMMENT_TYPE *magicCommentTypeOutPtr
|
|
)
|
|
{
|
|
int return_value = -1;
|
|
|
|
if (bfile_is_forward(file))
|
|
{
|
|
return_value = skip_slash_slash_comment_fwd(
|
|
file, magicCommentTypeOutPtr);
|
|
}
|
|
else
|
|
{
|
|
return_value = skip_slash_slash_comment_bwd(
|
|
file, magicCommentTypeOutPtr);
|
|
}
|
|
return return_value;
|
|
}
|
|
|
|
|
|
static int
|
|
skip_slash_slash_comment_fwd(
|
|
BFile file,
|
|
MAGIC_COMMENT_TYPE *magicCommentTypeOutPtr
|
|
)
|
|
{
|
|
int iChar = 0;
|
|
char cmtBuf[MAGIC_COMMENT_MAX_SIZE];
|
|
int cmtBufLen = 0;
|
|
|
|
while ((iChar != EOF) && (iChar != '\n'))
|
|
{
|
|
iChar = bfile_get_char(file);
|
|
if ( ((char_is_legal_for_ident(iChar, FALSE)) || (cmtBufLen > 0))
|
|
&& (cmtBufLen < MAGIC_COMMENT_MAX_LEN) )
|
|
{
|
|
cmtBuf[cmtBufLen++] = iChar;
|
|
}
|
|
}
|
|
cmtBuf[cmtBufLen] = 0;
|
|
|
|
if (magicCommentTypeOutPtr != NULL)
|
|
{
|
|
*magicCommentTypeOutPtr = determine_magic_comment_type(cmtBuf);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int
|
|
skip_slash_slash_comment_bwd(
|
|
BFile file,
|
|
MAGIC_COMMENT_TYPE *magicCommentTypeOutPtr
|
|
)
|
|
{
|
|
long startOff = bfile_get_off(file);
|
|
BOOL foundCommentStart = FALSE;
|
|
BOOL done = FALSE;
|
|
int iChar = 0;
|
|
|
|
if (magicCommentTypeOutPtr != NULL)
|
|
{
|
|
*magicCommentTypeOutPtr = MAGIC_CMT_UNDEF;
|
|
}
|
|
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, startOff);
|
|
}
|
|
|
|
return (foundCommentStart? 0:-1);
|
|
}
|
|
|
|
|
|
static int
|
|
skip_slash_star_comment(
|
|
BFile file,
|
|
MAGIC_COMMENT_TYPE *magicCommentTypeOutPtr
|
|
)
|
|
{
|
|
int iChar = 0;
|
|
BOOL done = FALSE;
|
|
BOOL foundCommentEnd = FALSE;
|
|
char cmtBuf[MAGIC_COMMENT_MAX_SIZE];
|
|
int cmtBufLen = 0;
|
|
|
|
while (!done)
|
|
{
|
|
iChar = bfile_get_char(file);
|
|
|
|
if (iChar == EOF)
|
|
{
|
|
done = TRUE;
|
|
continue;
|
|
}
|
|
|
|
if ( ((char_is_legal_for_ident(iChar, FALSE)) || (cmtBufLen > 0))
|
|
&& (cmtBufLen < MAGIC_COMMENT_MAX_LEN) )
|
|
{
|
|
cmtBuf[cmtBufLen++] = iChar;
|
|
}
|
|
|
|
if (iChar == '*')
|
|
{
|
|
if ((iChar = bfile_get_char(file)) == '/')
|
|
{
|
|
foundCommentEnd = TRUE;
|
|
done = TRUE;
|
|
}
|
|
else
|
|
{
|
|
bfile_backup(file, 1);
|
|
}
|
|
}
|
|
}
|
|
cmtBuf[cmtBufLen] = 0;
|
|
if (magicCommentTypeOutPtr != NULL)
|
|
{
|
|
*magicCommentTypeOutPtr = determine_magic_comment_type(cmtBuf);
|
|
}
|
|
|
|
return (foundCommentEnd? 0:-1);
|
|
}
|
|
|
|
|
|
static MAGIC_COMMENT_TYPE
|
|
determine_magic_comment_type(STRING cmt)
|
|
{
|
|
MAGIC_COMMENT_TYPE magicType = MAGIC_CMT_UNDEF;
|
|
static int startLen = -1;
|
|
static int endLen = -1;
|
|
|
|
if (startLen < 0)
|
|
{
|
|
startLen = strlen(magicCommentUserStart);
|
|
endLen = strlen(magicCommentUserEnd);
|
|
}
|
|
|
|
if (strncmp(cmt, magicCommentUserStart, startLen) == 0)
|
|
{
|
|
magicType = MAGIC_CMT_USER_START;
|
|
}
|
|
else if (strncmp(cmt, magicCommentUserEnd, endLen) == 0)
|
|
{
|
|
magicType = MAGIC_CMT_USER_END;
|
|
}
|
|
|
|
return magicType;
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
** **
|
|
** BFile **
|
|
** **
|
|
*************************************************************************/
|
|
static BOOL bfileP_set_eof(BFile file);
|
|
|
|
static int
|
|
bfile_construct(BFile file, FILE *stream)
|
|
{
|
|
file->stream = NULL;
|
|
file->reverse = FALSE;
|
|
file->lastNewlineOff = -1;
|
|
file->lastNewlineOff2 = -1;
|
|
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->eof = TRUE;
|
|
}
|
|
if (iChar == '\n')
|
|
{
|
|
file->lastNewlineOff2 = file->lastNewlineOff;
|
|
file->lastNewlineOff = (bfile_get_off(file) + (file->reverse? 1:-1));
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
static int
|
|
bfile_save_state(BFile file, BFileState state)
|
|
{
|
|
state->forward = bfile_is_forward(file);
|
|
state->offset = bfile_get_off(file);
|
|
state->lastNewlineOff = file->lastNewlineOff;
|
|
state->lastNewlineOff2 = file->lastNewlineOff2;
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int
|
|
bfile_restore_state(BFile file, BFileState state)
|
|
{
|
|
if (!(state->forward))
|
|
{
|
|
bfile_reverse(file);
|
|
}
|
|
else
|
|
{
|
|
bfile_forward(file);
|
|
}
|
|
bfile_set_off(file, state->offset);
|
|
file->lastNewlineOff = state->lastNewlineOff;
|
|
file->lastNewlineOff2 = state->lastNewlineOff2;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/******************* PRIVATE METHODS **********************/
|
|
|
|
static BOOL
|
|
bfileP_set_eof(BFile file)
|
|
{
|
|
file->eof = FALSE;
|
|
|
|
if (file->stream == NULL)
|
|
{
|
|
file->eof = TRUE;
|
|
goto epilogue;
|
|
}
|
|
|
|
/* DTB_USER_CODE_START */
|
|
/* DTB_USER_CODE_END*/
|
|
|
|
if (file->reverse)
|
|
{
|
|
/* dunno... */
|
|
}
|
|
else
|
|
{
|
|
file->eof = (feof(file->stream) || ferror(file->stream));
|
|
}
|
|
|
|
/* DTB_USER_CODE_START */
|
|
|
|
if (file->reverse)
|
|
{
|
|
/* put some goobies here */
|
|
}
|
|
|
|
/* DTB_USER_CODE_END*/
|
|
|
|
epilogue:
|
|
return 0;
|
|
}
|
|
|
|
|
|
CSegArray
|
|
cseg_array_create()
|
|
{
|
|
CSegArray newArray = (CSegArray)util_malloc(sizeof(CSegArrayRec));
|
|
if (newArray != NULL)
|
|
{
|
|
memset(newArray, 0, sizeof(CSegArrayRec));
|
|
}
|
|
return newArray;
|
|
}
|
|
|
|
|
|
int
|
|
cseg_arrayP_destroy_impl(CSegArray *arrayInOutPtr)
|
|
{
|
|
CSegArray array = *arrayInOutPtr;
|
|
if (array == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
util_free(array->segs);
|
|
util_free(array);
|
|
|
|
*arrayInOutPtr = NULL;
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int
|
|
cvt_offset_to_line(BFile file, long offset)
|
|
{
|
|
static long lastLineOff = 0;
|
|
static int lastLineNum = 1;
|
|
int lineNum = 1;
|
|
long curOff = 0;
|
|
int c = 0;
|
|
BFileStateRec startFileState;
|
|
|
|
bfile_save_state(file, &startFileState);
|
|
bfile_forward(file);
|
|
|
|
if (offset >= lastLineOff)
|
|
{
|
|
curOff = lastLineOff;
|
|
lineNum = lastLineNum;
|
|
}
|
|
else
|
|
{
|
|
curOff = 0;
|
|
lineNum = 1;
|
|
}
|
|
bfile_set_off(file, curOff);
|
|
while ((curOff < offset) && ((c = bfile_get_char(file)) != EOF))
|
|
{
|
|
++curOff;
|
|
if (c == '\n')
|
|
{
|
|
++lineNum;
|
|
lastLineNum = lineNum;
|
|
lastLineOff = curOff;
|
|
}
|
|
}
|
|
|
|
bfile_restore_state(file, &startFileState);
|
|
|
|
/*
|
|
* Return file to original state
|
|
*/
|
|
return lineNum;
|
|
}
|
|
|
|
|
|
/********
|
|
* This is here as a test (run this program on this file)
|
|
*/
|
|
/*
|
|
static int
|
|
old_style_params(x, y, z)
|
|
int x;
|
|
char *y;
|
|
CUserSegRec *z;
|
|
{
|
|
x = x; y = y; z = z;
|
|
return 69;
|
|
}
|
|
*/
|
|
|
|
|
|
/*************************************************************************
|
|
*************************************************************************
|
|
** **
|
|
** DEBUGGING SUPPORT **
|
|
** **
|
|
*************************************************************************
|
|
*************************************************************************/
|
|
|
|
|
|
#ifdef MAIN
|
|
|
|
/* Internationalization defines */
|
|
nl_catd Dtb_project_catd = (nl_catd)-1;
|
|
|
|
/* Workaround for XPG4 API compatibility */
|
|
#if !defined(NL_CAT_LOCALE)
|
|
#define NL_CAT_LOCALE 0
|
|
#endif
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
STRING inFilename = NULL;
|
|
FILE *inFile = NULL;
|
|
CSegArray segs = NULL;
|
|
CSeg cseg = NULL;
|
|
int numSegs = 0;
|
|
int segIndex = 0;
|
|
int usegIndex = 0;
|
|
|
|
util_init(&argc, &argv);
|
|
|
|
if (argc < 2)
|
|
{
|
|
util_printf_err("Usage %s <filename>\n", util_get_program_name());
|
|
exit(1);
|
|
}
|
|
|
|
inFilename = argv[1];
|
|
inFile = util_fopen_locked(inFilename, "r");
|
|
if (inFile == NULL)
|
|
{
|
|
perror(inFilename);
|
|
return -1;
|
|
}
|
|
|
|
numSegs = abmfP_parse_c_file(inFile, &segs);
|
|
if (numSegs < 0)
|
|
{
|
|
util_printf_err("Error parsing C file. Aborting\n");
|
|
exit(1);
|
|
}
|
|
util_printf_err("Segs found in file: %d\n", numSegs);
|
|
if (numSegs < 1)
|
|
{
|
|
exit(0);
|
|
}
|
|
|
|
for (segIndex = 0; segIndex < numSegs; ++segIndex)
|
|
{
|
|
cseg = &(segs->segs[segIndex]);
|
|
util_dprintf(1, "Seg: %s offset:%ld length:%ld userSegs:%d\n",
|
|
cseg->type == CSEG_GLOBAL? "[GLOBAL]": util_strsafe(cseg->name),
|
|
cseg->offset,
|
|
cseg->length,
|
|
cseg->userSegs.numSegs);
|
|
if (cseg->text != NULL)
|
|
{
|
|
printf("|||%s|||\n", cseg->text);
|
|
}
|
|
|
|
if (cseg->userSegs.numSegs < 1)
|
|
{
|
|
printf("[ No user segments ]\n");
|
|
}
|
|
else
|
|
{
|
|
for (usegIndex = 0; usegIndex < cseg->userSegs.numSegs; ++usegIndex)
|
|
{
|
|
printf("--- user seg %d [line %ld] ---\n%s---\n",
|
|
usegIndex,
|
|
cseg->userSegs.segs[usegIndex].line,
|
|
util_strsafe(cseg->userSegs.segs[usegIndex].text));
|
|
}
|
|
}
|
|
}
|
|
printf("\n");
|
|
|
|
return 0;
|
|
}
|
|
#endif /* MAIN */
|
|
|
|
/*
|
|
* Leave this user segment at the end of the file (this file can be
|
|
* used to test itself).
|
|
*/
|
|
|
|
/* DTB_USER_CODE_START */
|
|
|
|
static int
|
|
myfunc()
|
|
{
|
|
return 0;
|
|
}
|
|
/* DTB_USER_CODE_END*/
|