1291300Shselasky/*- 2291300Shselasky * Copyright (c) 2015 Hans Petter Selasky. All rights reserved. 3291300Shselasky * 4291300Shselasky * Redistribution and use in source and binary forms, with or without 5291300Shselasky * modification, are permitted provided that the following conditions 6291300Shselasky * are met: 7291300Shselasky * 1. Redistributions of source code must retain the above copyright 8291300Shselasky * notice, this list of conditions and the following disclaimer. 9291300Shselasky * 2. Redistributions in binary form must reproduce the above copyright 10291300Shselasky * notice, this list of conditions and the following disclaimer in the 11291300Shselasky * documentation and/or other materials provided with the distribution. 12291300Shselasky * 13291300Shselasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14291300Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15291300Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16291300Shselasky * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17291300Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18291300Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19291300Shselasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20291300Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21291300Shselasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22291300Shselasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23291300Shselasky * SUCH DAMAGE. 24291300Shselasky * 25291300Shselasky * $FreeBSD$ 26291300Shselasky */ 27291300Shselasky 28291300Shselasky#include <stdio.h> 29291300Shselasky#include <stdint.h> 30291300Shselasky#include <sys/queue.h> 31291300Shselasky#include <sysexits.h> 32291300Shselasky#include <err.h> 33291300Shselasky#include <fcntl.h> 34291300Shselasky#include <stdlib.h> 35291300Shselasky#include <unistd.h> 36291300Shselasky#include <string.h> 37291300Shselasky#include <ctype.h> 38291300Shselasky#include <signal.h> 39291300Shselasky 40291300Shselaskyextern char **environ; 41291300Shselasky 42291300Shselaskystatic int opt_verbose; 43291300Shselaskystatic char *opt_diff_tool; 44291300Shselasky 45291300Shselasky#define BLOCK_SIZE 4096 46291300Shselasky#define BLOCK_MASK 0x100 47291300Shselasky#define BLOCK_ADD 0x200 48291300Shselasky 49291300Shselaskystruct block { 50291300Shselasky TAILQ_ENTRY(block) entry; 51291300Shselasky uint32_t length; 52291300Shselasky uint32_t flags; 53291300Shselasky uint8_t *data; 54291300Shselasky uint8_t *mask; 55291300Shselasky}; 56291300Shselasky 57291300Shselaskytypedef TAILQ_HEAD(, block) block_head_t; 58291300Shselasky 59291300Shselaskystatic void 60291300Shselaskysigpipe(int sig) 61291300Shselasky{ 62291300Shselasky} 63291300Shselasky 64291300Shselaskystatic struct block * 65291300Shselaskyalloc_block(void) 66291300Shselasky{ 67291300Shselasky struct block *pb; 68291300Shselasky size_t size = sizeof(*pb) + (2 * BLOCK_SIZE); 69291300Shselasky 70291300Shselasky pb = malloc(size); 71291300Shselasky if (pb == NULL) 72291300Shselasky errx(EX_SOFTWARE, "Out of memory"); 73291300Shselasky memset(pb, 0, size); 74291300Shselasky pb->data = (void *)(pb + 1); 75291300Shselasky pb->mask = pb->data + BLOCK_SIZE; 76291300Shselasky pb->length = BLOCK_SIZE; 77291300Shselasky return (pb); 78291300Shselasky} 79291300Shselasky 80291300Shselaskystatic int 81291300Shselaskywrite_block(int fd, block_head_t *ph) 82291300Shselasky{ 83291300Shselasky struct block *ptr; 84291300Shselasky 85291300Shselasky if (fd < 0) 86291300Shselasky return (-1); 87291300Shselasky 88291300Shselasky TAILQ_FOREACH(ptr, ph, entry) { 89291300Shselasky if (write(fd, ptr->data, ptr->length) != ptr->length) 90291300Shselasky return (-1); 91291300Shselasky } 92291300Shselasky return (0); 93291300Shselasky} 94291300Shselasky 95291300Shselaskystatic uint16_t 96291300Shselaskypeek_block(block_head_t *pbh, uint64_t off) 97291300Shselasky{ 98291300Shselasky struct block *ptr; 99291300Shselasky 100291300Shselasky TAILQ_FOREACH(ptr, pbh, entry) { 101291300Shselasky if (off < ptr->length) 102291300Shselasky break; 103291300Shselasky off -= ptr->length; 104291300Shselasky } 105291300Shselasky if (ptr == NULL) 106291300Shselasky return (0); 107291300Shselasky return (ptr->data[off] | (ptr->mask[off] << 8)); 108291300Shselasky} 109291300Shselasky 110291300Shselaskystatic void 111291300Shselaskyset_block(block_head_t *pbh, uint64_t off, uint16_t ch) 112291300Shselasky{ 113291300Shselasky struct block *ptr; 114291300Shselasky 115291300Shselasky TAILQ_FOREACH(ptr, pbh, entry) { 116291300Shselasky if (off < ptr->length) 117291300Shselasky break; 118291300Shselasky off -= ptr->length; 119291300Shselasky } 120291300Shselasky if (ptr == NULL) 121291300Shselasky return; 122291300Shselasky ptr->data[off] = ch & 0xFF; 123291300Shselasky ptr->mask[off] = (ch >> 8) & 0xFF; 124291300Shselasky} 125291300Shselasky 126291300Shselaskystatic uint64_t 127291300Shselaskysize_block(block_head_t *pbh) 128291300Shselasky{ 129291300Shselasky struct block *ptr; 130291300Shselasky uint64_t off = 0; 131291300Shselasky 132291300Shselasky TAILQ_FOREACH(ptr, pbh, entry) 133291300Shselasky off += ptr->length; 134291300Shselasky return (off); 135291300Shselasky} 136291300Shselasky 137291300Shselaskystatic int 138291300Shselaskydiff_tool(block_head_t *pa, block_head_t *pb) 139291300Shselasky{ 140291300Shselasky char ca[] = {"/tmp/diff.orig.XXXXXX"}; 141291300Shselasky char cb[] = {"/tmp/diff.styled.XXXXXX"}; 142291300Shselasky char cc[256]; 143291300Shselasky uint64_t sa; 144291300Shselasky uint64_t sb; 145291300Shselasky uint64_t s; 146291300Shselasky uint64_t x; 147291300Shselasky int fa; 148291300Shselasky int fb; 149291300Shselasky 150291300Shselasky sa = size_block(pa); 151291300Shselasky sb = size_block(pb); 152291300Shselasky s = (sa > sb) ? sa : sb; 153291300Shselasky 154291300Shselasky for (x = 0; x != s; x++) { 155291300Shselasky char cha = peek_block(pa, x) & 0xFF; 156291300Shselasky char chb = peek_block(pb, x) & 0xFF; 157291300Shselasky 158291300Shselasky if (cha != chb) { 159291300Shselasky /* false positive */ 160291300Shselasky if (cha == '\n' && chb == 0 && x == sa - 1) 161291300Shselasky return (0); 162291300Shselasky break; 163291300Shselasky } 164291300Shselasky } 165291300Shselasky if (x == s) 166291300Shselasky return (0); /* identical */ 167291300Shselasky 168291300Shselasky fa = mkstemp(ca); 169291300Shselasky fb = mkstemp(cb); 170291300Shselasky 171291300Shselasky if (write_block(fa, pa) < 0 || write_block(fb, pb) < 0) { 172291300Shselasky close(fa); 173291300Shselasky close(fb); 174291300Shselasky unlink(ca); 175291300Shselasky unlink(cb); 176291300Shselasky err(EX_SOFTWARE, "Could not write data to temporary files"); 177291300Shselasky } 178291300Shselasky close(fa); 179291300Shselasky close(fb); 180291300Shselasky 181291300Shselasky snprintf(cc, sizeof(cc), "%s %s %s", opt_diff_tool, ca, cb); 182291300Shselasky system(cc); 183291300Shselasky 184291300Shselasky unlink(ca); 185291300Shselasky unlink(cb); 186291300Shselasky return (-1); 187291300Shselasky} 188291300Shselasky 189291300Shselaskystatic int 190291300Shselaskydiff_block(block_head_t *pa, block_head_t *pb) 191291300Shselasky{ 192291300Shselasky uint64_t sa = size_block(pa); 193291300Shselasky uint64_t sb = size_block(pb); 194291300Shselasky uint64_t s; 195291300Shselasky uint64_t x; 196291300Shselasky uint64_t y; 197291300Shselasky uint64_t n; 198291300Shselasky 199291300Shselasky s = (sa > sb) ? sa : sb; 200291300Shselasky 201291300Shselasky for (y = x = 0; x != s; x++) { 202291300Shselasky char cha = peek_block(pa, x) & 0xFF; 203291300Shselasky char chb = peek_block(pb, x) & 0xFF; 204291300Shselasky 205291300Shselasky if (cha != chb) { 206291300Shselasky int nonspace; 207291300Shselasky 208291300Shselasky /* false positive */ 209291300Shselasky if (cha == '\n' && chb == 0 && x == sa - 1) 210291300Shselasky return (0); 211291300Shselasky 212291300Shselasky n = x - y; 213291300Shselasky printf("Style error:\n"); 214291300Shselasky nonspace = 0; 215291300Shselasky for (n = y; n < sa; n++) { 216291300Shselasky char ch = peek_block(pa, n) & 0xFF; 217291300Shselasky 218291300Shselasky if (nonspace && ch == '\n') 219291300Shselasky break; 220291300Shselasky printf("%c", ch); 221291300Shselasky if (!isspace(ch)) 222291300Shselasky nonspace = 1; 223291300Shselasky } 224291300Shselasky printf("\n"); 225291300Shselasky printf("Style corrected:\n"); 226291300Shselasky nonspace = 0; 227291300Shselasky for (n = y; n < sb; n++) { 228291300Shselasky char ch = peek_block(pb, n) & 0xFF; 229291300Shselasky 230291300Shselasky if (nonspace && ch == '\n') 231291300Shselasky break; 232291300Shselasky printf("%c", ch); 233291300Shselasky if (!isspace(ch)) 234291300Shselasky nonspace = 1; 235291300Shselasky } 236291300Shselasky printf("\n"); 237291300Shselasky for (n = y; n != x; n++) { 238291300Shselasky if ((peek_block(pa, n) & 0xFF) == '\t') 239291300Shselasky printf("\t"); 240291300Shselasky else 241291300Shselasky printf(" "); 242291300Shselasky } 243291300Shselasky printf("^ %sdifference%s\n", 244291300Shselasky (isspace(cha) || isspace(chb)) ? "whitespace " : "", 245291300Shselasky (x >= sa || x >= sb) ? " in the end of a block" : ""); 246291300Shselasky return (1); 247291300Shselasky } else if (cha == '\n') { 248291300Shselasky y = x + 1; 249291300Shselasky } 250291300Shselasky } 251291300Shselasky return (0); 252291300Shselasky} 253291300Shselasky 254291300Shselaskystatic void 255291300Shselaskyfree_block(block_head_t *pbh) 256291300Shselasky{ 257291300Shselasky struct block *ptr; 258291300Shselasky 259291300Shselasky while ((ptr = TAILQ_FIRST(pbh))) { 260291300Shselasky TAILQ_REMOVE(pbh, ptr, entry); 261291300Shselasky free(ptr); 262291300Shselasky } 263291300Shselasky} 264291300Shselasky 265291300Shselaskystatic void 266291300Shselaskycmd_popen(char *command, FILE **iop) 267291300Shselasky{ 268291300Shselasky char *argv[4]; 269291300Shselasky int pdes[4]; 270291300Shselasky int pid; 271291300Shselasky 272291300Shselasky if (pipe(pdes) < 0) 273291300Shselasky goto error; 274291300Shselasky 275291300Shselasky if (pipe(pdes + 2) < 0) { 276291300Shselasky close(pdes[0]); 277291300Shselasky close(pdes[1]); 278291300Shselasky goto error; 279291300Shselasky } 280291300Shselasky argv[0] = "sh"; 281291300Shselasky argv[1] = "-c"; 282291300Shselasky argv[2] = command; 283291300Shselasky argv[3] = NULL; 284291300Shselasky 285291300Shselasky switch ((pid = vfork())) { 286291300Shselasky case -1: /* Error. */ 287291300Shselasky close(pdes[0]); 288291300Shselasky close(pdes[1]); 289291300Shselasky close(pdes[2]); 290291300Shselasky close(pdes[3]); 291291300Shselasky goto error; 292291300Shselasky case 0: /* Child. */ 293291300Shselasky dup2(pdes[1], STDOUT_FILENO); 294291300Shselasky dup2(pdes[2], STDIN_FILENO); 295291300Shselasky close(pdes[0]); 296291300Shselasky close(pdes[3]); 297291300Shselasky execve("/bin/sh", argv, environ); 298291300Shselasky exit(127); 299291300Shselasky default: 300291300Shselasky break; 301291300Shselasky } 302291300Shselasky iop[0] = fdopen(pdes[3], "w"); 303291300Shselasky iop[1] = fdopen(pdes[0], "r"); 304291300Shselasky close(pdes[1]); 305291300Shselasky close(pdes[2]); 306291300Shselasky return; 307291300Shselaskyerror: 308291300Shselasky iop[0] = iop[1] = NULL; 309291300Shselasky} 310291300Shselasky 311291300Shselaskystatic void 312291300Shselaskycmd_block_process(block_head_t *pbh_in, block_head_t *pbh_out, char *cmd_str) 313291300Shselasky{ 314291300Shselasky FILE *pfd[2]; 315291300Shselasky struct block *ptr; 316291300Shselasky 317291300Shselasky TAILQ_INIT(pbh_out); 318291300Shselasky 319291300Shselasky cmd_popen(cmd_str, pfd); 320291300Shselasky 321291300Shselasky if (pfd[0] == NULL || pfd[1] == NULL) 322291300Shselasky errx(EX_SOFTWARE, "Cannot invoke command '%s'", cmd_str); 323291300Shselasky 324291300Shselasky if (pbh_in != NULL) { 325291300Shselasky TAILQ_FOREACH(ptr, pbh_in, entry) { 326291300Shselasky if (fwrite(ptr->data, 1, ptr->length, pfd[0]) != ptr->length) 327291300Shselasky err(EX_SOFTWARE, "Cannot write all data to command '%s'", cmd_str); 328291300Shselasky } 329291300Shselasky fflush(pfd[0]); 330291300Shselasky } 331291300Shselasky fclose(pfd[0]); 332291300Shselasky 333291300Shselasky while (1) { 334291300Shselasky int len; 335291300Shselasky 336291300Shselasky ptr = alloc_block(); 337291300Shselasky len = fread(ptr->data, 1, BLOCK_SIZE, pfd[1]); 338291300Shselasky if (len <= 0) { 339291300Shselasky free(ptr); 340291300Shselasky break; 341291300Shselasky } 342291300Shselasky ptr->length = len; 343291300Shselasky TAILQ_INSERT_TAIL(pbh_out, ptr, entry); 344291300Shselasky } 345291300Shselasky fclose(pfd[1]); 346291300Shselasky} 347291300Shselasky 348291300Shselaskystatic void 349291300Shselaskyusage(void) 350291300Shselasky{ 351291300Shselasky fprintf(stderr, 352291300Shselasky "indent_wrapper [-v] [-d] [-D] [-g <githash>]\n" 353291300Shselasky "\t" "[-s <svnrevision> ] [ -t <tool> ] [ -c <command> ]\n" 354291300Shselasky "\t" "-v Increase verbosity\n" 355291300Shselasky "\t" "-d Check output from git diff\n" 356291300Shselasky "\t" "-D Check output from svn diff\n" 357291302Shselasky "\t" "-c <cmd> Set custom command to produce diff\n" 358291300Shselasky "\t" "-g <hash> Check output from git hash\n" 359291300Shselasky "\t" "-s <rev> Check output from svn revision\n" 360291300Shselasky "\t" "-t <tool> Launch external diff tool\n" 361291300Shselasky "\n" 362291300Shselasky "Examples:\n" 363291300Shselasky "\t" "indent_wrapper -D\n" 364291302Shselasky "\t" "indent_wrapper -D -t meld\n" 365291302Shselasky "\t" "indent_wrapper -D -t \"diff -u\"\n"); 366291300Shselasky exit(EX_SOFTWARE); 367291300Shselasky} 368291300Shselasky 369291300Shselaskyint 370291300Shselaskymain(int argc, char **argv) 371291300Shselasky{ 372291300Shselasky block_head_t diff_head; 373291300Shselasky block_head_t diff_a_head; 374291300Shselasky block_head_t diff_b_head; 375291300Shselasky block_head_t indent_in_head; 376291300Shselasky block_head_t indent_out_head; 377291300Shselasky struct block *p1 = NULL; 378291300Shselasky struct block *p2 = NULL; 379291300Shselasky uint64_t size; 380291300Shselasky uint64_t x; 381291300Shselasky uint64_t y1 = 0; 382291300Shselasky uint64_t y2 = 0; 383291300Shselasky int recurse = 0; 384291300Shselasky int inside_string = 0; 385291300Shselasky int escape_char = 0; 386291300Shselasky int do_parse = 0; 387291300Shselasky char cmdbuf[256]; 388291300Shselasky uint16_t ch; 389291300Shselasky uint16_t chn; 390291300Shselasky int c; 391291300Shselasky int retval = 0; 392291300Shselasky 393291300Shselasky signal(SIGPIPE, &sigpipe); 394291300Shselasky 395291300Shselasky cmdbuf[0] = 0; 396291300Shselasky 397291300Shselasky while ((c = getopt(argc, argv, "dDvg:s:c:ht:")) != -1) { 398291300Shselasky switch (c) { 399291300Shselasky case 'v': 400291300Shselasky opt_verbose++; 401291300Shselasky break; 402291300Shselasky case 't': 403291300Shselasky opt_diff_tool = optarg; 404291300Shselasky break; 405291300Shselasky case 'g': 406291300Shselasky snprintf(cmdbuf, sizeof(cmdbuf), "git show -U1000000 %s", optarg); 407291300Shselasky break; 408291300Shselasky case 'd': 409291300Shselasky snprintf(cmdbuf, sizeof(cmdbuf), "git diff -U1000000"); 410291300Shselasky break; 411291300Shselasky case 'D': 412291300Shselasky snprintf(cmdbuf, sizeof(cmdbuf), "svn diff --diff-cmd=diff -x -U1000000"); 413291300Shselasky break; 414291300Shselasky case 's': 415291300Shselasky snprintf(cmdbuf, sizeof(cmdbuf), "svn diff --diff-cmd=diff -x -U1000000 -r %s", optarg); 416291300Shselasky break; 417291300Shselasky case 'c': 418291300Shselasky snprintf(cmdbuf, sizeof(cmdbuf), "%s", optarg); 419291300Shselasky break; 420291300Shselasky default: 421291300Shselasky usage(); 422291300Shselasky } 423291300Shselasky } 424291300Shselasky if (cmdbuf[0] == 0) 425291300Shselasky usage(); 426291300Shselasky 427291300Shselasky cmd_block_process(NULL, &diff_head, cmdbuf); 428291300Shselasky 429291300Shselasky TAILQ_INIT(&diff_a_head); 430291300Shselasky TAILQ_INIT(&diff_b_head); 431291300Shselasky 432291300Shselasky size = size_block(&diff_head); 433291300Shselasky p1 = alloc_block(); 434291300Shselasky y1 = 0; 435291300Shselasky p2 = alloc_block(); 436291300Shselasky y2 = 0; 437291300Shselasky 438291300Shselasky for (x = 0; x < size;) { 439291300Shselasky ch = peek_block(&diff_head, x); 440291300Shselasky switch (ch & 0xFF) { 441291300Shselasky case '+': 442291300Shselasky if (ch == peek_block(&diff_head, x + 1) && 443291300Shselasky ch == peek_block(&diff_head, x + 2) && 444291300Shselasky ' ' == (peek_block(&diff_head, x + 3) & 0xFF)) 445291300Shselasky goto parse_filename; 446291300Shselasky if (do_parse == 0) 447291300Shselasky break; 448291300Shselasky for (x++; x != size; x++) { 449291300Shselasky ch = peek_block(&diff_head, x); 450291300Shselasky p1->mask[y1] = BLOCK_ADD >> 8; 451291300Shselasky p1->data[y1++] = ch; 452291300Shselasky if (y1 == BLOCK_SIZE) { 453291300Shselasky TAILQ_INSERT_TAIL(&diff_a_head, p1, entry); 454291300Shselasky p1 = alloc_block(); 455291300Shselasky y1 = 0; 456291300Shselasky } 457291300Shselasky if ((ch & 0xFF) == '\n') 458291300Shselasky break; 459291300Shselasky } 460291300Shselasky break; 461291300Shselasky case '-': 462291300Shselasky if (ch == peek_block(&diff_head, x + 1) && 463291300Shselasky ch == peek_block(&diff_head, x + 2) && 464291300Shselasky ' ' == (peek_block(&diff_head, x + 3) & 0xFF)) 465291300Shselasky goto parse_filename; 466291300Shselasky if (do_parse == 0) 467291300Shselasky break; 468291300Shselasky for (x++; x != size; x++) { 469291300Shselasky ch = peek_block(&diff_head, x); 470291300Shselasky p2->data[y2++] = ch; 471291300Shselasky if (y2 == BLOCK_SIZE) { 472291300Shselasky TAILQ_INSERT_TAIL(&diff_b_head, p2, entry); 473291300Shselasky p2 = alloc_block(); 474291300Shselasky y2 = 0; 475291300Shselasky } 476291300Shselasky if ((ch & 0xFF) == '\n') 477291300Shselasky break; 478291300Shselasky } 479291300Shselasky break; 480291300Shselasky case ' ': 481291300Shselasky if (do_parse == 0) 482291300Shselasky break; 483291300Shselasky for (x++; x != size; x++) { 484291300Shselasky ch = peek_block(&diff_head, x); 485291300Shselasky p1->data[y1++] = ch; 486291300Shselasky if (y1 == BLOCK_SIZE) { 487291300Shselasky TAILQ_INSERT_TAIL(&diff_a_head, p1, entry); 488291300Shselasky p1 = alloc_block(); 489291300Shselasky y1 = 0; 490291300Shselasky } 491291300Shselasky p2->data[y2++] = ch; 492291300Shselasky if (y2 == BLOCK_SIZE) { 493291300Shselasky TAILQ_INSERT_TAIL(&diff_b_head, p2, entry); 494291300Shselasky p2 = alloc_block(); 495291300Shselasky y2 = 0; 496291300Shselasky } 497291300Shselasky if ((ch & 0xFF) == '\n') 498291300Shselasky break; 499291300Shselasky } 500291300Shselasky break; 501291300Shselasky parse_filename: 502291300Shselasky for (x += 3; x != size; x++) { 503291300Shselasky ch = peek_block(&diff_head, x); 504291300Shselasky chn = peek_block(&diff_head, x + 1); 505291300Shselasky if ((ch & 0xFF) == '.') { 506291300Shselasky /* only accept .c and .h files */ 507291300Shselasky do_parse = ((chn & 0xFF) == 'c' || (chn & 0xFF) == 'h'); 508291300Shselasky } 509291300Shselasky if ((ch & 0xFF) == '\n') 510291300Shselasky break; 511291300Shselasky } 512291300Shselasky default: 513291300Shselasky break; 514291300Shselasky } 515291300Shselasky /* skip till end of line */ 516291300Shselasky for (; x < size; x++) { 517291300Shselasky ch = peek_block(&diff_head, x); 518291300Shselasky if ((ch & 0xFF) == '\n') { 519291300Shselasky x++; 520291300Shselasky break; 521291300Shselasky } 522291300Shselasky } 523291300Shselasky } 524291300Shselasky p1->length = y1; 525291300Shselasky p2->length = y2; 526291300Shselasky TAILQ_INSERT_TAIL(&diff_a_head, p1, entry); 527291300Shselasky TAILQ_INSERT_TAIL(&diff_b_head, p2, entry); 528291300Shselasky 529291300Shselasky /* first pass - verify input */ 530291300Shselasky size = size_block(&diff_a_head); 531291300Shselasky for (x = 0; x != size; x++) { 532291300Shselasky ch = peek_block(&diff_a_head, x) & 0xFF; 533291300Shselasky if (!(ch & 0x80) && ch != '\t' && ch != '\r' && ch != '\n' && 534291300Shselasky ch != ' ' && !isprint(ch)) 535291300Shselasky errx(EX_SOFTWARE, "Non printable characters are not allowed: '%c'", ch); 536291300Shselasky else if (ch & 0x80) { 537291300Shselasky set_block(&diff_a_head, x, ch | BLOCK_MASK); 538291300Shselasky } 539291300Shselasky } 540291300Shselasky 541291300Shselasky /* second pass - identify all comments */ 542291300Shselasky for (x = 0; x < size; x++) { 543291300Shselasky ch = peek_block(&diff_a_head, x); 544291300Shselasky chn = peek_block(&diff_a_head, x + 1); 545291300Shselasky if ((ch & 0xFF) == '/' && (chn & 0xFF) == '/') { 546291300Shselasky set_block(&diff_a_head, x, ch | BLOCK_MASK); 547291300Shselasky set_block(&diff_a_head, x + 1, chn | BLOCK_MASK); 548291300Shselasky for (x += 2; x < size; x++) { 549291300Shselasky ch = peek_block(&diff_a_head, x); 550291300Shselasky if ((ch & 0xFF) == '\n') 551291300Shselasky break; 552291300Shselasky set_block(&diff_a_head, x, ch | BLOCK_MASK); 553291300Shselasky } 554291300Shselasky } else if ((ch & 0xFF) == '/' && (chn & 0xFF) == '*') { 555291300Shselasky set_block(&diff_a_head, x, ch | BLOCK_MASK); 556291300Shselasky set_block(&diff_a_head, x + 1, chn | BLOCK_MASK); 557291300Shselasky for (x += 2; x < size; x++) { 558291300Shselasky ch = peek_block(&diff_a_head, x); 559291300Shselasky chn = peek_block(&diff_a_head, x + 1); 560291300Shselasky if ((ch & 0xFF) == '*' && (chn & 0xFF) == '/') { 561291300Shselasky set_block(&diff_a_head, x, ch | BLOCK_MASK); 562291300Shselasky set_block(&diff_a_head, x + 1, chn | BLOCK_MASK); 563291300Shselasky x++; 564291300Shselasky break; 565291300Shselasky } 566291300Shselasky set_block(&diff_a_head, x, ch | BLOCK_MASK); 567291300Shselasky } 568291300Shselasky } 569291300Shselasky } 570291300Shselasky 571291300Shselasky /* third pass - identify preprocessor tokens and strings */ 572291300Shselasky for (x = 0; x < size; x++) { 573291300Shselasky ch = peek_block(&diff_a_head, x); 574291300Shselasky if (ch & BLOCK_MASK) 575291300Shselasky continue; 576291300Shselasky if (inside_string == 0 && (ch & 0xFF) == '#') { 577291300Shselasky int skip_newline = 0; 578291300Shselasky 579291300Shselasky set_block(&diff_a_head, x, ch | BLOCK_MASK); 580291300Shselasky for (x++; x < size; x++) { 581291300Shselasky ch = peek_block(&diff_a_head, x); 582291300Shselasky if ((ch & 0xFF) == '\n') { 583291300Shselasky if (!skip_newline) 584291300Shselasky break; 585291300Shselasky skip_newline = 0; 586291300Shselasky } 587291300Shselasky if (ch & BLOCK_MASK) 588291300Shselasky continue; 589291300Shselasky if ((ch & 0xFF) == '\\') 590291300Shselasky skip_newline = 1; 591291300Shselasky set_block(&diff_a_head, x, ch | BLOCK_MASK); 592291300Shselasky } 593291300Shselasky } 594291300Shselasky if ((ch & 0xFF) == '"' || (ch & 0xFF) == '\'') { 595291300Shselasky if (inside_string == 0) { 596291300Shselasky inside_string = (ch & 0xFF); 597291300Shselasky } else { 598291300Shselasky if (escape_char == 0 && inside_string == (ch & 0xFF)) 599291300Shselasky inside_string = 0; 600291300Shselasky } 601291300Shselasky escape_char = 0; 602291300Shselasky set_block(&diff_a_head, x, ch | BLOCK_MASK); 603291300Shselasky } else if (inside_string != 0) { 604291300Shselasky if ((ch & 0xFF) == '\\') 605291300Shselasky escape_char = !escape_char; 606291300Shselasky else 607291300Shselasky escape_char = 0; 608291300Shselasky set_block(&diff_a_head, x, ch | BLOCK_MASK); 609291300Shselasky } 610291300Shselasky } 611291300Shselasky 612291300Shselasky /* fourth pass - identify function blocks */ 613291300Shselasky if (opt_verbose > 0) { 614291300Shselasky chn = peek_block(&diff_a_head, x); 615291300Shselasky printf("L%02d%c|", recurse, 616291300Shselasky (chn & BLOCK_ADD) ? '+' : ' '); 617291300Shselasky } 618291300Shselasky for (x = 0; x < size; x++) { 619291300Shselasky ch = peek_block(&diff_a_head, x); 620291300Shselasky if (opt_verbose > 0) { 621291300Shselasky printf("%c", ch & 0xFF); 622291300Shselasky if ((ch & 0xFF) == '\n') { 623291300Shselasky chn = peek_block(&diff_a_head, x + 1); 624291300Shselasky printf("L%02d%c|", recurse, 625291300Shselasky (chn & BLOCK_ADD) ? '+' : ' '); 626291300Shselasky } 627291300Shselasky } 628291300Shselasky if (ch & BLOCK_MASK) 629291300Shselasky continue; 630291300Shselasky switch (ch & 0xFF) { 631291300Shselasky case '{': 632291300Shselasky case '(': 633291300Shselasky recurse++; 634291300Shselasky break; 635291300Shselasky default: 636291300Shselasky break; 637291300Shselasky } 638291300Shselasky if (recurse != 0) 639291300Shselasky set_block(&diff_a_head, x, ch | BLOCK_MASK); 640291300Shselasky switch (ch & 0xFF) { 641291300Shselasky case '}': 642291300Shselasky case ')': 643291300Shselasky recurse--; 644291300Shselasky break; 645291300Shselasky default: 646291300Shselasky break; 647291300Shselasky } 648291300Shselasky } 649291300Shselasky if (opt_verbose > 0) 650291300Shselasky printf("\n"); 651291300Shselasky if (recurse != 0) 652291300Shselasky errx(EX_SOFTWARE, "Unbalanced parenthesis"); 653291300Shselasky if (inside_string != 0) 654291300Shselasky errx(EX_SOFTWARE, "String without end"); 655291300Shselasky 656291300Shselasky /* fifth pass - on the same line statements */ 657291300Shselasky for (x = 0; x < size; x++) { 658291300Shselasky ch = peek_block(&diff_a_head, x); 659291300Shselasky if (ch & BLOCK_MASK) 660291300Shselasky continue; 661291300Shselasky switch (ch & 0xFF) { 662291300Shselasky case '\n': 663291300Shselasky break; 664291300Shselasky default: 665291300Shselasky set_block(&diff_a_head, x, ch | BLOCK_MASK); 666291300Shselasky break; 667291300Shselasky } 668291300Shselasky } 669291300Shselasky 670291300Shselasky /* sixth pass - output relevant blocks to indent */ 671291300Shselasky for (y1 = x = 0; x < size; x++) { 672291300Shselasky ch = peek_block(&diff_a_head, x); 673291300Shselasky if (ch & BLOCK_ADD) { 674291300Shselasky TAILQ_INIT(&indent_in_head); 675291300Shselasky 676291300Shselasky p2 = alloc_block(); 677291300Shselasky y2 = 0; 678291300Shselasky for (; y1 < size; y1++) { 679291300Shselasky ch = peek_block(&diff_a_head, y1); 680291300Shselasky if (y1 > x && !(ch & (BLOCK_MASK | BLOCK_ADD))) 681291300Shselasky break; 682291300Shselasky p2->data[y2++] = ch & 0xFF; 683291300Shselasky if (y2 == BLOCK_SIZE) { 684291300Shselasky TAILQ_INSERT_TAIL(&indent_in_head, p2, entry); 685291300Shselasky p2 = alloc_block(); 686291300Shselasky y2 = 0; 687291300Shselasky } 688291300Shselasky } 689291300Shselasky if (p2->data[y2] != '\n') 690291300Shselasky p2->data[y2++] = '\n'; 691291300Shselasky p2->length = y2; 692291300Shselasky TAILQ_INSERT_TAIL(&indent_in_head, p2, entry); 693291300Shselasky 694291300Shselasky cmd_block_process(&indent_in_head, &indent_out_head, 695291300Shselasky "indent " 696291300Shselasky "-Tbool " 697291300Shselasky "-Tclass " 698291300Shselasky "-TFILE " 699291300Shselasky "-TLIST_ENTRY " 700291300Shselasky "-TLIST_HEAD " 701291300Shselasky "-TSLIST_ENTRY " 702291300Shselasky "-TSLIST_HEAD " 703291300Shselasky "-TSTAILQ_ENTRY " 704291300Shselasky "-TSTAILQ_HEAD " 705291300Shselasky "-TTAILQ_ENTRY " 706291300Shselasky "-TTAILQ_HEAD " 707291300Shselasky "-T__aligned " 708291300Shselasky "-T__packed " 709291300Shselasky "-T__unused " 710291300Shselasky "-T__used " 711291300Shselasky "-Tfd_set " 712291300Shselasky "-Toss_mixerinfo " 713291300Shselasky "-Tu_char " 714291300Shselasky "-Tu_int " 715291300Shselasky "-Tu_long " 716291300Shselasky "-Tu_short " 717291300Shselasky "-ta -st -bad -bap -nbbb -nbc -br -nbs " 718291300Shselasky "-c41 -cd41 -cdb -ce -ci4 -cli0 -d0 -di8 -ndj -ei -nfc1 " 719291300Shselasky "-nfcb -i8 -ip8 -l79 -lc77 -ldi0 -nlp -npcs -psl -sc " 720291300Shselasky "-nsob -nv " 721291300Shselasky " | " 722291300Shselasky "sed " 723291300Shselasky "-e 's/_HEAD [(]/_HEAD(/g' " 724291300Shselasky "-e 's/_ENTRY [(]/_ENTRY(/g' " 725291300Shselasky "-e 's/\t__aligned/ __aligned/g' " 726291300Shselasky "-e 's/\t__packed/ __packed/g' " 727291300Shselasky "-e 's/\t__unused/ __unused/g' " 728291300Shselasky "-e 's/\t__used/ __used/g' " 729291300Shselasky "-e 's/^#define /#define\t/g'"); 730291300Shselasky 731291300Shselasky if (opt_diff_tool != NULL) { 732291300Shselasky if (diff_tool(&indent_in_head, &indent_out_head)) 733291300Shselasky retval = 1; 734291300Shselasky } else { 735291300Shselasky if (diff_block(&indent_in_head, &indent_out_head)) 736291300Shselasky retval = 1; 737291300Shselasky } 738291300Shselasky free_block(&indent_in_head); 739291300Shselasky free_block(&indent_out_head); 740291300Shselasky x = y1; 741291300Shselasky } else if (!(ch & BLOCK_MASK)) { 742291300Shselasky y1 = x + 1; 743291300Shselasky } 744291300Shselasky } 745291300Shselasky return (retval); 746291300Shselasky} 747