mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-12 14:29:34 +02:00
357 lines
7.5 KiB
C
357 lines
7.5 KiB
C
/* This file is part of the software similarity tester SIM.
|
|
Written by Dick Grune, Vrije Universiteit, Amsterdam.
|
|
$Id: pass3.c,v 2.11 2005/02/20 17:03:03 dick Exp $
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <malloc.h>
|
|
|
|
#include "system.par"
|
|
#include "debug.par"
|
|
#include "sim.h"
|
|
#include "runs.h"
|
|
#include "error.h"
|
|
#include "options.h"
|
|
#include "pass3.h"
|
|
#include "percentages.h"
|
|
|
|
#ifdef DB_RUN
|
|
#include "tokenarray.h"
|
|
static void db_run(const struct run *);
|
|
#endif
|
|
|
|
static FILE *open_chunk(const struct chunk *);
|
|
static void fill_line(FILE *, char []);
|
|
static void clear_line(char []);
|
|
static void show_runs(void);
|
|
static void show_run(const struct run *);
|
|
static void show_2C_line(const char [], const char []);
|
|
static void show_1C_line(FILE *, const char *);
|
|
static int prhead(const struct chunk *);
|
|
static int prs(const char *);
|
|
static int pru(unsigned int);
|
|
static int unslen(unsigned int);
|
|
|
|
static int maxline; /* Actual maximum line length */
|
|
static char *line0; /* by malloc() */
|
|
static char *line1;
|
|
|
|
void
|
|
Pass3(void) {
|
|
if (option_set('p')) {
|
|
show_percentages();
|
|
}
|
|
else {
|
|
show_runs();
|
|
}
|
|
}
|
|
|
|
static void
|
|
show_runs(void) {
|
|
AisoIter iter;
|
|
struct run *run;
|
|
|
|
maxline = PageWidth / 2 - 2;
|
|
line0 = malloc((unsigned int)((maxline + 1) * sizeof (char)));
|
|
line1 = malloc((unsigned int)((maxline + 1) * sizeof (char)));
|
|
if (!line0 || !line1) fatal("out of memory");
|
|
|
|
OpenIter(&iter);
|
|
while (GetAisoItem(&iter, &run)) {
|
|
#ifdef DB_RUN
|
|
db_run(run);
|
|
#endif /* DB_RUN */
|
|
show_run(run);
|
|
fprintf(OutputFile, "\n");
|
|
}
|
|
CloseIter(&iter);
|
|
|
|
free(line0); line0 = 0;
|
|
free(line1); line1 = 0;
|
|
}
|
|
|
|
static void
|
|
show_run(const struct run *run) {
|
|
/* The animals came in two by two ... */
|
|
register const struct chunk *cnk0 = &run->rn_cn0;
|
|
register const struct chunk *cnk1 = &run->rn_cn1;
|
|
register unsigned int nl_cnt0 =
|
|
cnk0->ch_last.ps_nl_cnt - cnk0->ch_first.ps_nl_cnt;
|
|
register unsigned int nl_cnt1 =
|
|
cnk1->ch_last.ps_nl_cnt - cnk1->ch_first.ps_nl_cnt;
|
|
FILE *f0;
|
|
FILE *f1;
|
|
|
|
/* display heading of chunk */
|
|
if (!option_set('d')) {
|
|
/* no assumptions about the lengths of the file names! */
|
|
register unsigned int size = run->rn_size;
|
|
register int pos = 0;
|
|
|
|
pos += prhead(cnk0);
|
|
while (pos < maxline + 1) {
|
|
pos += prs(" ");
|
|
}
|
|
pos += prs("|");
|
|
pos += prhead(cnk1);
|
|
while (pos < 2*maxline - unslen(size)) {
|
|
pos += prs(" ");
|
|
}
|
|
fprintf(OutputFile, "[%u]\n", size);
|
|
}
|
|
else {
|
|
(void)prhead(cnk0);
|
|
fprintf(OutputFile, "\n");
|
|
(void)prhead(cnk1);
|
|
fprintf(OutputFile, "\n");
|
|
}
|
|
|
|
/* stop if that suffices */
|
|
if (option_set('n'))
|
|
return; /* ... had enough so soon ... */
|
|
|
|
/* open the files that hold the chunks */
|
|
f0 = open_chunk(cnk0);
|
|
f1 = open_chunk(cnk1);
|
|
|
|
/* display the chunks in the required format */
|
|
if (!option_set('d')) {
|
|
/* fill 2-column lines and print them */
|
|
while (nl_cnt0 != 0 || nl_cnt1 != 0) {
|
|
if (nl_cnt0) {
|
|
fill_line(f0, line0);
|
|
nl_cnt0--;
|
|
}
|
|
else {
|
|
clear_line(line0);
|
|
}
|
|
if (nl_cnt1) {
|
|
fill_line(f1, line1);
|
|
nl_cnt1--;
|
|
}
|
|
else {
|
|
clear_line(line1);
|
|
}
|
|
show_2C_line(line0, line1);
|
|
}
|
|
}
|
|
else {
|
|
/* display the lines in a diff(1)-like format */
|
|
while (nl_cnt0--) {
|
|
show_1C_line(f0, "<");
|
|
}
|
|
fprintf(OutputFile, "---\n");
|
|
while (nl_cnt1--) {
|
|
show_1C_line(f1, ">");
|
|
}
|
|
}
|
|
|
|
/* close the pertinent files */
|
|
fclose(f0);
|
|
fclose(f1);
|
|
}
|
|
|
|
static int
|
|
prhead(const struct chunk *cnk) {
|
|
register int pos = 0;
|
|
|
|
pos += prs(cnk->ch_text->tx_fname);
|
|
pos += prs(": line ");
|
|
pos += pru(cnk->ch_first.ps_nl_cnt);
|
|
pos += prs("-");
|
|
pos += pru(cnk->ch_last.ps_nl_cnt - 1);
|
|
return pos;
|
|
}
|
|
|
|
static int
|
|
prs(const char *str) {
|
|
fprintf(OutputFile, "%s", str);
|
|
return strlen(str);
|
|
}
|
|
|
|
static int
|
|
pru(unsigned int u) {
|
|
fprintf(OutputFile, "%u", u);
|
|
return unslen(u);
|
|
}
|
|
|
|
static int
|
|
unslen(unsigned int u) {
|
|
register int res = 1;
|
|
|
|
while (u > 9) {
|
|
u /= 10, res++;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
static FILE *
|
|
open_chunk(const struct chunk *cnk) {
|
|
/* opens the file in which the chunk resides, positions the
|
|
file at the beginning of the chunk and returns the file pointer
|
|
*/
|
|
register char *fname = cnk->ch_text->tx_fname;
|
|
register FILE *f = fopen(fname, "r");
|
|
register unsigned int nl_cnt;
|
|
|
|
if (!f) {
|
|
fprintf(stderr, ">>>> File %s disappeared <<<<\n", fname);
|
|
f = fopen(NULLFILE, "r");
|
|
}
|
|
|
|
nl_cnt = cnk->ch_first.ps_nl_cnt;
|
|
while (nl_cnt > 1) {
|
|
int ch = getc(f);
|
|
|
|
if (ch < 0) break;
|
|
if (ch == '\n') {
|
|
nl_cnt--;
|
|
}
|
|
}
|
|
|
|
return f;
|
|
}
|
|
|
|
static void
|
|
fill_line(FILE *f, char ln[]) {
|
|
/* Reads one line from f and puts it in condensed form in ln.
|
|
*/
|
|
register int indent = 0, lpos = 0;
|
|
register int ch;
|
|
|
|
/* condense and skip initial blank */
|
|
while ((ch = getc(f)), ch == ' ' || ch == '\t') {
|
|
if (ch == '\t') {
|
|
indent = 8;
|
|
}
|
|
else {
|
|
indent++;
|
|
}
|
|
if (indent == 8) {
|
|
/* every eight blanks give one blank */
|
|
if (lpos < maxline) {
|
|
ln[lpos++] = ' ';
|
|
}
|
|
indent = 0;
|
|
}
|
|
}
|
|
|
|
/* store the rest */
|
|
while (ch >= 0 && ch != '\n') {
|
|
if (ch == '\t') {
|
|
/* replace tabs by blanks */
|
|
ch = ' ';
|
|
}
|
|
if (lpos < maxline) {
|
|
ln[lpos++] = ch;
|
|
}
|
|
ch = getc(f);
|
|
}
|
|
ln[lpos] = '\0'; /* always room for this one */
|
|
}
|
|
|
|
static void
|
|
clear_line(char ln[]) {
|
|
/* a simple null byte will suffice */
|
|
ln[0] = '\0';
|
|
}
|
|
|
|
static void
|
|
show_2C_line(const char ln0[], const char ln1[]) {
|
|
/* displays the contents of the two lines in a two-column
|
|
format
|
|
*/
|
|
register int i;
|
|
|
|
for (i = 0; i < maxline && ln0[i] != '\0'; i++) {
|
|
fputc(ln0[i], OutputFile);
|
|
}
|
|
for (; i < maxline; i++) {
|
|
fputc(' ', OutputFile);
|
|
}
|
|
fprintf(OutputFile, " |");
|
|
|
|
for (i = 0; i < maxline && ln1[i] != '\0'; i++) {
|
|
fputc(ln1[i], OutputFile);
|
|
}
|
|
fprintf(OutputFile, "\n");
|
|
}
|
|
|
|
static void
|
|
show_1C_line(FILE *f, const char *marker) {
|
|
/* displays one line from f, preceded by the marker
|
|
*/
|
|
register int ch;
|
|
|
|
fprintf(OutputFile, "%s", marker);
|
|
while ((ch = getc(f)), ch > 0 && ch != '\n') {
|
|
fputc(ch, OutputFile);
|
|
}
|
|
fputc('\n', OutputFile);
|
|
}
|
|
|
|
#ifdef DB_RUN
|
|
|
|
static void db_chunk(const struct chunk *);
|
|
|
|
static void
|
|
db_run(const struct run *run) {
|
|
/* prints detailed data about a run */
|
|
register const struct chunk *cnk0 = &run->rn_cn0;
|
|
register const struct chunk *cnk1 = &run->rn_cn1;
|
|
|
|
fprintf(DebugFile, "File %s / file %s:\n",
|
|
cnk0->ch_text->tx_fname,
|
|
cnk1->ch_text->tx_fname
|
|
);
|
|
fprintf(DebugFile, "from token %u/%u to %u/%u:",
|
|
cnk0->ch_first.ps_tk_cnt, cnk1->ch_first.ps_tk_cnt,
|
|
cnk0->ch_last.ps_tk_cnt, cnk1->ch_last.ps_tk_cnt
|
|
);
|
|
fprintf(DebugFile, " from lines %u/%u to %u/%u:",
|
|
cnk0->ch_first.ps_nl_cnt, cnk1->ch_first.ps_nl_cnt,
|
|
cnk0->ch_last.ps_nl_cnt, cnk1->ch_last.ps_nl_cnt
|
|
);
|
|
fprintf(DebugFile, " %u %s\n",
|
|
run->rn_size,
|
|
(run->rn_size == 1 ? "token" : "tokens")
|
|
);
|
|
|
|
db_chunk(cnk0);
|
|
db_chunk(cnk1);
|
|
}
|
|
|
|
static void
|
|
db_chunk(const struct chunk *cnk) {
|
|
/* print the tokens in the chunk, with a one-char margin
|
|
*/
|
|
unsigned int i;
|
|
const struct position *first = &cnk->ch_first;
|
|
const struct position *last = &cnk->ch_last;
|
|
unsigned int start = cnk->ch_text->tx_start;
|
|
|
|
if (first->ps_tk_cnt > 0) {
|
|
fprintf(DebugFile, "...");
|
|
print_token(stdout, TokenArray[start + first->ps_tk_cnt - 1]);
|
|
fprintf(DebugFile, " ");
|
|
}
|
|
else { /* create same offset as above */
|
|
fprintf(DebugFile, " ");
|
|
}
|
|
|
|
for (i = first->ps_tk_cnt; i <= last->ps_tk_cnt; i++) {
|
|
print_token(stdout, TokenArray[start + i]);
|
|
}
|
|
|
|
if (start + last->ps_tk_cnt + 1 < cnk->ch_text->tx_limit) {
|
|
fprintf(DebugFile, " ");
|
|
print_token(stdout, TokenArray[start + last->ps_tk_cnt + 1]);
|
|
fprintf(DebugFile, "...");
|
|
}
|
|
|
|
fprintf(DebugFile, "\n");
|
|
}
|
|
|
|
#endif /* DB_RUN */
|