Add support for updating tags from a memory buffer (code merged from Anjuta).
This still doesn't work and is currently disabled. It would only work for a few filetypes like C, Fortran and JavaScript. The current implementation is still buggy, e.g. function signature parsing is broken. git-svn-id: https://geany.svn.sourceforge.net/svnroot/geany/trunk@3184 ea778897-0a13-0410-b9d1-a72fbfd435f5
This commit is contained in:
parent
71523b8a2b
commit
99860e187a
@ -99,6 +99,7 @@ typedef struct
|
||||
|
||||
static void document_undo_clear(GeanyDocument *doc);
|
||||
static void document_redo_add(GeanyDocument *doc, guint type, gpointer data);
|
||||
static gboolean update_tags_from_buffer(GeanyDocument *doc);
|
||||
|
||||
|
||||
/* ignore the case of filenames and paths under WIN32, causes errors if not */
|
||||
@ -975,6 +976,25 @@ static void set_indentation(GeanyEditor *editor)
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static gboolean auto_update_tag_list(gpointer data)
|
||||
{
|
||||
GeanyDocument *doc = data;
|
||||
|
||||
if (! doc || ! doc->is_valid || doc->tm_file == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (gtk_window_get_focus(GTK_WINDOW(main_widgets.window)) != GTK_WIDGET(doc->editor->sci))
|
||||
return TRUE;
|
||||
|
||||
if (update_tags_from_buffer(doc))
|
||||
treeviews_update_tag_list(doc, TRUE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* To open a new file, set doc to NULL; filename should be locale encoded.
|
||||
* To reload a file, set the doc for the document to be reloaded; filename should be NULL.
|
||||
* pos is the cursor position, which can be overridden by --line and --column.
|
||||
@ -990,10 +1010,6 @@ GeanyDocument *document_open_file_full(GeanyDocument *doc, const gchar *filename
|
||||
GeanyFiletype *use_ft;
|
||||
FileData filedata;
|
||||
|
||||
/*struct timeval tv, tv1;*/
|
||||
/*struct timezone tz;*/
|
||||
/*gettimeofday(&tv, &tz);*/
|
||||
|
||||
if (reload)
|
||||
{
|
||||
utf8_filename = g_strdup(doc->file_name);
|
||||
@ -1123,8 +1139,10 @@ GeanyDocument *document_open_file_full(GeanyDocument *doc, const gchar *filename
|
||||
|
||||
g_free(utf8_filename);
|
||||
g_free(locale_filename);
|
||||
/*gettimeofday(&tv1, &tz);*/
|
||||
/*geany_debug("%s: %d", filename, (gint)(tv1.tv_usec - tv.tv_usec)); */
|
||||
|
||||
/* TODO This could be used to automatically update the symbol list,
|
||||
* based on a configurable interval */
|
||||
/*g_timeout_add(10000, auto_update_tag_list, doc);*/
|
||||
|
||||
return doc;
|
||||
}
|
||||
@ -1532,10 +1550,10 @@ gboolean document_save_file(GeanyDocument *doc, gboolean force)
|
||||
document_set_filetype(doc, doc->file_type);
|
||||
|
||||
tm_workspace_update(TM_WORK_OBJECT(app->tm_workspace), TRUE, TRUE, FALSE);
|
||||
{
|
||||
gtk_label_set_text(GTK_LABEL(doc->priv->tab_label), base_name);
|
||||
gtk_label_set_text(GTK_LABEL(doc->priv->tabmenu_label), base_name);
|
||||
}
|
||||
|
||||
gtk_label_set_text(GTK_LABEL(doc->priv->tab_label), base_name);
|
||||
gtk_label_set_text(GTK_LABEL(doc->priv->tabmenu_label), base_name);
|
||||
|
||||
msgwin_status_add(_("File %s saved."), doc->file_name);
|
||||
ui_update_statusbar(doc, -1);
|
||||
g_free(base_name);
|
||||
@ -1972,6 +1990,26 @@ gboolean document_replace_all(GeanyDocument *doc, const gchar *find_text, const
|
||||
}
|
||||
|
||||
|
||||
static gboolean update_tags_from_buffer(GeanyDocument *doc)
|
||||
{
|
||||
gboolean result;
|
||||
#if 1
|
||||
/* old code */
|
||||
result = tm_source_file_update(doc->tm_file, TRUE, FALSE, TRUE);
|
||||
#else
|
||||
gsize len = sci_get_length(doc->editor->sci) + 1;
|
||||
gchar *text = g_malloc(len);
|
||||
|
||||
/* we copy the whole text into memory instead using a direct char pointer from
|
||||
* Scintilla because tm_source_file_buffer_update() does modify the string slightly */
|
||||
sci_get_text(doc->editor->sci, len, text);
|
||||
result = tm_source_file_buffer_update(doc->tm_file, (guchar*) text, len, TRUE);
|
||||
g_free(text);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void document_update_tag_list(GeanyDocument *doc, gboolean update)
|
||||
{
|
||||
/* We must call treeviews_update_tag_list() before returning,
|
||||
@ -2006,14 +2044,14 @@ void document_update_tag_list(GeanyDocument *doc, gboolean update)
|
||||
else
|
||||
{
|
||||
if (update)
|
||||
tm_source_file_update(doc->tm_file, TRUE, FALSE, TRUE);
|
||||
update_tags_from_buffer(doc);
|
||||
success = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
success = tm_source_file_update(doc->tm_file, TRUE, FALSE, TRUE);
|
||||
success = update_tags_from_buffer(doc);
|
||||
if (! success)
|
||||
geany_debug("tag list updating failed");
|
||||
}
|
||||
|
@ -169,6 +169,7 @@ typedef struct sTokenInfo {
|
||||
vString* name; /* the name of the token */
|
||||
unsigned long lineNumber; /* line number of tag */
|
||||
fpos_t filePosition; /* file position of line containing name */
|
||||
int bufferPosition; /* buffer position of line containing name */
|
||||
} tokenInfo;
|
||||
|
||||
typedef enum eImplementation {
|
||||
@ -506,7 +507,10 @@ static void initToken (tokenInfo* const token)
|
||||
token->type = TOKEN_NONE;
|
||||
token->keyword = KEYWORD_NONE;
|
||||
token->lineNumber = getSourceLineNumber ();
|
||||
token->filePosition = getInputFilePosition ();
|
||||
if (useFile())
|
||||
token->filePosition = getInputFilePosition ();
|
||||
else
|
||||
token->bufferPosition = getInputBufferPosition ();
|
||||
vStringClear (token->name);
|
||||
}
|
||||
|
||||
@ -1057,8 +1061,16 @@ static void addOtherFields (tagEntryInfo* const tag, const tagType type,
|
||||
tag->extensionFields.access = accessField (st);
|
||||
}
|
||||
if ((TRUE == st->gotArgs) && (TRUE == Option.extensionFields.argList) &&
|
||||
((TAG_FUNCTION == type) || (TAG_METHOD == type) || (TAG_PROTOTYPE == type))) {
|
||||
tag->extensionFields.arglist = getArglistFromPos(tag->filePosition, tag->name);
|
||||
((TAG_FUNCTION == type) || (TAG_METHOD == type) || (TAG_PROTOTYPE == type)))
|
||||
{
|
||||
if (useFile()) {
|
||||
tag->extensionFields.arglist = getArglistFromFilePos(
|
||||
tag->filePosition, tag->name);
|
||||
}
|
||||
else {
|
||||
tag->extensionFields.arglist = getArglistFromBufferPos(
|
||||
tag->bufferPosition, tag->name);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1233,8 +1245,11 @@ static void makeTag (const tokenInfo *const token,
|
||||
initTagEntry (&e, vStringValue (token->name));
|
||||
|
||||
e.lineNumber = token->lineNumber;
|
||||
e.filePosition = token->filePosition;
|
||||
e.isFileScope = isFileScope;
|
||||
if (useFile())
|
||||
e.filePosition = token->filePosition;
|
||||
else
|
||||
e.bufferPosition = token->bufferPosition;
|
||||
e.isFileScope = isFileScope;
|
||||
e.kindName = tagName (type);
|
||||
e.kind = tagLetter (type);
|
||||
e.type = type;
|
||||
@ -1688,7 +1703,10 @@ static void copyToken (tokenInfo *const dest, const tokenInfo *const src)
|
||||
{
|
||||
dest->type = src->type;
|
||||
dest->keyword = src->keyword;
|
||||
dest->filePosition = src->filePosition;
|
||||
if (useFile())
|
||||
dest->filePosition = src->filePosition;
|
||||
else
|
||||
dest->bufferPosition = src->bufferPosition;
|
||||
dest->lineNumber = src->lineNumber;
|
||||
vStringCopy (dest->name, src->name);
|
||||
}
|
||||
@ -2199,7 +2217,14 @@ static int parseParens (statementInfo *const st, parenInfo *const info)
|
||||
--depth;
|
||||
}
|
||||
if (st->argEndPosition == 0)
|
||||
st->argEndPosition = ftell(File.fp);
|
||||
{
|
||||
if (useFile())
|
||||
st->argEndPosition = ftell(File.fp);
|
||||
else
|
||||
/* FIXME File.fpBufferPosition is wrong here, this breaks function signatures and
|
||||
* so Geany's calltips */
|
||||
st->argEndPosition = File.fpBufferPosition;
|
||||
}
|
||||
|
||||
if (! info->isNameCandidate)
|
||||
initToken (token);
|
||||
|
@ -403,6 +403,7 @@ extern void initTagEntry (tagEntryInfo *const e, const char *const name)
|
||||
e->lineNumber = getSourceLineNumber ();
|
||||
e->language = getSourceLanguageName ();
|
||||
e->filePosition = getInputFilePosition ();
|
||||
e->bufferPosition = getInputBufferPosition ();
|
||||
e->sourceFileName = getSourceFileTagPath ();
|
||||
e->name = name;
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ typedef struct sTagEntryInfo {
|
||||
boolean lineNumberEntry;/* pattern or line number entry */
|
||||
unsigned long lineNumber; /* line number of tag */
|
||||
fpos_t filePosition; /* file position of line containing tag */
|
||||
int bufferPosition; /* buffer position of line containing tag */
|
||||
const char* language; /* language of source file */
|
||||
boolean isFileScope; /* is tag visibile only within source file? */
|
||||
boolean isFileEntry; /* is this just an entry for a file name? */
|
||||
|
@ -155,6 +155,7 @@ typedef struct sTokenInfo {
|
||||
vString* string;
|
||||
unsigned long lineNumber;
|
||||
fpos_t filePosition;
|
||||
int bufferPosition; /* buffer position of line containing name */
|
||||
} tokenInfo;
|
||||
|
||||
/*
|
||||
@ -350,7 +351,10 @@ static void makeFortranTag (tokenInfo *const token, tagType tag)
|
||||
e.lineNumberEntry = (boolean) (Option.locate != EX_PATTERN);
|
||||
|
||||
e.lineNumber = token->lineNumber;
|
||||
e.filePosition = token->filePosition;
|
||||
if (useFile())
|
||||
e.filePosition = token->filePosition;
|
||||
else
|
||||
e.bufferPosition = token->bufferPosition;
|
||||
e.isFileScope = isFileScope (token->tag);
|
||||
e.kindName = FortranKinds [token->tag].name;
|
||||
e.kind = FortranKinds [token->tag].letter;
|
||||
@ -390,7 +394,10 @@ static void makeLabelTag (vString *const label)
|
||||
token.tag = TAG_LABEL;
|
||||
token.string = label;
|
||||
token.lineNumber = getSourceLineNumber ();
|
||||
token.filePosition = getInputFilePosition ();
|
||||
if (useFile())
|
||||
token.filePosition = getInputFilePosition ();
|
||||
else
|
||||
token.bufferPosition = getInputBufferPosition ();
|
||||
|
||||
makeFortranTag (&token, TAG_LABEL);
|
||||
}
|
||||
@ -728,7 +735,10 @@ static tokenInfo *newToken (void)
|
||||
token->tag = TAG_UNDEFINED;
|
||||
token->string = vStringNew ();
|
||||
token->lineNumber = getSourceLineNumber ();
|
||||
token->filePosition = getInputFilePosition ();
|
||||
if (useFile())
|
||||
token->filePosition = getInputFilePosition ();
|
||||
else
|
||||
token->bufferPosition = getInputBufferPosition ();
|
||||
|
||||
return token;
|
||||
}
|
||||
@ -797,7 +807,10 @@ static void readToken (tokenInfo *const token)
|
||||
|
||||
getNextChar:
|
||||
token->lineNumber = getSourceLineNumber ();
|
||||
token->filePosition = getInputFilePosition ();
|
||||
if (useFile())
|
||||
token->filePosition = getInputFilePosition ();
|
||||
else
|
||||
token->bufferPosition = getInputBufferPosition ();
|
||||
|
||||
c = getChar ();
|
||||
|
||||
|
@ -313,8 +313,16 @@ static void makeDefineTag (const char *const name, boolean parameterized)
|
||||
e.kindName = "macro";
|
||||
e.kind = 'd';
|
||||
if (parameterized)
|
||||
e.extensionFields.arglist = getArglistFromPos(getInputFilePosition()
|
||||
, e.name);
|
||||
{
|
||||
if (useFile()) {
|
||||
e.extensionFields.arglist = getArglistFromFilePos(getInputFilePosition()
|
||||
, e.name);
|
||||
}
|
||||
else {
|
||||
e.extensionFields.arglist = getArglistFromBufferPos(getInputBufferPosition()
|
||||
, e.name);
|
||||
}
|
||||
}
|
||||
makeTagEntry (&e);
|
||||
if (parameterized)
|
||||
free((char *) e.extensionFields.arglist);
|
||||
@ -676,16 +684,52 @@ process:
|
||||
return c;
|
||||
}
|
||||
|
||||
extern char *getArglistFromPos(fpos_t startPosition, const char *tokenName)
|
||||
extern char *getArglistFromBufferPos(int startPosition, const char *tokenName)
|
||||
{
|
||||
int bufferOriginalPosition;
|
||||
char *result = NULL;
|
||||
char *arglist = NULL;
|
||||
long pos1, pos2;
|
||||
|
||||
/* FIXME startPosition as well as getBufPos() are mostly wrong here */
|
||||
pos2 = getBufPos();
|
||||
|
||||
if (!useFile()) {
|
||||
bufferOriginalPosition = getBufPos ();
|
||||
setBufPos(startPosition);
|
||||
pos1 = File.fpBufferPosition;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
|
||||
if (pos2 > pos1)
|
||||
{
|
||||
result = (char *) g_malloc(sizeof(char ) * (pos2 - pos1 + 2));
|
||||
if (result != NULL)
|
||||
{
|
||||
memcpy(result, &File.fpBuffer[getBufPos()], pos2 - pos1 + 1);
|
||||
result[pos2-pos1+1] = '\0';
|
||||
arglist = getArglistFromStr(result, tokenName);
|
||||
free(result);
|
||||
}
|
||||
}
|
||||
setBufPos (bufferOriginalPosition);
|
||||
return arglist;
|
||||
}
|
||||
|
||||
extern char *getArglistFromFilePos(fpos_t startPosition, const char *tokenName)
|
||||
{
|
||||
fpos_t originalPosition;
|
||||
char *result = NULL;
|
||||
char *arglist = NULL;
|
||||
long pos1, pos2 = ftell(File.fp);
|
||||
long pos1, pos2;
|
||||
|
||||
pos2 = ftell(File.fp);
|
||||
|
||||
fgetpos(File.fp, &originalPosition);
|
||||
fsetpos(File.fp, &startPosition);
|
||||
pos1 = ftell(File.fp);
|
||||
|
||||
if (pos2 > pos1)
|
||||
{
|
||||
result = (char *) g_malloc(sizeof(char ) * (pos2 - pos1 + 2));
|
||||
|
@ -44,7 +44,8 @@ extern void cppEndStatement (void);
|
||||
extern void cppUngetc (const int c);
|
||||
extern int cppGetc (void);
|
||||
extern int skipOverCComment (void);
|
||||
extern char *getArglistFromPos(fpos_t startPosition, const char *tokenName);
|
||||
extern char *getArglistFromFilePos(fpos_t startPosition, const char *tokenName);
|
||||
extern char *getArglistFromBufferPos(int startPosition, const char *tokenName);
|
||||
extern char *getArglistFromStr(char *buf, const char *name);
|
||||
|
||||
#endif /* _GET_H */
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <glib.h>
|
||||
#include "tm_work_object.h"
|
||||
|
||||
|
||||
/*! \file
|
||||
The TMProject structure and associated functions can be used to group together
|
||||
related source files in a "project". The update, open and save functions take
|
||||
@ -142,6 +143,13 @@ TMWorkObject *tm_project_find_file(TMWorkObject *work_object, const char *file_n
|
||||
*/
|
||||
gboolean tm_project_remove_object(TMProject *project, TMWorkObject *w);
|
||||
|
||||
/*! Removes only the project-tags associated with the object. Then resort the project's tags.
|
||||
\param project The project from which the file's tags are to be removed.
|
||||
\param w The member work object (source file) to remove the tags.
|
||||
\return TRUE on success, FALSE on failure
|
||||
*/
|
||||
gboolean tm_project_remove_tags_from_list(TMProject *project, TMWorkObject *w);
|
||||
|
||||
/*! Updates the project database and all the source files contained in the
|
||||
project. All sorting and deduping is lost and should be redone.
|
||||
\param work_object The project to update.
|
||||
|
@ -110,6 +110,7 @@ typedef struct sTokenInfo {
|
||||
fpos_t filePosition;
|
||||
int nestLevel;
|
||||
boolean ignoreTag;
|
||||
int bufferPosition; /* buffer position of line containing name */
|
||||
} tokenInfo;
|
||||
|
||||
/*
|
||||
@ -197,7 +198,10 @@ static tokenInfo *newToken (void)
|
||||
token->nestLevel = 0;
|
||||
token->ignoreTag = FALSE;
|
||||
token->lineNumber = getSourceLineNumber ();
|
||||
token->filePosition = getInputFilePosition ();
|
||||
if (useFile())
|
||||
token->filePosition = getInputFilePosition ();
|
||||
else
|
||||
token->bufferPosition = getInputBufferPosition ();
|
||||
|
||||
return token;
|
||||
}
|
||||
@ -353,8 +357,11 @@ getNextChar:
|
||||
{
|
||||
c = fileGetc ();
|
||||
token->lineNumber = getSourceLineNumber ();
|
||||
token->filePosition = getInputFilePosition ();
|
||||
}
|
||||
if (useFile())
|
||||
token->filePosition = getInputFilePosition ();
|
||||
else
|
||||
token->bufferPosition = getInputBufferPosition ();
|
||||
}
|
||||
while (c == '\t' || c == ' ' || c == '\n');
|
||||
|
||||
switch (c)
|
||||
@ -377,7 +384,10 @@ getNextChar:
|
||||
token->type = TOKEN_STRING;
|
||||
parseString (token->string, c);
|
||||
token->lineNumber = getSourceLineNumber ();
|
||||
token->filePosition = getInputFilePosition ();
|
||||
if (useFile())
|
||||
token->filePosition = getInputFilePosition ();
|
||||
else
|
||||
token->bufferPosition = getInputBufferPosition ();
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
@ -386,7 +396,10 @@ getNextChar:
|
||||
fileUngetc (c);
|
||||
token->type = TOKEN_CHARACTER;
|
||||
token->lineNumber = getSourceLineNumber ();
|
||||
token->filePosition = getInputFilePosition ();
|
||||
if (useFile())
|
||||
token->filePosition = getInputFilePosition ();
|
||||
else
|
||||
token->bufferPosition = getInputBufferPosition ();
|
||||
break;
|
||||
|
||||
case '/':
|
||||
@ -429,7 +442,10 @@ getNextChar:
|
||||
{
|
||||
parseIdentifier (token->string, c);
|
||||
token->lineNumber = getSourceLineNumber ();
|
||||
token->filePosition = getInputFilePosition ();
|
||||
if (useFile())
|
||||
token->filePosition = getInputFilePosition ();
|
||||
else
|
||||
token->bufferPosition = getInputBufferPosition ();
|
||||
token->keyword = analyzeToken (token->string);
|
||||
if (isKeyword (token, KEYWORD_NONE))
|
||||
token->type = TOKEN_IDENTIFIER;
|
||||
@ -444,7 +460,10 @@ static void copyToken (tokenInfo *const dest, tokenInfo *const src)
|
||||
{
|
||||
dest->nestLevel = src->nestLevel;
|
||||
dest->lineNumber = src->lineNumber;
|
||||
dest->filePosition = src->filePosition;
|
||||
if (useFile())
|
||||
dest->filePosition = src->filePosition;
|
||||
else
|
||||
dest->bufferPosition = src->bufferPosition;
|
||||
dest->type = src->type;
|
||||
dest->keyword = src->keyword;
|
||||
vStringCopy(dest->string, src->string);
|
||||
|
@ -29,6 +29,11 @@
|
||||
*/
|
||||
inputFile File; /* globally read through macros */
|
||||
static fpos_t StartOfLine; /* holds deferred position of start of line */
|
||||
static int bufferStartOfLine; /* the same as StartOfLine but for buffer */
|
||||
|
||||
|
||||
static int readNextChar (void);
|
||||
static int pushBackChar (int c);
|
||||
|
||||
/*
|
||||
* FUNCTION DEFINITIONS
|
||||
@ -115,7 +120,7 @@ static int skipWhite (void)
|
||||
{
|
||||
int c;
|
||||
do
|
||||
c = getc (File.fp);
|
||||
c = readNextChar ();
|
||||
while (c == ' ' || c == '\t');
|
||||
return c;
|
||||
}
|
||||
@ -127,9 +132,9 @@ static unsigned long readLineNumber (void)
|
||||
while (c != EOF && isdigit (c))
|
||||
{
|
||||
lNum = (lNum * 10) + (c - '0');
|
||||
c = getc (File.fp);
|
||||
c = readNextChar ();
|
||||
}
|
||||
ungetc (c, File.fp);
|
||||
pushBackChar (c);
|
||||
if (c != ' ' && c != '\t')
|
||||
lNum = 0;
|
||||
|
||||
@ -152,17 +157,17 @@ static vString *readFileName (void)
|
||||
|
||||
if (c == '"')
|
||||
{
|
||||
c = getc (File.fp); /* skip double-quote */
|
||||
c = readNextChar (); /* skip double-quote */
|
||||
quoteDelimited = TRUE;
|
||||
}
|
||||
while (c != EOF && c != '\n' &&
|
||||
(quoteDelimited ? (c != '"') : (c != ' ' && c != '\t')))
|
||||
{
|
||||
vStringPut (fileName, c);
|
||||
c = getc (File.fp);
|
||||
c = readNextChar ();
|
||||
}
|
||||
if (c == '\n')
|
||||
ungetc (c, File.fp);
|
||||
pushBackChar (c);
|
||||
vStringPut (fileName, '\0');
|
||||
|
||||
return fileName;
|
||||
@ -176,13 +181,13 @@ static boolean parseLineDirective (void)
|
||||
|
||||
if (isdigit (c))
|
||||
{
|
||||
ungetc (c, File.fp);
|
||||
pushBackChar (c);
|
||||
result = TRUE;
|
||||
}
|
||||
else if (c == 'l' && getc (File.fp) == 'i' &&
|
||||
getc (File.fp) == 'n' && getc (File.fp) == 'e')
|
||||
else if (c == 'l' && readNextChar () == 'i' &&
|
||||
readNextChar () == 'n' && readNextChar () == 'e')
|
||||
{
|
||||
c = getc (File.fp);
|
||||
c = readNextChar ();
|
||||
if (c == ' ' || c == '\t')
|
||||
{
|
||||
DebugStatement ( lineStr = "line"; )
|
||||
@ -283,6 +288,60 @@ extern boolean fileOpen (const char *const fileName, const langType language)
|
||||
return opened;
|
||||
}
|
||||
|
||||
/* The user should take care of allocate and free the buffer param.
|
||||
* This func is NOT THREAD SAFE.
|
||||
* The user should not tamper with the buffer while this func is executing.
|
||||
*/
|
||||
extern boolean bufferOpen (unsigned char *buffer, int buffer_size,
|
||||
const char *const fileName, const langType language )
|
||||
{
|
||||
boolean opened = FALSE;
|
||||
|
||||
/* Check whether a file of a buffer were already open, then close them.
|
||||
*/
|
||||
if (File.fp != NULL) {
|
||||
fclose (File.fp); /* close any open source file */
|
||||
File.fp = NULL;
|
||||
}
|
||||
|
||||
if (File.fpBuffer != NULL) {
|
||||
error(PERROR, "An unallocated buffer was found. Please check you called \
|
||||
correctly bufferClose ()\n");
|
||||
File.fpBuffer = NULL;
|
||||
}
|
||||
|
||||
/* check if we got a good buffer */
|
||||
if (buffer == NULL || buffer_size == 0) {
|
||||
opened = FALSE;
|
||||
return opened;
|
||||
}
|
||||
|
||||
opened = TRUE;
|
||||
|
||||
File.fpBuffer = buffer;
|
||||
setInputFileName (fileName);
|
||||
bufferStartOfLine = 0;
|
||||
File.fpBufferPosition = 0;
|
||||
File.fpBufferSize = buffer_size;
|
||||
File.currentLine = NULL;
|
||||
File.language = language;
|
||||
File.lineNumber = 0L;
|
||||
File.eof = FALSE;
|
||||
File.newLine = TRUE;
|
||||
|
||||
if (File.line != NULL)
|
||||
vStringClear (File.line);
|
||||
|
||||
setSourceFileParameters (vStringNewInit (fileName), language);
|
||||
File.source.lineNumber = 0L;
|
||||
|
||||
verbose ("OPENING %s as %s language %sfile\n", fileName,
|
||||
getLanguageName (language),
|
||||
File.source.isHeader ? "include " : "");
|
||||
|
||||
return opened;
|
||||
}
|
||||
|
||||
extern void fileClose (void)
|
||||
{
|
||||
if (File.fp != NULL)
|
||||
@ -299,6 +358,14 @@ extern void fileClose (void)
|
||||
}
|
||||
}
|
||||
|
||||
/* user should take care of freeing the buffer */
|
||||
extern void bufferClose (void)
|
||||
{
|
||||
if (File.fpBuffer != NULL) {
|
||||
File.fpBuffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
extern boolean fileEOF (void)
|
||||
{
|
||||
return File.eof;
|
||||
@ -323,7 +390,7 @@ static int iFileGetc (void)
|
||||
{
|
||||
int c;
|
||||
readnext:
|
||||
c = getc (File.fp);
|
||||
c = readNextChar ();
|
||||
|
||||
/* If previous character was a newline, then we're starting a line.
|
||||
*/
|
||||
@ -336,8 +403,13 @@ readnext:
|
||||
goto readnext;
|
||||
else
|
||||
{
|
||||
fsetpos (File.fp, &StartOfLine);
|
||||
c = getc (File.fp);
|
||||
/* FIXME: find out a better way to do this check */
|
||||
if (File.fp != NULL)
|
||||
fsetpos (File.fp, &StartOfLine);
|
||||
else
|
||||
File.fpBufferPosition = bufferStartOfLine;
|
||||
|
||||
c = readNextChar ();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -346,8 +418,10 @@ readnext:
|
||||
File.eof = TRUE;
|
||||
else if (c == NEWLINE)
|
||||
{
|
||||
File.newLine = TRUE;
|
||||
fgetpos (File.fp, &StartOfLine);
|
||||
if (File.fp != NULL) /* we have a file */
|
||||
fgetpos (File.fp, &StartOfLine);
|
||||
else /* it's a buffer */
|
||||
bufferStartOfLine = File.fpBufferPosition;
|
||||
}
|
||||
else if (c == CRETURN)
|
||||
{
|
||||
@ -355,14 +429,17 @@ readnext:
|
||||
* used forms if line breaks: LF (UNIX), CR (MacIntosh), and
|
||||
* CR-LF (MS-DOS) are converted into a generic newline.
|
||||
*/
|
||||
const int next = getc (File.fp); /* is CR followed by LF? */
|
||||
const int next = readNextChar (); /* is CR followed by LF? */
|
||||
|
||||
if (next != NEWLINE)
|
||||
ungetc (next, File.fp);
|
||||
pushBackChar (next);
|
||||
|
||||
c = NEWLINE; /* convert CR into newline */
|
||||
File.newLine = TRUE;
|
||||
fgetpos (File.fp, &StartOfLine);
|
||||
if (File.fp != NULL)
|
||||
fgetpos (File.fp, &StartOfLine);
|
||||
else
|
||||
bufferStartOfLine = File.fpBufferPosition;
|
||||
}
|
||||
DebugStatement ( debugPutc (DEBUG_RAW, c); )
|
||||
return c;
|
||||
@ -457,8 +534,67 @@ extern const unsigned char *fileReadLine (void)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Read a character choosing automatically between file or buffer, depending
|
||||
* on which mode we are.
|
||||
*/
|
||||
static int readNextChar(void)
|
||||
{
|
||||
if (File.fp != NULL) {
|
||||
return getc(File.fp);
|
||||
}
|
||||
else {
|
||||
int c;
|
||||
if (File.fpBufferPosition >= File.fpBufferSize)
|
||||
return EOF;
|
||||
|
||||
c = File.fpBuffer[File.fpBufferPosition];
|
||||
File.fpBufferPosition++;
|
||||
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
/* Replaces ungetc() for file. In case of buffer we'll perform the same action:
|
||||
* fpBufferPosition-- and write of the param char into the buf.
|
||||
*/
|
||||
static int pushBackChar (int c)
|
||||
{
|
||||
if (File.fp != NULL) {
|
||||
return ungetc (c, File.fp);
|
||||
}
|
||||
else {
|
||||
File.fpBufferPosition--;
|
||||
if (File.fpBufferPosition < 0)
|
||||
return EOF;
|
||||
File.fpBuffer[File.fpBufferPosition] = c;
|
||||
return File.fpBuffer[File.fpBufferPosition];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* replacement for fsetpos, applied to a buffer */
|
||||
extern void setBufPos (int new_position)
|
||||
{
|
||||
File.fpBufferPosition = new_position;
|
||||
}
|
||||
|
||||
/* replacement for fgetpos, applied to a buffer */
|
||||
extern int getBufPos (void)
|
||||
{
|
||||
return File.fpBufferPosition;
|
||||
}
|
||||
|
||||
extern boolean useFile (void)
|
||||
{
|
||||
if (File.fp != NULL)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Source file line reading with automatic buffer sizing
|
||||
* Does not perform file/buffer checks. Only file is supported.
|
||||
*/
|
||||
extern char *readLine (vString *const vLine, FILE *const fp)
|
||||
{
|
||||
|
@ -33,6 +33,7 @@
|
||||
#define getInputLineNumber() File.lineNumber
|
||||
#define getInputFileName() vStringValue (File.source.name)
|
||||
#define getInputFilePosition() File.filePosition
|
||||
#define getInputBufferPosition() File.fpBufferPosition
|
||||
#define getSourceFileName() vStringValue (File.source.name)
|
||||
#define getSourceFileTagPath() File.source.tagPath
|
||||
#define getSourceLanguage() File.source.language
|
||||
@ -73,6 +74,10 @@ typedef struct sInputFile {
|
||||
vString *line; /* last line read from file */
|
||||
const unsigned char* currentLine; /* current line being worked on */
|
||||
FILE *fp; /* stream used for reading the file */
|
||||
unsigned char* fpBuffer; /* buffer which contains the text to be parsed.
|
||||
This is optional to the use of a file-descriptor */
|
||||
int fpBufferSize; /* size of the fpBuffer */
|
||||
int fpBufferPosition; /* pointer to the current position in buffer */
|
||||
unsigned long lineNumber; /* line number in the input file */
|
||||
fpos_t filePosition; /* file position of current line */
|
||||
int ungetch; /* a single character that was ungotten */
|
||||
@ -116,6 +121,13 @@ extern const unsigned char *fileReadLine (void);
|
||||
extern char *readLine (vString *const vLine, FILE *const fp);
|
||||
extern char *readSourceLine (vString *const vLine, fpos_t location, long *const pSeekValue);
|
||||
|
||||
extern boolean bufferOpen (unsigned char *buffer, int buffer_size,
|
||||
const char *const fileName, const langType language );
|
||||
extern void bufferClose (void);
|
||||
extern void setBufPos (int new_position);
|
||||
extern int getBufPos ();
|
||||
extern boolean useFile ();
|
||||
|
||||
#endif /* _READ_H */
|
||||
|
||||
/* vi:set tabstop=8 shiftwidth=4: */
|
||||
|
@ -138,6 +138,7 @@ typedef struct sTokenInfo {
|
||||
vString * scope;
|
||||
unsigned long lineNumber;
|
||||
fpos_t filePosition;
|
||||
int bufferPosition; /* buffer position of line containing name */
|
||||
} tokenInfo;
|
||||
|
||||
/*
|
||||
@ -274,30 +275,30 @@ static void dispToken (tokenInfo *const token, char * location)
|
||||
{
|
||||
if ( isType(token, TOKEN_IDENTIFIER) || isType(token, TOKEN_STRING) )
|
||||
{
|
||||
printf( "\n%s: token string t:%s s:%s l:%lu p:%ld\n"
|
||||
printf( "\n%s: token string t:%s s:%s l:%lu p:%d\n"
|
||||
, location
|
||||
, vStringValue(token->string)
|
||||
, vStringValue(token->scope)
|
||||
, token->lineNumber
|
||||
, token->filePosition
|
||||
, token->bufferPosition
|
||||
);
|
||||
} else {
|
||||
printf( "\n%s: token t:%d s:%s l:%lu p:%lu\n"
|
||||
printf( "\n%s: token t:%d s:%s l:%lu p:%d\n"
|
||||
, location
|
||||
, token->type
|
||||
, vStringValue(token->scope)
|
||||
, token->lineNumber
|
||||
, token->filePosition
|
||||
, token->bufferPosition
|
||||
);
|
||||
}
|
||||
} else {
|
||||
printf( "\n%s: keyword:%s k:%d s:%s l:%lu p:%ld\n"
|
||||
printf( "\n%s: keyword:%s k:%d s:%s l:%lu p:%d\n"
|
||||
, location
|
||||
, vStringValue(token->string)
|
||||
, token->keyword
|
||||
, vStringValue(token->scope)
|
||||
, token->lineNumber
|
||||
, token->filePosition
|
||||
, token->bufferPosition
|
||||
);
|
||||
}
|
||||
#endif
|
||||
@ -391,7 +392,10 @@ static void makeConstTag (tokenInfo *const token, const sqlKind kind)
|
||||
initTagEntry (&e, name);
|
||||
|
||||
e.lineNumber = token->lineNumber;
|
||||
e.filePosition = token->filePosition;
|
||||
if (useFile())
|
||||
e.filePosition = token->filePosition;
|
||||
else
|
||||
e.bufferPosition = token->bufferPosition;
|
||||
e.kindName = SqlKinds [kind].name;
|
||||
e.kind = SqlKinds [kind].letter;
|
||||
|
||||
@ -491,7 +495,10 @@ getNextChar:
|
||||
token->type = TOKEN_STRING;
|
||||
parseString (token->string, c);
|
||||
token->lineNumber = getSourceLineNumber ();
|
||||
token->filePosition = getInputFilePosition ();
|
||||
if (useFile())
|
||||
token->filePosition = getInputFilePosition ();
|
||||
else
|
||||
token->bufferPosition = getInputBufferPosition ();
|
||||
break;
|
||||
|
||||
case '-':
|
||||
@ -557,7 +564,10 @@ getNextChar:
|
||||
{
|
||||
parseIdentifier (token->string, c);
|
||||
token->lineNumber = getSourceLineNumber ();
|
||||
token->filePosition = getInputFilePosition ();
|
||||
if (useFile())
|
||||
token->filePosition = getInputFilePosition ();
|
||||
else
|
||||
token->bufferPosition = getInputBufferPosition ();
|
||||
token->keyword = analyzeToken (token->string);
|
||||
if (isKeyword (token, KEYWORD_rem))
|
||||
{
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "tm_source_file.h"
|
||||
#include "tm_tag.h"
|
||||
|
||||
|
||||
guint source_file_class_id = 0;
|
||||
static TMSourceFile *current_source_file = NULL;
|
||||
|
||||
@ -154,6 +155,76 @@ gboolean tm_source_file_parse(TMSourceFile *source_file)
|
||||
return status;
|
||||
}
|
||||
|
||||
gboolean tm_source_file_buffer_parse(TMSourceFile *source_file, guchar* text_buf, gint buf_size)
|
||||
{
|
||||
const char *file_name;
|
||||
gboolean status = TRUE;
|
||||
|
||||
if ((NULL == source_file) || (NULL == source_file->work_object.file_name))
|
||||
{
|
||||
g_warning("Attempt to parse NULL file");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((NULL == text_buf) || (0 == buf_size))
|
||||
{
|
||||
g_warning("Attempt to parse a NULL text buffer");
|
||||
}
|
||||
|
||||
file_name = source_file->work_object.file_name;
|
||||
if (NULL == LanguageTable)
|
||||
{
|
||||
initializeParsing();
|
||||
installLanguageMapDefaults();
|
||||
if (NULL == TagEntryFunction)
|
||||
TagEntryFunction = tm_source_file_tags;
|
||||
}
|
||||
current_source_file = source_file;
|
||||
if (LANG_AUTO == source_file->lang)
|
||||
source_file->lang = getFileLanguage (file_name);
|
||||
if (source_file->lang == LANG_IGNORE)
|
||||
{
|
||||
#ifdef TM_DEBUG
|
||||
g_warning("ignoring %s (unknown language)\n", file_name);
|
||||
#endif
|
||||
}
|
||||
else if (! LanguageTable [source_file->lang]->enabled)
|
||||
{
|
||||
#ifdef TM_DEBUG
|
||||
g_warning("ignoring %s (language disabled)\n", file_name);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
int passCount = 0;
|
||||
while ((TRUE == status) && (passCount < 3))
|
||||
{
|
||||
if (source_file->work_object.tags_array)
|
||||
tm_tags_array_free(source_file->work_object.tags_array, FALSE);
|
||||
if (bufferOpen (text_buf, buf_size, file_name, source_file->lang))
|
||||
{
|
||||
if (LanguageTable [source_file->lang]->parser != NULL)
|
||||
{
|
||||
LanguageTable [source_file->lang]->parser ();
|
||||
bufferClose ();
|
||||
break;
|
||||
}
|
||||
else if (LanguageTable [source_file->lang]->parser2 != NULL)
|
||||
status = LanguageTable [source_file->lang]->parser2 (passCount);
|
||||
bufferClose ();
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning("Unable to open %s", file_name);
|
||||
return FALSE;
|
||||
}
|
||||
++ passCount;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int tm_source_file_tags(const tagEntryInfo *tag)
|
||||
{
|
||||
if (NULL == current_source_file)
|
||||
@ -179,10 +250,42 @@ gboolean tm_source_file_update(TMWorkObject *source_file, gboolean force
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
else {
|
||||
#ifdef TM_DEBUG
|
||||
g_message ("no parsing of %s has been done", source_file->file_name);
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
gboolean tm_source_file_buffer_update(TMWorkObject *source_file, guchar* text_buf,
|
||||
gint buf_size, gboolean update_parent)
|
||||
{
|
||||
#ifdef TM_DEBUG
|
||||
g_message("Buffer updating based on source file %s", source_file->file_name);
|
||||
#endif
|
||||
|
||||
tm_source_file_buffer_parse (TM_SOURCE_FILE(source_file), text_buf, buf_size);
|
||||
tm_tags_sort(source_file->tags_array, NULL, FALSE);
|
||||
source_file->analyze_time = time(NULL);
|
||||
if ((source_file->parent) && update_parent)
|
||||
{
|
||||
#ifdef TM_DEBUG
|
||||
g_message("Updating parent [project] from buffer..");
|
||||
#endif
|
||||
tm_work_object_update(source_file->parent, TRUE, FALSE, TRUE);
|
||||
}
|
||||
#ifdef TM_DEBUG
|
||||
else
|
||||
g_message("Skipping parent update because parent is %s and update_parent is %s"
|
||||
, source_file->parent?"NOT NULL":"NULL", update_parent?"TRUE":"FALSE");
|
||||
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
gboolean tm_source_file_write(TMWorkObject *source_file, FILE *fp, guint attrs)
|
||||
{
|
||||
TMTag *tag;
|
||||
|
@ -631,7 +631,7 @@ TMTag **tm_tags_find(const GPtrArray *sorted_tags_array, const char *name,
|
||||
s_partial = partial;
|
||||
result = (TMTag **) bsearch(&tag, sorted_tags_array->pdata, sorted_tags_array->len
|
||||
, sizeof(gpointer), tm_tag_compare);
|
||||
/* there can be matches on both sides of result */
|
||||
/* There can be matches on both sides of result */
|
||||
if (result)
|
||||
{
|
||||
TMTag **last = (TMTag **) &sorted_tags_array->pdata[sorted_tags_array->len - 1];
|
||||
@ -640,7 +640,7 @@ TMTag **tm_tags_find(const GPtrArray *sorted_tags_array, const char *name,
|
||||
/* First look for any matches after result */
|
||||
adv = result;
|
||||
adv++;
|
||||
for (; *adv && adv <= last; ++ adv)
|
||||
for (; adv <= last && *adv; ++ adv)
|
||||
{
|
||||
if (0 != tm_tag_compare(&tag, adv))
|
||||
break;
|
||||
@ -654,7 +654,7 @@ TMTag **tm_tags_find(const GPtrArray *sorted_tags_array, const char *name,
|
||||
++tagMatches;
|
||||
}
|
||||
*tagCount=tagMatches;
|
||||
++ result; /* correct address for the last successful match */
|
||||
++ result; /* Correct address for the last successful match */
|
||||
}
|
||||
s_partial = FALSE;
|
||||
return (TMTag **) result;
|
||||
|
Loading…
x
Reference in New Issue
Block a user