home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume14 / unidiff / part01 / unify.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-08-30  |  10.6 KB  |  533 lines

  1. /*
  2. ** unify.c - change a diff to/from a context diff from/to a unidiff.
  3. **
  4. ** Author:  Wayne Davison <davison@dri.com> (uunet!drivax!davison)
  5. **
  6. ** Feel free to use this code in any way you desire.
  7. */
  8.  
  9. #include <stdio.h>
  10.  
  11. extern char *malloc();
  12.  
  13. #define FIND_NEXT    0
  14. #define PARSE_UNIDIFF    1
  15. #define UNI_LINES    2
  16. #define PARSE_CDIFF    3
  17. #define PARSE_OLD    4
  18. #define CHECK_OLD    5
  19. #define OLD_LINES    6
  20. #define PARSE_NEW    7
  21. #define NEW_LINES    8
  22.  
  23. #define strnEQ(s1,s2,n) (!strncmp(s1,s2,n))
  24. #define strnNE(s1,s2,n) strncmp(s1,s2,n)
  25.  
  26. char buf[2048];
  27.  
  28. struct liner {
  29.     struct liner *link;
  30.     char type;
  31.     int num;
  32.     char str[1];
  33. } root, *head = &root, *hold = &root, *line;
  34.  
  35. long o_first = 0, o_last = -1;
  36. long n_first = 0, n_last = 0;
  37.  
  38. long o_start, o_end, o_line;
  39. long n_start, n_end, n_line;
  40.  
  41. long line_num = 0;
  42. int input_type = 0;
  43. int output_type = 0;
  44. int echo_comments = 0;
  45. int strip_comments = 0;
  46. int patch_format = 0;
  47.  
  48. int state = FIND_NEXT;
  49. int found_index = 0;
  50. char name[256] = { '\0' };
  51.  
  52. void ensure_name(), add_line(), generate_output();
  53.  
  54. int
  55. main(argc, argv)
  56. int argc;
  57. char *argv[];
  58. {
  59.     char type;
  60.     char ndiff;        /* Equals '*' when we have a new-style context diff */
  61.     FILE *fp_in = stdin;
  62.  
  63.     while (--argc) {
  64.     if (**++argv == '-') {
  65.         while (*++*argv) {
  66.         switch (**argv) {
  67.         case 'c':        /* force context diff output */
  68.             output_type = 2;
  69.             break;
  70.         case 'e':        /* echo comments to stderr */
  71.             echo_comments = 1;
  72.             break;
  73.         case 'p':        /* generate patch format */
  74.         case 'P':
  75.             patch_format = 1;
  76.             break;
  77.         case 's':        /* strip comment lines */
  78.             strip_comments = 1;
  79.             break;
  80.         case 'U':        /* force patch-unidiff output */
  81.             patch_format = 1;
  82.         case 'u':        /* force unidiff output */
  83.             output_type = 1;
  84.             break;
  85.         default:
  86.             fprintf(stderr, "Unknown option: '%c'\n", **argv);
  87.             exit(1);
  88.         }
  89.         }
  90.     } else {
  91.         if (fp_in != stdin) {
  92.         fprintf(stderr, "Only one filename allowed.\n", *argv);
  93.         exit(1);
  94.         }
  95.         if ((fp_in = fopen(*argv, "r")) == NULL) {
  96.         fprintf(stderr, "Unable to open '%s'.\n", *argv);
  97.         exit(1);
  98.         }
  99.     }
  100.     }
  101.  
  102.     while (fgets(buf, sizeof buf, fp_in)) {
  103.     line_num++;
  104.       reprocess:
  105.     switch (state) {
  106.     case FIND_NEXT:
  107.         if (input_type < 2 && strnEQ(buf, "@@ -", 4)) {
  108.         input_type = 1;
  109.         if (!output_type) {
  110.             output_type = 2;
  111.         }
  112.         ensure_name();
  113.         state = PARSE_UNIDIFF;
  114.         goto reprocess;
  115.         }
  116.         if (!(input_type & 1) && strnEQ(buf, "********", 8)) {
  117.         input_type = 2;
  118.         if (!output_type) {
  119.             output_type = 1;
  120.         }
  121.         ensure_name();
  122.         state = PARSE_OLD;
  123.         break;
  124.         }
  125.         if (strnEQ(buf, "Index: ", 7)) {
  126.         found_index = 1;
  127.         printf("%s", buf);
  128.         } else if (strnEQ(buf, "Prereq: ", 8)) {
  129.         printf("%s", buf);
  130.         } else if (strnEQ(buf, "*** ", 4) || strnEQ(buf, "--- ", 4)) {
  131.         if (!found_index) {
  132.             char *cp;
  133.             int len;
  134.  
  135.             for (cp=buf+4,len=0; *cp>' ' && len<255; cp++,len++) {
  136.             ;
  137.             }
  138.             if (!*name || len < strlen(name)) {
  139.             strncpy(name, buf+4, len);
  140.             name[len] = '\0';
  141.             }
  142.         }
  143.         if (!patch_format) {
  144.             printf("%s", buf);
  145.         }
  146.         } else if( patch_format
  147.          && (strnEQ(buf, "Only in ", 8) || strnEQ(buf, "Common subdir", 13)
  148.           || strnEQ(buf, "diff -", 6))) {
  149.         if (echo_comments) {
  150.             fprintf(stderr, "%s%s", strip_comments ? "" : "!!! ", buf);
  151.         }
  152.         } else {
  153.         if (echo_comments) {
  154.             fprintf(stderr, "%s", buf);
  155.         }
  156.         if (!strip_comments) {
  157.             printf("%s", buf);
  158.         }
  159.         }
  160.         break;
  161.     case PARSE_UNIDIFF:
  162.         if (strnNE(buf, "@@ -", 4)) {
  163.         found_index = 0;
  164.         *name = '\0';
  165.         state = FIND_NEXT;
  166.         goto reprocess;
  167.         }
  168.         if (sscanf(buf+4, "%ld,%ld +%ld,%ld %c",
  169.           &o_start, &o_end, &n_start, &n_end, &type) != 5 || type != '@') {
  170.         fprintf(stderr, "Invalid unidiff header at line %ld.\n",
  171.             line_num);
  172.         exit(1);
  173.         }
  174.         o_end = (o_start ? o_start + o_end - 1 : 0);
  175.         n_end = (n_start ? n_start + n_end - 1 : 0);
  176.         o_first = o_start;
  177.         n_first = n_start;
  178.         if (o_start) {
  179.         o_line = o_start-1;
  180.         } else {
  181.         o_line = o_last = 0;
  182.         }
  183.         if (n_start) {
  184.         n_line = n_start-1;
  185.         } else {
  186.         n_line = n_last = 0;
  187.         }
  188.         state = UNI_LINES;
  189.         break;
  190.     case UNI_LINES:
  191.         switch (*buf) {
  192.         case ' ':
  193.         case '=':
  194.         *buf = ' ';
  195.         o_last = ++o_line;
  196.         n_last = ++n_line;
  197.         break;
  198.         case '-':
  199.         o_last = ++o_line;
  200.         break;
  201.         case '+':
  202.         n_last = ++n_line;
  203.         break;
  204.         default:
  205.         fprintf(stderr, "Malformed unidiff at line %ld.\n",
  206.             line_num);
  207.         exit(1);
  208.         }
  209.         add_line(*buf, 0, buf+1);
  210.         if (o_line == o_end && n_line == n_end) {
  211.         generate_output();
  212.         state = PARSE_UNIDIFF;
  213.         }
  214.         break;
  215.     case PARSE_CDIFF:
  216.         if (strnNE(buf, "********", 8)) {
  217.         generate_output();
  218.         found_index = 0;
  219.         *name = '\0';
  220.         state = FIND_NEXT;
  221.         goto reprocess;
  222.         }
  223.         state = PARSE_OLD;
  224.         break;
  225.     case PARSE_OLD:
  226.         ndiff = ' ';
  227.         o_start = -1;
  228.         if (sscanf(buf, "*** %ld,%ld %c", &o_start, &o_end, &ndiff) < 2) {
  229.         if (o_start < 0) {
  230.             fprintf(stderr,
  231.             "Context diff missing 'old' header at line %ld.\n",
  232.             line_num);
  233.             exit(1);
  234.         }
  235.         o_end = o_start;
  236.         ndiff = ' ';
  237.         }
  238.         if (o_last >= 0) {
  239.         if (o_start > o_last) {
  240.             generate_output();
  241.         } else {
  242.             ndiff = ' ';
  243.             while (head->link && head->link->num != o_start) {
  244.             head = head->link;
  245.             }
  246.         }
  247.         }
  248.         o_line = o_start-1;
  249.         n_line = 0;
  250.         if (!o_first) {
  251.         o_first = o_start;
  252.         }
  253.         if (!o_start) {
  254.         state = PARSE_NEW;
  255.         } else {
  256.         state = CHECK_OLD;
  257.         }
  258.         break;
  259.     case CHECK_OLD:
  260.         if (strnEQ(buf, "--- ", 4)) {
  261.         state = PARSE_NEW;
  262.         } else {
  263.         state = OLD_LINES;
  264.         hold = head;
  265.         }
  266.         goto reprocess;
  267.     case OLD_LINES:
  268.         if (buf[0] == '\n') {
  269.         strcpy(buf, "  \n");
  270.         }
  271.         if (buf[1] == '\n') {
  272.         strcpy(buf+1, " \n");
  273.         }
  274.         if (buf[1] != ' ') {
  275.         fprintf(stderr, "Malformed context diff at line %ld.\n",
  276.             line_num);
  277.         exit(1);
  278.         }
  279.         switch (*buf) {
  280.         case ' ':
  281.         type = ' ';
  282.         n_line++;
  283.         o_line++;
  284.         break;
  285.         case '-':
  286.         case '!':
  287.         type = '-';
  288.         o_line++;
  289.         break;
  290.         default:
  291.         fprintf(stderr, "Malformed context diff at line %ld.\n",
  292.             line_num);
  293.         exit(1);
  294.         }
  295.         if (o_line > o_last) {
  296.         add_line(type, 0, buf+2);
  297.         o_last = o_line;
  298.         n_last = n_line;
  299.         } else {
  300.         do {
  301.             hold = hold->link;
  302.         } while (hold->type == '+');
  303.         if (type != ' ') {
  304.             hold->type = type;
  305.             hold->num = 0;
  306.         }
  307.         }
  308.         if (o_line == o_end) {
  309.         state = PARSE_NEW;
  310.         }
  311.         break;
  312.     case PARSE_NEW:
  313.         if (*buf == '\n') {
  314.         break;
  315.         }
  316.         n_start = -1;
  317.         if (sscanf(buf, "--- %ld,%ld", &n_start, &n_end) != 2) {
  318.         if (n_start < 0) {
  319.             fprintf(stderr,
  320.             "Context diff missing 'new' header at line %ld.\n",
  321.             line_num);
  322.             exit(1);
  323.         }
  324.         n_end = n_start;
  325.         }
  326.         n_last = n_line;
  327.         o_line = o_start ? o_start-1 : 0;
  328.         n_line = n_start ? n_start-1 : 0;
  329.         n_last += n_line;
  330.         hold = head;
  331.         if (!n_first) {
  332.         n_first = n_start;
  333.         while (hold->link && hold->link->type == '-') {
  334.             hold = hold->link;
  335.             hold->num = ++o_line;
  336.         }
  337.         }
  338.         if (ndiff == '*' && n_last == n_end) {
  339.         state = PARSE_CDIFF;
  340.         break;
  341.         }
  342.         state = NEW_LINES;
  343.         break;
  344.     case NEW_LINES:
  345.         if (buf[0] == '\n') {
  346.         strcpy(buf, "  \n");
  347.         }
  348.         if (buf[1] == '\n') {
  349.         strcpy(buf+1, " \n");
  350.         }
  351.         if (buf[1] != ' ') {
  352.         fprintf(stderr, "Malformed context diff at line %ld.\n",
  353.             line_num);
  354.         exit(1);
  355.         }
  356.         switch (*buf) {
  357.         case ' ':
  358.         type = ' ';
  359.         n_line++;
  360.         o_line++;
  361.         break;
  362.         case '+':
  363.         case '!':
  364.         type = '+';
  365.         n_line++;
  366.         break;
  367.         default:
  368.         fprintf(stderr, "Malformed context diff at line %ld.\n",
  369.             line_num);
  370.         exit(1);
  371.         }
  372.         if (o_line > o_last) {
  373.         o_last = o_line;
  374.         add_line(type, o_line, buf+2);
  375.         n_last++;
  376.         } else if (type != ' ') {
  377.         add_line(type, 0, buf+2);
  378.         n_last++;
  379.         } else {
  380.         hold = hold->link;
  381.         hold->num = o_line;
  382.         while (hold->link && !hold->link->num
  383.             && hold->link->type != ' ') {
  384.             hold = hold->link;
  385.             if (hold->type == '-') {
  386.             hold->num = ++o_line;
  387.             }
  388.         }
  389.         }
  390.         if (o_line == o_end && n_line == n_end) {
  391.         state = PARSE_CDIFF;
  392.         }
  393.         break;
  394.     }/* switch */
  395.     }/* while */
  396.     generate_output();
  397.  
  398.     return 0;
  399. }
  400.  
  401. void
  402. ensure_name()
  403. {
  404.     char *cp = name;
  405.  
  406.     if (!found_index) {
  407.     if (!*name) {
  408.         fprintf(stderr,
  409.         "Couldn't find a name for the diff at line %ld.\n",
  410.         line_num);
  411.     } else if (patch_format) {
  412.         if (cp[0] == '.' && cp[1] == '/') {
  413.         cp += 2;
  414.         }
  415.         printf("Index: %s\n", cp);
  416.     }
  417.     }
  418. }
  419.  
  420. void
  421. add_line(type, num, str)
  422. char type;
  423. int num;
  424. char *str;
  425. {
  426.     line = (struct liner *)malloc(sizeof (struct liner) + strlen(str));
  427.     if (!line) {
  428.     fprintf(stderr, "Out of memory!\n");
  429.     exit(1);
  430.     }
  431.     line->type = type;
  432.     line->num = num;
  433.     strcpy(line->str, str);
  434.     line->link = hold->link;
  435.     hold->link = line;
  436.     hold = line;
  437. }
  438.  
  439. void
  440. generate_output()
  441. {
  442.     if (o_last < 0) {
  443.     return;
  444.     }
  445.     if (output_type == 1) {
  446.     int i, j;
  447.  
  448.     i = o_first ? o_last - o_first + 1 : 0;
  449.     j = n_first ? n_last - n_first + 1 : 0;
  450.     printf("@@ -%ld,%ld +%ld,%ld @@\n", o_first, i, n_first, j);
  451.     for (line = root.link; line; line = hold) {
  452.         printf("%c%s", patch_format && line->type == ' '? '=' : line->type,
  453.         line->str);
  454.         hold = line->link;
  455.         free(line);
  456.     }
  457.     } else { /* if output == 2 */
  458.     struct liner *scan;
  459.     int found_plus = 1;
  460.     char ch;
  461.  
  462.     printf("***************\n*** %ld", o_first);
  463.     if (o_first == o_last) {
  464.         printf(" ****\n");
  465.     } else {
  466.         printf(",%ld ****\n", o_last);
  467.     }
  468.     for (line = root.link; line; line = line->link) {
  469.         if (line->type == '-') {
  470.         break;
  471.         }
  472.     }
  473.     if (line) {
  474.         found_plus = 0;
  475.         ch = ' ';
  476.         for (line = root.link; line; line = line->link) {
  477.         switch (line->type) {
  478.         case '-':
  479.             if (ch != ' ') {
  480.             break;
  481.             }
  482.             scan = line;
  483.             while ((scan = scan->link) != NULL && scan->type == '-') {
  484.             ;
  485.             }
  486.             if (scan && scan->type == '+') {
  487.             do {
  488.                 scan->type = '!';
  489.             } while ((scan = scan->link) && scan->type == '+');
  490.             ch = '!';
  491.             } else {
  492.             ch = '-';
  493.             }
  494.             break;
  495.         case '+':
  496.         case '!':
  497.             found_plus = 1;
  498.             continue;
  499.         case ' ':
  500.             ch = ' ';
  501.             break;
  502.         }
  503.         printf("%c %s", ch, line->str);
  504.         }/* for */
  505.     }/* if */
  506.     if (n_first == n_last) {
  507.         printf("--- %ld ----\n", n_first);
  508.     } else {
  509.         printf("--- %ld,%ld ----\n", n_first, n_last);
  510.     }
  511.     if (found_plus) {
  512.         for (line = root.link; line; line = line->link) {
  513.         if (line->type != '-') {
  514.             printf("%c %s", line->type, line->str);
  515.         }
  516.         }
  517.     }
  518.     for (line = root.link; line; line = hold) {
  519.         hold = line->link;
  520.         free(line);
  521.     }
  522.     }/* if output == 2 */
  523.  
  524.     root.link = NULL;
  525.     head = &root;
  526.     hold = &root;
  527.  
  528.     o_first = 0;
  529.     n_first = 0;
  530.     o_last = -1;
  531.     n_last = 0;
  532. }
  533.