Files
hustoj/core/sim/sim_3_01/sim.c
2024-10-10 12:56:56 +08:00

254 lines
6.2 KiB
C
Executable File

/* This file is part of the software similarity tester SIM.
Written by Dick Grune, Vrije Universiteit, Amsterdam.
$Id: sim.c,v 2.69 2017-03-19 09:30:38 dick Exp $
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "system.par"
#include "settings.par"
#include "sim.h"
#include "options.h"
#include "newargs.h"
#include "token.h"
#include "tokenarray.h"
#include "language.h"
#include "text.h"
#include "runs.h"
#include "hash.h"
#include "compare.h"
#include "pass1.h"
#include "pass2.h"
#include "pass3.h"
#include "percentages.h"
#include "stream.h"
#include "lang.h"
#include "Malloc.h"
#include "any_int.h"
const char *Version;
/* PARAMETERS */
/* Command-line parameters, with defaults */
int Min_Run_Size = DEFAULT_MIN_RUN_SIZE;
int Page_Width = DEFAULT_PAGE_WIDTH;
int Threshold_Percentage = 1;
FILE *Output_File;
FILE *Debug_File;
/* Language-specific parameters; may be changed in Init_Language() */
const char *Token_Name = "token";
static const char *progname; /* for error reporting */
static const char *output_name; /* for redirecting the output */
static const struct option optlist[] = {
{'r', "set minimum run size to N", Number, &Min_Run_Size},
{' ', "output runs as text (default)", None, 0},
{'d', "output in a diff-like format", None, 0},
{'n', "suppress the text of the runs", None, 0},
{'T', "suppress reporting the input files", None, 0},
{'p', "output similarity in percentages", None, 0},
{'P', "main contributing file to percentages only", None, 0},
{'t', "threshold level of percentages", Number, &Threshold_Percentage},
{'e', "compare each file to each file separately", None, 0},
{' ', "compare a file to files after it only (default)", None, 0},
{'a', "compare to all files", None, 0},
{'S', "compare to old files only", None, 0},
{'s', "do not compare a file to itself", None, 0},
{' ', "sorted output, most significant first (default)", None, 0},
{'u', "unbuffered, unsorted output", None, 0},
{' ', "miscellaneous options:", None, 0},
{'f', "function-like forms only", None, 0},
{'F', "keep function identifiers in tact", None, 0},
{'R', "recurse into subdirectories", None, 0},
{'i', "read arguments (file names) from standard input", None, 0},
{'o', "write output to file F", String, &output_name},
{'w', "set page width to N", Number, &Page_Width},
{'O', "show command line options at start-up", None, 0},
{'M', "show memory usage info at close-down", None, 0},
{'v', "show version number and compilation date", None, 0},
{'-', "lexical scan output only", None, 0},
{0, 0, 0, 0}
};
/* SERVICE ROUTINES */
int
is_new_old_separator(const char *s) {
if (strcmp(s, "/") == 0) return 1;
if (strcmp(s, "|") == 0) return 1;
return 0;
}
const char *
size_t2string(size_t s) {
return any_uint2string(s, 0);
}
void
fatal(const char *msg) {
fprintf(stderr, "%s: %s\n", progname, msg);
exit(1);
}
/* PROGRAM */
#ifdef ARG_TEST
static void
show_args(const char *msg, int argc, const char *argv[]) {
fprintf(stdout, "%s: ", msg);
int i;
for (i = 0; i < argc; i++) {
fprintf(stdout, "arg[%d] = %s; ", i, argv[i]);
}
fprintf(stdout, "\n");
}
#endif /* ARG_TEST */
int
main(int argc, const char *argv[]) {
/* The value of Version derives from the macro VERSION in the
Makefile if present. If not, a build time stamp is created.
*/
char version[40];
#ifdef VERSION
sprintf(version, "Version %s", VERSION);
#else
sprintf(version, "Build %s, %s", __DATE__, __TIME__);
#endif
Version = version;
/* Save program name */
progname = argv[0];
argv++, argc--; /* and skip it */
/* Set the default output and debug streams */
Output_File = stdout;
Debug_File = stdout;
Threshold_Percentage = 1;
/* Options, default string values given above */
/* override from language file */
Init_Language();
/* override from command line */
{ int n_op = do_options(progname, optlist, argc, argv);
argc -= n_op, argv += n_op; /* and skip them */
}
/* Check options compatibility */
allow_at_most_one_option_out_of("dnp"); /* alternative output formats */
allow_at_most_one_option_out_of("aS"); /* alternative ranges */
allow_at_most_one_option_out_of("sS"); /* self is outside old files */
if (is_set_option('t')) {
/* threshold means percentages */
if (!is_set_option('p'))
fatal("option -t requires -p");
}
if (is_set_option('P')) {
if (!is_set_option('p'))
fatal("option -P requires -p");
}
/* ZZ
if (is_set_option('u')) {
if (!is_set_option('p'))
fatal("option -u available with -p only");
}
*/
/* Treat the simple options */
if (is_set_option('v')) {
fprintf(stdout, "%s\n", Version);
return 0;
}
if (is_set_option('p')) {
set_option('s');
}
/* Check the value options */
if (Min_Run_Size <= 0)
fatal("bad run size");
if (Page_Width <= 0)
fatal("bad page width");
if (is_set_option('p')) {
if ((Threshold_Percentage > 100) || (Threshold_Percentage <= 0))
fatal("threshold must be between 1 and 100");
}
if (output_name) {
Output_File = fopen(output_name, "w");
if (Output_File == 0) {
char *msg = (char *)Malloc(strlen(output_name) + 100);
sprintf(msg, "cannot open output file `%s'",
output_name);
fatal(msg);
/*NOTREACHED*/
}
}
/* Treat the input-determining options */
if (is_set_option('i')) {
/* read input file names from standard input */
if (argc != 0)
fatal("-i option conflicts with file arguments");
get_new_std_input_args(&argc, &argv);
}
if (is_set_option('R')) {
get_new_recursive_args(&argc, &argv);
}
/* (argc, argv) now represents new_file* [ / old_file*] */
/* Optionally show command line options */
if (is_set_option('O')) {
print_options(progname, optlist);
}
/* Here the real work starts */
if (is_set_option('-')) {
/* Just the lexical scan */
while (argv[0]) {
const char *arg = argv[0];
if (!is_new_old_separator(arg)) {
Print_Stream(arg);
}
argv++;
}
}
else { /* The works */
Read_Input_Files(argc, argv);
Make_Forward_References();
Compare_Files();
Free_Forward_References();
if (is_set_option('p')) {
Show_Percentages();
} else {
Retrieve_Runs();
Show_Runs();
}
}
Free_Text();
Free_Token_Array();
if (is_set_option('M')) {
ReportMemoryStatus(stderr);
}
return 0;
}