pass3.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. /* This file is part of the software similarity tester SIM.
  2. Written by Dick Grune, Vrije Universiteit, Amsterdam.
  3. $Id: pass3.c,v 2.11 2005/02/20 17:03:03 dick Exp $
  4. */
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include <malloc.h>
  8. #include "system.par"
  9. #include "debug.par"
  10. #include "sim.h"
  11. #include "runs.h"
  12. #include "error.h"
  13. #include "options.h"
  14. #include "pass3.h"
  15. #include "percentages.h"
  16. #ifdef DB_RUN
  17. #include "tokenarray.h"
  18. static void db_run(const struct run *);
  19. #endif
  20. static FILE *open_chunk(const struct chunk *);
  21. static void fill_line(FILE *, char []);
  22. static void clear_line(char []);
  23. static void show_runs(void);
  24. static void show_run(const struct run *);
  25. static void show_2C_line(const char [], const char []);
  26. static void show_1C_line(FILE *, const char *);
  27. static int prhead(const struct chunk *);
  28. static int prs(const char *);
  29. static int pru(unsigned int);
  30. static int unslen(unsigned int);
  31. static int maxline; /* Actual maximum line length */
  32. static char *line0; /* by malloc() */
  33. static char *line1;
  34. void
  35. Pass3(void) {
  36. if (option_set('p')) {
  37. show_percentages();
  38. }
  39. else {
  40. show_runs();
  41. }
  42. }
  43. static void
  44. show_runs(void) {
  45. AisoIter iter;
  46. struct run *run;
  47. maxline = PageWidth / 2 - 2;
  48. line0 = malloc((unsigned int)((maxline + 1) * sizeof (char)));
  49. line1 = malloc((unsigned int)((maxline + 1) * sizeof (char)));
  50. if (!line0 || !line1) fatal("out of memory");
  51. OpenIter(&iter);
  52. while (GetAisoItem(&iter, &run)) {
  53. #ifdef DB_RUN
  54. db_run(run);
  55. #endif /* DB_RUN */
  56. show_run(run);
  57. fprintf(OutputFile, "\n");
  58. }
  59. CloseIter(&iter);
  60. free(line0); line0 = 0;
  61. free(line1); line1 = 0;
  62. }
  63. static void
  64. show_run(const struct run *run) {
  65. /* The animals came in two by two ... */
  66. register const struct chunk *cnk0 = &run->rn_cn0;
  67. register const struct chunk *cnk1 = &run->rn_cn1;
  68. register unsigned int nl_cnt0 =
  69. cnk0->ch_last.ps_nl_cnt - cnk0->ch_first.ps_nl_cnt;
  70. register unsigned int nl_cnt1 =
  71. cnk1->ch_last.ps_nl_cnt - cnk1->ch_first.ps_nl_cnt;
  72. FILE *f0;
  73. FILE *f1;
  74. /* display heading of chunk */
  75. if (!option_set('d')) {
  76. /* no assumptions about the lengths of the file names! */
  77. register unsigned int size = run->rn_size;
  78. register int pos = 0;
  79. pos += prhead(cnk0);
  80. while (pos < maxline + 1) {
  81. pos += prs(" ");
  82. }
  83. pos += prs("|");
  84. pos += prhead(cnk1);
  85. while (pos < 2*maxline - unslen(size)) {
  86. pos += prs(" ");
  87. }
  88. fprintf(OutputFile, "[%u]\n", size);
  89. }
  90. else {
  91. (void)prhead(cnk0);
  92. fprintf(OutputFile, "\n");
  93. (void)prhead(cnk1);
  94. fprintf(OutputFile, "\n");
  95. }
  96. /* stop if that suffices */
  97. if (option_set('n'))
  98. return; /* ... had enough so soon ... */
  99. /* open the files that hold the chunks */
  100. f0 = open_chunk(cnk0);
  101. f1 = open_chunk(cnk1);
  102. /* display the chunks in the required format */
  103. if (!option_set('d')) {
  104. /* fill 2-column lines and print them */
  105. while (nl_cnt0 != 0 || nl_cnt1 != 0) {
  106. if (nl_cnt0) {
  107. fill_line(f0, line0);
  108. nl_cnt0--;
  109. }
  110. else {
  111. clear_line(line0);
  112. }
  113. if (nl_cnt1) {
  114. fill_line(f1, line1);
  115. nl_cnt1--;
  116. }
  117. else {
  118. clear_line(line1);
  119. }
  120. show_2C_line(line0, line1);
  121. }
  122. }
  123. else {
  124. /* display the lines in a diff(1)-like format */
  125. while (nl_cnt0--) {
  126. show_1C_line(f0, "<");
  127. }
  128. fprintf(OutputFile, "---\n");
  129. while (nl_cnt1--) {
  130. show_1C_line(f1, ">");
  131. }
  132. }
  133. /* close the pertinent files */
  134. fclose(f0);
  135. fclose(f1);
  136. }
  137. static int
  138. prhead(const struct chunk *cnk) {
  139. register int pos = 0;
  140. pos += prs(cnk->ch_text->tx_fname);
  141. pos += prs(": line ");
  142. pos += pru(cnk->ch_first.ps_nl_cnt);
  143. pos += prs("-");
  144. pos += pru(cnk->ch_last.ps_nl_cnt - 1);
  145. return pos;
  146. }
  147. static int
  148. prs(const char *str) {
  149. fprintf(OutputFile, "%s", str);
  150. return strlen(str);
  151. }
  152. static int
  153. pru(unsigned int u) {
  154. fprintf(OutputFile, "%u", u);
  155. return unslen(u);
  156. }
  157. static int
  158. unslen(unsigned int u) {
  159. register int res = 1;
  160. while (u > 9) {
  161. u /= 10, res++;
  162. }
  163. return res;
  164. }
  165. static FILE *
  166. open_chunk(const struct chunk *cnk) {
  167. /* opens the file in which the chunk resides, positions the
  168. file at the beginning of the chunk and returns the file pointer
  169. */
  170. register char *fname = cnk->ch_text->tx_fname;
  171. register FILE *f = fopen(fname, "r");
  172. register unsigned int nl_cnt;
  173. if (!f) {
  174. fprintf(stderr, ">>>> File %s disappeared <<<<\n", fname);
  175. f = fopen(NULLFILE, "r");
  176. }
  177. nl_cnt = cnk->ch_first.ps_nl_cnt;
  178. while (nl_cnt > 1) {
  179. int ch = getc(f);
  180. if (ch < 0) break;
  181. if (ch == '\n') {
  182. nl_cnt--;
  183. }
  184. }
  185. return f;
  186. }
  187. static void
  188. fill_line(FILE *f, char ln[]) {
  189. /* Reads one line from f and puts it in condensed form in ln.
  190. */
  191. register int indent = 0, lpos = 0;
  192. register int ch;
  193. /* condense and skip initial blank */
  194. while ((ch = getc(f)), ch == ' ' || ch == '\t') {
  195. if (ch == '\t') {
  196. indent = 8;
  197. }
  198. else {
  199. indent++;
  200. }
  201. if (indent == 8) {
  202. /* every eight blanks give one blank */
  203. if (lpos < maxline) {
  204. ln[lpos++] = ' ';
  205. }
  206. indent = 0;
  207. }
  208. }
  209. /* store the rest */
  210. while (ch >= 0 && ch != '\n') {
  211. if (ch == '\t') {
  212. /* replace tabs by blanks */
  213. ch = ' ';
  214. }
  215. if (lpos < maxline) {
  216. ln[lpos++] = ch;
  217. }
  218. ch = getc(f);
  219. }
  220. ln[lpos] = '\0'; /* always room for this one */
  221. }
  222. static void
  223. clear_line(char ln[]) {
  224. /* a simple null byte will suffice */
  225. ln[0] = '\0';
  226. }
  227. static void
  228. show_2C_line(const char ln0[], const char ln1[]) {
  229. /* displays the contents of the two lines in a two-column
  230. format
  231. */
  232. register int i;
  233. for (i = 0; i < maxline && ln0[i] != '\0'; i++) {
  234. fputc(ln0[i], OutputFile);
  235. }
  236. for (; i < maxline; i++) {
  237. fputc(' ', OutputFile);
  238. }
  239. fprintf(OutputFile, " |");
  240. for (i = 0; i < maxline && ln1[i] != '\0'; i++) {
  241. fputc(ln1[i], OutputFile);
  242. }
  243. fprintf(OutputFile, "\n");
  244. }
  245. static void
  246. show_1C_line(FILE *f, const char *marker) {
  247. /* displays one line from f, preceded by the marker
  248. */
  249. register int ch;
  250. fprintf(OutputFile, "%s", marker);
  251. while ((ch = getc(f)), ch > 0 && ch != '\n') {
  252. fputc(ch, OutputFile);
  253. }
  254. fputc('\n', OutputFile);
  255. }
  256. #ifdef DB_RUN
  257. static void db_chunk(const struct chunk *);
  258. static void
  259. db_run(const struct run *run) {
  260. /* prints detailed data about a run */
  261. register const struct chunk *cnk0 = &run->rn_cn0;
  262. register const struct chunk *cnk1 = &run->rn_cn1;
  263. fprintf(DebugFile, "File %s / file %s:\n",
  264. cnk0->ch_text->tx_fname,
  265. cnk1->ch_text->tx_fname
  266. );
  267. fprintf(DebugFile, "from token %u/%u to %u/%u:",
  268. cnk0->ch_first.ps_tk_cnt, cnk1->ch_first.ps_tk_cnt,
  269. cnk0->ch_last.ps_tk_cnt, cnk1->ch_last.ps_tk_cnt
  270. );
  271. fprintf(DebugFile, " from lines %u/%u to %u/%u:",
  272. cnk0->ch_first.ps_nl_cnt, cnk1->ch_first.ps_nl_cnt,
  273. cnk0->ch_last.ps_nl_cnt, cnk1->ch_last.ps_nl_cnt
  274. );
  275. fprintf(DebugFile, " %u %s\n",
  276. run->rn_size,
  277. (run->rn_size == 1 ? "token" : "tokens")
  278. );
  279. db_chunk(cnk0);
  280. db_chunk(cnk1);
  281. }
  282. static void
  283. db_chunk(const struct chunk *cnk) {
  284. /* print the tokens in the chunk, with a one-char margin
  285. */
  286. unsigned int i;
  287. const struct position *first = &cnk->ch_first;
  288. const struct position *last = &cnk->ch_last;
  289. unsigned int start = cnk->ch_text->tx_start;
  290. if (first->ps_tk_cnt > 0) {
  291. fprintf(DebugFile, "...");
  292. print_token(stdout, TokenArray[start + first->ps_tk_cnt - 1]);
  293. fprintf(DebugFile, " ");
  294. }
  295. else { /* create same offset as above */
  296. fprintf(DebugFile, " ");
  297. }
  298. for (i = first->ps_tk_cnt; i <= last->ps_tk_cnt; i++) {
  299. print_token(stdout, TokenArray[start + i]);
  300. }
  301. if (start + last->ps_tk_cnt + 1 < cnk->ch_text->tx_limit) {
  302. fprintf(DebugFile, " ");
  303. print_token(stdout, TokenArray[start + last->ps_tk_cnt + 1]);
  304. fprintf(DebugFile, "...");
  305. }
  306. fprintf(DebugFile, "\n");
  307. }
  308. #endif /* DB_RUN */