-
+ 79F0962254F05215DF25FF996EF028819A31E13BEAB4B0C10B9955AB48A571EA5C7714155E30EE244A6699D4CB3A8EB2588A60CC4F3F4F8342E3F2671E0A66D7
vtools/src/util.c
(0 . 0)(1 . 428)
5124
5125 #include "diff.h"
5126 #include <error.h>
5127 #include <xalloc.h>
5128 #include <stdlib.h>
5129
5130 /* Use when a system call returns non-zero status. |name| should
5131 normally be the file name. */
5132
5133 void
5134 perror_with_name(char const *name) {
5135 error(0, errno, "%s", name);
5136 }
5137
5138 /* Use when a system call returns non-zero status and that is
5139 fatal. */
5140
5141 void
5142 pfatal_with_name(char const *name) {
5143 int e = errno;
5144 fprintf(stderr, "%s", name);
5145 exit(EXIT_TROUBLE);
5146 }
5147
5148 /* Print an error message containing |msgid|, then exit. */
5149
5150 void
5151 fatal(char const *msgid) {
5152 fprintf(stderr, "%s", msgid);
5153 exit(EXIT_TROUBLE);
5154 }
5155
5156 /* Like |printf|, except if -l in effect then save the message and
5157 print later. This is used for things like "Only in ...". */
5158
5159 void
5160 message(char const *format_msgid, char const *arg1, char const *arg2) {
5161 message5(format_msgid, arg1, arg2, 0, 0);
5162 }
5163
5164 void
5165 message5(char const *format_msgid, char const *arg1, char const *arg2,
5166 char const *arg3, char const *arg4) {
5167 fprintf(stderr, format_msgid, arg1, arg2, arg3, arg4);
5168 }
5169
5170 static char const *current_name0;
5171 static char const *current_name1;
5172 static bool currently_recursive;
5173
5174 /* Call before outputting the results of comparing files |name0| and |name1|
5175 to set up |outfile|, the stdio stream for the output to go to.
5176
5177 Usually, |outfile| is just stdout. But when -l was specified we
5178 fork off a |pr| and make |outfile| a pipe to it. 'pr' then outputs
5179 to our stdout. */
5180
5181 void
5182 setup_output(char const *name0, char const *name1, bool recursive) {
5183 current_name0 = name0;
5184 current_name1 = name1;
5185 currently_recursive = recursive;
5186 outfile = 0;
5187 }
5188
5189 static char c_escape_char(char c) {
5190 switch (c) {
5191 case '\a':
5192 return 'a';
5193 case '\b':
5194 return 'b';
5195 case '\t':
5196 return 't';
5197 case '\n':
5198 return 'n';
5199 case '\v':
5200 return 'v';
5201 case '\f':
5202 return 'f';
5203 case '\r':
5204 return 'r';
5205 case '"':
5206 return '"';
5207 case '\\':
5208 return '\\';
5209 default:
5210 return c < 32;
5211 }
5212 }
5213
5214 static char *
5215 c_escape(char const *str) {
5216 char const *s;
5217 size_t plus = 0;
5218 bool must_quote = false;
5219
5220 for (s = str; *s; s++) {
5221 char c = *s;
5222
5223 if (c == ' ') {
5224 must_quote = true;
5225 continue;
5226 }
5227 switch (c_escape_char(*s)) {
5228 case 1:
5229 plus += 3;
5230 /* fall through */
5231 case 0:
5232 break;
5233 default:
5234 plus++;
5235 break;
5236 }
5237 }
5238
5239 if (must_quote || plus) {
5240 size_t s_len = s - str;
5241 char *buffer = xmalloc(s_len + plus + 3);
5242 char *b = buffer;
5243
5244 *b++ = '"';
5245 for (s = str; *s; s++) {
5246 char c = *s;
5247 char escape = c_escape_char(c);
5248
5249 switch (escape) {
5250 case 0:
5251 *b++ = c;
5252 break;
5253 case 1:
5254 *b++ = '\\';
5255 *b++ = ((c >> 6) & 03) + '0';
5256 *b++ = ((c >> 3) & 07) + '0';
5257 *b++ = ((c >> 0) & 07) + '0';
5258 break;
5259 default:
5260 *b++ = '\\';
5261 *b++ = escape;
5262 break;
5263 }
5264 }
5265 *b++ = '"';
5266 *b = 0;
5267 return buffer;
5268 }
5269
5270 return (char *) str;
5271 }
5272
5273 void
5274 begin_output(void) {
5275 char *names[2];
5276 char *name;
5277
5278 if (outfile != 0)
5279 return;
5280
5281 names[0] = c_escape(current_name0);
5282 names[1] = c_escape(current_name1);
5283
5284 /* Construct the header of this piece of diff. */
5285 if(asprintf(&name, "diff%s %s %s", switch_string, names[0], names[1]) == -1)
5286 xalloc_die();
5287
5288 outfile = stdout;
5289
5290 /* If handling multiple files (because scanning a directory),
5291 print which files the following output is about. */
5292 if (currently_recursive)
5293 printf("%s\n", name);
5294
5295 free(name);
5296
5297 print_context_header(files, (char const *const *) names);
5298
5299 if (names[0] != current_name0)
5300 free(names[0]);
5301 if (names[1] != current_name1)
5302 free(names[1]);
5303 }
5304
5305 void
5306 finish_output(void) {
5307 if (outfile != 0 && outfile != stdout) {
5308 if (ferror(outfile))
5309 fatal("write failed");
5310 if (fclose(outfile) != 0)
5311 pfatal_with_name("write failed");
5312 }
5313
5314 outfile = 0;
5315 }
5316
5317 /* Compare two lines (typically one from each input file) according to
5318 the command line options. For efficiency, this is invoked only
5319 when the lines do not match exactly but an option like -i might
5320 cause us to ignore the difference. Return nonzero if the lines
5321 differ. */
5322
5323 bool
5324 lines_differ(char const *s1, char const *s2) {
5325 register char const *t1 = s1;
5326 register char const *t2 = s2;
5327 size_t column = 0;
5328
5329 while (1) {
5330 register unsigned char c1 = *t1++;
5331 register unsigned char c2 = *t2++;
5332
5333 /* Test for exact char equality first, since it's a common
5334 case. */
5335 if (c1 != c2) {
5336 break;
5337 }
5338 if (c1 == '\n')
5339 return false;
5340
5341 column++;
5342 }
5343
5344 return true;
5345 }
5346
5347 /* Find the consecutive changes at the start of the script START.
5348 Return the last link before the first gap. */
5349
5350 struct change *
5351 find_change(struct change *start) {
5352 return start;
5353 }
5354
5355 /* Divide |script| into pieces by calling |hunkfun| and print each piece
5356 with |printfun|. Both functions take one arg, an edit script.
5357
5358 |hunkfun| is called with the tail of the script and returns the
5359 last link that belongs together with the start of the tail.
5360
5361 |printfun| takes a subscript which belongs together (with a null
5362 link at the end) and prints it. */
5363
5364 void
5365 print_script(struct change *script) {
5366 struct change *next = script;
5367
5368 while (next) {
5369 struct change *this, *end;
5370
5371 /* Find a set of changes that belong together. */
5372 this = next;
5373 end = find_hunk(next);
5374
5375 /* Disconnect them from the rest of the changes, making them a
5376 hunk, and remember the rest for next iteration. */
5377 next = end->link;
5378 end->link = 0;
5379 #ifdef DEBUG
5380 debug_script (this);
5381 #endif
5382
5383 /* Print this hunk. */
5384 pr_unidiff_hunk(this);
5385
5386 /* Reconnect the script so it will all be freed properly. */
5387 end->link = next;
5388 }
5389 }
5390
5391 /* Print the text of a single line |line|, flagging it with the
5392 characters in |line_flag| (which say whether the line is inserted,
5393 deleted, changed, etc.). |line_flag| must not end in a blank,
5394 unless it is a single blank. */
5395
5396 void
5397 print_1_line(char const *line_flag, char const *const *line) {
5398 print_1_line_nl(line_flag, line, false);
5399 }
5400
5401 /* Print the text of a single line |line|, flagging it with the
5402 characters in |line_flag| (which say whether the line is inserted,
5403 deleted, changed, etc.). |line_flag| must not end in a blank,
5404 unless it is a single blank. If |skip_nl| is set, then the final
5405 |'\n'| is not printed. */
5406
5407 void
5408 print_1_line_nl(char const *line_flag, char const *const *line, bool skip_nl) {
5409 char const *base = line[0], *limit = line[1]; /* Help the compiler. */
5410 FILE *out = outfile; /* Help the compiler some more. */
5411 char const *flag_format = 0;
5412
5413 /* If -T was specified, use a Tab between the line-flag and the
5414 text. Otherwise use a Space (as Unix diff does). Print
5415 neither space nor tab if line-flags are empty. But omit
5416 trailing blanks if requested. */
5417
5418 if (line_flag && *line_flag) {
5419 char const *flag_format_1 = flag_format = "%s ";
5420 char const *line_flag_1 = line_flag;
5421
5422 if (suppress_blank_empty && **line == '\n') {
5423 flag_format_1 = "%s";
5424
5425 /* This hack to omit trailing blanks takes advantage of
5426 the fact that the only way that |line_flag| can end in
5427 a blank is when |line_flag| consists of a single
5428 blank. */
5429 line_flag_1 += *line_flag_1 == ' ';
5430 }
5431
5432 fprintf(out, flag_format_1, line_flag_1);
5433 }
5434
5435 output_1_line(base, limit - (skip_nl && limit[-1] == '\n'));
5436
5437 if ((!line_flag || line_flag[0]) && limit[-1] != '\n') {
5438 fprintf(out, "\n\\ %s\n", "No newline at end of file");
5439 }
5440 }
5441
5442 /* Output a line from |base| up to |limit|. */
5443
5444 void
5445 output_1_line(char const *base, char const *limit) {
5446 const size_t MAX_CHUNK = 1024;
5447 size_t left = limit - base;
5448 while (left) {
5449 size_t to_write = MIN (left, MAX_CHUNK);
5450 size_t written = fwrite(base, sizeof(char), to_write, outfile);
5451 if (written < to_write)
5452 return;
5453 base += written;
5454 left -= written;
5455 }
5456 }
5457
5458 /* Translate an internal line number (an index into diff's table of
5459 lines) into an actual line number in the input file. The internal
5460 line number is |i|. |file| points to the data on the file.
5461
5462 Internal line numbers count from 0 starting after the prefix.
5463 Actual line numbers count from 1 within the entire file. */
5464
5465 lin
5466 translate_line_number(struct file_data const *file, lin i) {
5467 return i + file->prefix_lines + 1;
5468 }
5469
5470 /* Translate a line number range. This is always done for printing,
5471 so for convenience translate to printint rather than lin, so that
5472 the caller can use |printf| with |"%"pI"d"| without casting. */
5473
5474 void
5475 translate_range(struct file_data const *file,
5476 lin a, lin b,
5477 printint *aptr, printint *bptr) {
5478 *aptr = translate_line_number(file, a - 1) + 1;
5479 *bptr = translate_line_number(file, b + 1) - 1;
5480 }
5481
5482 /* Look at a hunk of edit script and report the range of lines in each
5483 file that it applies to. |hunk| is the start of the hunk, which is
5484 a chain of |struct change|. The first and last line numbers of
5485 file 0 are stored in |*first0| and |*last0|, and likewise for file
5486 1 in |*first1| and |*last1|. Note that these are internal line numbers
5487 that count from 0.
5488
5489 If no lines from file 0 are deleted, then |first0| is |last0+1|.
5490
5491 Return |UNCHANGED| if only ignorable lines are inserted or deleted,
5492 |OLD| if lines of file 0 are deleted,
5493 |NEW| if lines of file 1 are inserted,
5494 and |CHANGED| if both kinds of changes are found. */
5495
5496 enum changes
5497 analyze_hunk(struct change *hunk,
5498 lin *first0, lin *last0,
5499 lin *first1, lin *last1) {
5500 struct change *next;
5501 lin l0, l1;
5502 lin show_from, show_to;
5503 /* If 0, ignore zero-length lines;
5504 if |SIZE_MAX|, do not ignore lines just because of their length. */
5505
5506 char const *const *linbuf0 = files[0].linbuf; /* Help the compiler. */
5507 char const *const *linbuf1 = files[1].linbuf;
5508
5509 show_from = show_to = 0;
5510
5511 *first0 = hunk->line0;
5512 *first1 = hunk->line1;
5513
5514 next = hunk;
5515 do {
5516 l0 = next->line0 + next->deleted - 1;
5517 l1 = next->line1 + next->inserted - 1;
5518 show_from += next->deleted;
5519 show_to += next->inserted;
5520 } while ((next = next->link) != 0);
5521
5522 *last0 = l0;
5523 *last1 = l1;
5524
5525 return (show_from ? OLD : UNCHANGED) | (show_to ? NEW : UNCHANGED);
5526 }
5527
5528 /* Yield a new block of |size| bytes, initialized to zero. */
5529
5530 void *
5531 zalloc(size_t size) {
5532 void *p = xmalloc(size);
5533 memset (p, 0, size);
5534 return p;
5535 }
5536
5537 void
5538 debug_script(struct change *sp) {
5539 fflush(stdout);
5540
5541 for (; sp; sp = sp->link) {
5542 printint line0 = sp->line0;
5543 printint line1 = sp->line1;
5544 printint deleted = sp->deleted;
5545 printint inserted = sp->inserted;
5546 fprintf(stderr, "%3"pI"d %3"pI"d delete %"pI"d insert %"pI"d\n",
5547 line0, line1, deleted, inserted);
5548 }
5549
5550 fflush(stderr);
5551 }