+static int copy_wsfix(char *output, const char *patch, int plen,
+ unsigned ws_rule)
+{
+ /*
+ * plen is number of bytes to be copied from patch, starting
+ * at patch. Typically patch[plen-1] is '\n', unless this is
+ * the incomplete last line.
+ */
+ int i;
+ int add_nl_to_tail = 0;
+ int fixed = 0;
+ int last_tab_in_indent = -1;
+ int last_space_in_indent = -1;
+ int need_fix_leading_space = 0;
+ char *buf;
+
+ /*
+ * Strip trailing whitespace
+ */
+ if ((ws_rule & WS_TRAILING_SPACE) &&
+ (2 < plen && isspace(patch[plen-2]))) {
+ if (patch[plen-1] == '\n')
+ add_nl_to_tail = 1;
+ plen--;
+ while (0 < plen && isspace(patch[plen-1]))
+ plen--;
+ fixed = 1;
+ }
+
+ /*
+ * Check leading whitespaces (indent)
+ */
+ for (i = 0; i < plen; i++) {
+ char ch = patch[i];
+ if (ch == '\t') {
+ last_tab_in_indent = i;
+ if ((ws_rule & WS_SPACE_BEFORE_TAB) &&
+ 0 <= last_space_in_indent)
+ need_fix_leading_space = 1;
+ } else if (ch == ' ') {
+ last_space_in_indent = i;
+ if ((ws_rule & WS_INDENT_WITH_NON_TAB) &&
+ 8 <= i - last_tab_in_indent)
+ need_fix_leading_space = 1;
+ } else
+ break;
+ }
+
+ buf = output;
+ if (need_fix_leading_space) {
+ /* Process indent ourselves */
+ int consecutive_spaces = 0;
+ int last = last_tab_in_indent + 1;
+
+ if (ws_rule & WS_INDENT_WITH_NON_TAB) {
+ /* have "last" point at one past the indent */
+ if (last_tab_in_indent < last_space_in_indent)
+ last = last_space_in_indent + 1;
+ else
+ last = last_tab_in_indent + 1;
+ }
+
+ /*
+ * between patch[0..last-1], strip the funny spaces,
+ * updating them to tab as needed.
+ */
+ for (i = 0; i < last; i++) {
+ char ch = patch[i];
+ if (ch != ' ') {
+ consecutive_spaces = 0;
+ *output++ = ch;
+ } else {
+ consecutive_spaces++;
+ if (consecutive_spaces == 8) {
+ *output++ = '\t';
+ consecutive_spaces = 0;
+ }
+ }
+ }
+ while (0 < consecutive_spaces--)
+ *output++ = ' ';
+ plen -= last;
+ patch += last;
+ fixed = 1;
+ }
+
+ memcpy(output, patch, plen);
+ if (add_nl_to_tail)
+ output[plen++] = '\n';
+ if (fixed)
+ applied_after_fixing_ws++;
+ return output + plen - buf;
+}
+