257 lines
5.6 KiB
C
257 lines
5.6 KiB
C
/* This file is part of the software similarity tester SIM.
|
|
Written by Dick Grune, Vrije Universiteit, Amsterdam.
|
|
$Id: text.c,v 1.23 2016-08-03 19:14:04 dick Exp $
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "debug.par"
|
|
#include "sim.h"
|
|
#include "token.h"
|
|
#include "stream.h"
|
|
#include "lang.h"
|
|
#include "Malloc.h"
|
|
#include "options.h"
|
|
#include "text.h"
|
|
|
|
struct text *Text; /* to be filled in by Malloc() */
|
|
int Number_of_Texts;
|
|
int Number_of_New_Texts;
|
|
|
|
typedef unsigned short nl_tk_diff_t;
|
|
|
|
struct newline {
|
|
nl_tk_diff_t nl_tk_diff; /* token position difference */
|
|
};
|
|
|
|
#define NL_START 1024 /* initial newline buffer size */
|
|
|
|
static struct newline *nl_buff; /* to be filled by Malloc() */
|
|
static size_t nl_size; /* size of nl_buff[] */
|
|
static size_t nl_free; /* next free position in nl_buff[] */
|
|
|
|
static size_t nl_next, nl_limit; /* nl_buff[] pointers during pass 2 */
|
|
|
|
static void store_newline(void);
|
|
static void init_nl_buff(void);
|
|
|
|
/* TEXT INTERFACE */
|
|
|
|
static size_t last_tk_cnt; /* token count at newline */
|
|
static size_t last_nl_cnt; /* nl counter during pass 2 */
|
|
|
|
void
|
|
Init_Text(int nfiles) {
|
|
/* allocate the array of text descriptors */
|
|
if (Text) {
|
|
Free(Text);
|
|
Text = 0;
|
|
}
|
|
Number_of_Texts = nfiles;
|
|
Text = (struct text *)
|
|
Malloc((size_t)(Number_of_Texts*sizeof (struct text)));
|
|
|
|
init_nl_buff();
|
|
}
|
|
|
|
int
|
|
Open_Text(enum Pass pass, struct text *txt) {
|
|
switch (pass) {
|
|
case First_Pass:
|
|
last_tk_cnt = 0;
|
|
if (nl_buff) {
|
|
txt->tx_nl_start = nl_free;
|
|
}
|
|
break;
|
|
|
|
case Second_Pass:
|
|
last_tk_cnt = 0;
|
|
if (nl_buff) {
|
|
nl_next = txt->tx_nl_start;
|
|
nl_limit = txt->tx_nl_limit;
|
|
last_nl_cnt = 1;
|
|
lex_nl_cnt = 1;
|
|
lex_tk_cnt = 0;
|
|
return 1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return Open_Stream(txt->tx_fname);
|
|
}
|
|
|
|
int
|
|
Next_Text_Token_Obtained(void) {
|
|
if (!Next_Stream_Token_Obtained()) return 0;
|
|
if (Token_EQ(lex_token, End_Of_Line)) {
|
|
store_newline();
|
|
last_tk_cnt = lex_tk_cnt;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
Next_Text_EOL_Obtained(void) {
|
|
/* get newline info from the buffer or from the file itself */
|
|
if (nl_buff) {
|
|
if (nl_next == nl_limit) return 0;
|
|
|
|
struct newline *nl = &nl_buff[nl_next++];
|
|
lex_nl_cnt = ++last_nl_cnt;
|
|
lex_tk_cnt = (last_tk_cnt += nl->nl_tk_diff);
|
|
lex_token = End_Of_Line;
|
|
return 1;
|
|
} else {
|
|
int ok;
|
|
while ( (ok = Next_Stream_Token_Obtained())
|
|
&& !Token_EQ(lex_token, End_Of_Line)
|
|
) {
|
|
/* skip */
|
|
}
|
|
return ok;
|
|
}
|
|
}
|
|
|
|
void
|
|
Close_Text(enum Pass pass, struct text *txt) {
|
|
switch (pass) {
|
|
case First_Pass:
|
|
if (nl_buff) {
|
|
if (last_tk_cnt != lex_tk_cnt) {
|
|
/* there were tokens after the last newline */
|
|
store_newline();
|
|
}
|
|
txt->tx_nl_limit = nl_free;
|
|
}
|
|
break;
|
|
case Second_Pass:
|
|
break;
|
|
}
|
|
Close_Stream();
|
|
}
|
|
|
|
void
|
|
Free_Text(void) {
|
|
if (nl_buff) {
|
|
Free(nl_buff); nl_buff = 0;
|
|
}
|
|
if (Text) {
|
|
Free(Text); Text = 0;
|
|
}
|
|
}
|
|
|
|
/* NEWLINE CACHING */
|
|
|
|
/* To speed up pass2 which is interested in token positions at line ends,
|
|
the newline buffer keeps this info from pass1. To reduce the size of
|
|
the newline buffer, the info is kept as the differences of the values
|
|
at consecutive line ends. This allows unsigned chars to be used rather
|
|
than integers.
|
|
|
|
The recording of token position differences at End_Of_Line is optional,
|
|
and is switched off if
|
|
- there is not room enough for the newline buffer;
|
|
- a difference would not fit in the field in the struct;
|
|
- we are reporting percentages.
|
|
Switching off is done by freeing the buffer and setting nl_buff to 0.
|
|
Anybody using nl_buff should therefore test for nl_buff being zero.
|
|
*/
|
|
|
|
static void abandon_nl_buff(const char *);
|
|
|
|
static void
|
|
init_nl_buff(void) {
|
|
/* if we are doing percentages, we don't need the nl_buff mechanism */
|
|
if (is_set_option('p')) return;
|
|
|
|
/* Allocate the newline buffer, if possible */
|
|
nl_size = 0 + NL_START;
|
|
nl_buff = (struct newline *)TryMalloc(sizeof (struct newline)*nl_size);
|
|
nl_free = 0;
|
|
}
|
|
|
|
static void
|
|
store_newline(void) {
|
|
if (!nl_buff) return;
|
|
|
|
if (nl_free == nl_size) {
|
|
/* allocated array is full; try to increase its size */
|
|
size_t new_size = nl_size + nl_size/2;
|
|
if (new_size < nl_free) {
|
|
abandon_nl_buff("out of address space");
|
|
return;
|
|
}
|
|
|
|
struct newline *new_buff = (struct newline *)TryRealloc(
|
|
(char *)nl_buff,
|
|
sizeof (struct newline) * new_size
|
|
);
|
|
|
|
if (!new_buff) {
|
|
abandon_nl_buff("out of memry");
|
|
return;
|
|
}
|
|
nl_buff = new_buff, nl_size = new_size;
|
|
}
|
|
|
|
/* now we are sure there is room enough */
|
|
{
|
|
struct newline *nl = &nl_buff[nl_free++];
|
|
size_t tk_diff = lex_tk_cnt - last_tk_cnt;
|
|
|
|
nl->nl_tk_diff = (nl_tk_diff_t) tk_diff;
|
|
if (nl->nl_tk_diff != tk_diff) {
|
|
abandon_nl_buff("tk_diff does not fit in nl_tk_diff");
|
|
}
|
|
}
|
|
}
|
|
|
|
static void /*ARGSUSED*/
|
|
abandon_nl_buff(const char *msg) {
|
|
#undef DB_BUFF
|
|
#ifdef DB_BUFF
|
|
fprintf(Debug_File, "abandon_nl_buff, %s\n", msg);
|
|
#endif /* DB_BUFF */
|
|
if (nl_buff) {
|
|
Free(nl_buff);
|
|
nl_buff = 0;
|
|
}
|
|
}
|
|
|
|
#ifdef DB_NL_BUFF
|
|
|
|
void
|
|
db_print_nl_buff(size_t start, size_t limit) {
|
|
size_t i;
|
|
|
|
fprintf(Debug_File, "\n**** DB_NL_BUFF ****\n");
|
|
if (!nl_buff) {
|
|
fprintf(Debug_File, ">>>> NO NL_BUFF\n\n");
|
|
return;
|
|
}
|
|
|
|
if (start > nl_free) {
|
|
fprintf(Debug_File, ">>>> start (%s) > nl_free (%s)\n\n",
|
|
size_t2string(start), size_t2string(nl_free)
|
|
);
|
|
return;
|
|
}
|
|
if (limit > nl_free) {
|
|
fprintf(Debug_File, ">>>> limit (%s) > nl_free (%s)\n\n",
|
|
size_t2string(limit), size_t2string(nl_free)
|
|
);
|
|
return;
|
|
}
|
|
|
|
fprintf(Debug_File, "nl_buff: %s entries:\n", size_t2string(nl_free));
|
|
for (i = start; i < limit; i++) {
|
|
struct newline *nl = &nl_buff[i];
|
|
|
|
fprintf(Debug_File, "nl_tk_diff = %d\n", nl->nl_tk_diff);
|
|
}
|
|
fprintf(Debug_File, "\n");
|
|
}
|
|
|
|
#endif /* DB_NL_BUFF */
|