Merge branch 'tr/maint-ident-to-git-memmove'
authorJunio C Hamano <gitster@pobox.com>
Fri, 2 Sep 2011 20:18:25 +0000 (13:18 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 2 Sep 2011 20:18:25 +0000 (13:18 -0700)
* tr/maint-ident-to-git-memmove:
Use memmove in ident_to_git

1  2 
convert.c
diff --combined convert.c
index 416bf83c75510930146dc0e3c2dd3273a9cb4e33,893b105adbe843371ca16492ae14cd1b297dec7d..3bb5a4dd57c669bc59be0e2317ef33b64b024992
+++ b/convert.c
@@@ -533,7 -533,7 +533,7 @@@ static int ident_to_git(const char *pat
                dollar = memchr(src, '$', len);
                if (!dollar)
                        break;
-               memcpy(dst, src, dollar + 1 - src);
+               memmove(dst, src, dollar + 1 - src);
                dst += dollar + 1 - src;
                len -= dollar + 1 - src;
                src  = dollar + 1;
                        src  = dollar + 1;
                }
        }
-       memcpy(dst, src, len);
+       memmove(dst, src, len);
        strbuf_setlen(buf, dst + len - buf->buf);
        return 1;
  }
@@@ -727,7 -727,7 +727,7 @@@ static void convert_attrs(struct conv_a
                git_config(read_convert_config, NULL);
        }
  
 -      if (!git_checkattr(path, NUM_CONV_ATTRS, ccheck)) {
 +      if (!git_check_attr(path, NUM_CONV_ATTRS, ccheck)) {
                ca->crlf_action = git_path_check_crlf(path, ccheck + 4);
                if (ca->crlf_action == CRLF_GUESS)
                        ca->crlf_action = git_path_check_crlf(path, ccheck + 0);
@@@ -813,400 -813,3 +813,400 @@@ int renormalize_buffer(const char *path
        }
        return ret | convert_to_git(path, src, len, dst, 0);
  }
 +
 +/*****************************************************************
 + *
 + * Streaming converison support
 + *
 + *****************************************************************/
 +
 +typedef int (*filter_fn)(struct stream_filter *,
 +                       const char *input, size_t *isize_p,
 +                       char *output, size_t *osize_p);
 +typedef void (*free_fn)(struct stream_filter *);
 +
 +struct stream_filter_vtbl {
 +      filter_fn filter;
 +      free_fn free;
 +};
 +
 +struct stream_filter {
 +      struct stream_filter_vtbl *vtbl;
 +};
 +
 +static int null_filter_fn(struct stream_filter *filter,
 +                        const char *input, size_t *isize_p,
 +                        char *output, size_t *osize_p)
 +{
 +      size_t count;
 +
 +      if (!input)
 +              return 0; /* we do not keep any states */
 +      count = *isize_p;
 +      if (*osize_p < count)
 +              count = *osize_p;
 +      if (count) {
 +              memmove(output, input, count);
 +              *isize_p -= count;
 +              *osize_p -= count;
 +      }
 +      return 0;
 +}
 +
 +static void null_free_fn(struct stream_filter *filter)
 +{
 +      ; /* nothing -- null instances are shared */
 +}
 +
 +static struct stream_filter_vtbl null_vtbl = {
 +      null_filter_fn,
 +      null_free_fn,
 +};
 +
 +static struct stream_filter null_filter_singleton = {
 +      &null_vtbl,
 +};
 +
 +int is_null_stream_filter(struct stream_filter *filter)
 +{
 +      return filter == &null_filter_singleton;
 +}
 +
 +
 +/*
 + * LF-to-CRLF filter
 + */
 +static int lf_to_crlf_filter_fn(struct stream_filter *filter,
 +                              const char *input, size_t *isize_p,
 +                              char *output, size_t *osize_p)
 +{
 +      size_t count;
 +
 +      if (!input)
 +              return 0; /* we do not keep any states */
 +      count = *isize_p;
 +      if (count) {
 +              size_t i, o;
 +              for (i = o = 0; o < *osize_p && i < count; i++) {
 +                      char ch = input[i];
 +                      if (ch == '\n') {
 +                              if (o + 1 < *osize_p)
 +                                      output[o++] = '\r';
 +                              else
 +                                      break;
 +                      }
 +                      output[o++] = ch;
 +              }
 +
 +              *osize_p -= o;
 +              *isize_p -= i;
 +      }
 +      return 0;
 +}
 +
 +static struct stream_filter_vtbl lf_to_crlf_vtbl = {
 +      lf_to_crlf_filter_fn,
 +      null_free_fn,
 +};
 +
 +static struct stream_filter lf_to_crlf_filter_singleton = {
 +      &lf_to_crlf_vtbl,
 +};
 +
 +
 +/*
 + * Cascade filter
 + */
 +#define FILTER_BUFFER 1024
 +struct cascade_filter {
 +      struct stream_filter filter;
 +      struct stream_filter *one;
 +      struct stream_filter *two;
 +      char buf[FILTER_BUFFER];
 +      int end, ptr;
 +};
 +
 +static int cascade_filter_fn(struct stream_filter *filter,
 +                           const char *input, size_t *isize_p,
 +                           char *output, size_t *osize_p)
 +{
 +      struct cascade_filter *cas = (struct cascade_filter *) filter;
 +      size_t filled = 0;
 +      size_t sz = *osize_p;
 +      size_t to_feed, remaining;
 +
 +      /*
 +       * input -- (one) --> buf -- (two) --> output
 +       */
 +      while (filled < sz) {
 +              remaining = sz - filled;
 +
 +              /* do we already have something to feed two with? */
 +              if (cas->ptr < cas->end) {
 +                      to_feed = cas->end - cas->ptr;
 +                      if (stream_filter(cas->two,
 +                                        cas->buf + cas->ptr, &to_feed,
 +                                        output + filled, &remaining))
 +                              return -1;
 +                      cas->ptr += (cas->end - cas->ptr) - to_feed;
 +                      filled = sz - remaining;
 +                      continue;
 +              }
 +
 +              /* feed one from upstream and have it emit into our buffer */
 +              to_feed = input ? *isize_p : 0;
 +              if (input && !to_feed)
 +                      break;
 +              remaining = sizeof(cas->buf);
 +              if (stream_filter(cas->one,
 +                                input, &to_feed,
 +                                cas->buf, &remaining))
 +                      return -1;
 +              cas->end = sizeof(cas->buf) - remaining;
 +              cas->ptr = 0;
 +              if (input) {
 +                      size_t fed = *isize_p - to_feed;
 +                      *isize_p -= fed;
 +                      input += fed;
 +              }
 +
 +              /* do we know that we drained one completely? */
 +              if (input || cas->end)
 +                      continue;
 +
 +              /* tell two to drain; we have nothing more to give it */
 +              to_feed = 0;
 +              remaining = sz - filled;
 +              if (stream_filter(cas->two,
 +                                NULL, &to_feed,
 +                                output + filled, &remaining))
 +                      return -1;
 +              if (remaining == (sz - filled))
 +                      break; /* completely drained two */
 +              filled = sz - remaining;
 +      }
 +      *osize_p -= filled;
 +      return 0;
 +}
 +
 +static void cascade_free_fn(struct stream_filter *filter)
 +{
 +      struct cascade_filter *cas = (struct cascade_filter *)filter;
 +      free_stream_filter(cas->one);
 +      free_stream_filter(cas->two);
 +      free(filter);
 +}
 +
 +static struct stream_filter_vtbl cascade_vtbl = {
 +      cascade_filter_fn,
 +      cascade_free_fn,
 +};
 +
 +static struct stream_filter *cascade_filter(struct stream_filter *one,
 +                                          struct stream_filter *two)
 +{
 +      struct cascade_filter *cascade;
 +
 +      if (!one || is_null_stream_filter(one))
 +              return two;
 +      if (!two || is_null_stream_filter(two))
 +              return one;
 +
 +      cascade = xmalloc(sizeof(*cascade));
 +      cascade->one = one;
 +      cascade->two = two;
 +      cascade->end = cascade->ptr = 0;
 +      cascade->filter.vtbl = &cascade_vtbl;
 +      return (struct stream_filter *)cascade;
 +}
 +
 +/*
 + * ident filter
 + */
 +#define IDENT_DRAINING (-1)
 +#define IDENT_SKIPPING (-2)
 +struct ident_filter {
 +      struct stream_filter filter;
 +      struct strbuf left;
 +      int state;
 +      char ident[45]; /* ": x40 $" */
 +};
 +
 +static int is_foreign_ident(const char *str)
 +{
 +      int i;
 +
 +      if (prefixcmp(str, "$Id: "))
 +              return 0;
 +      for (i = 5; str[i]; i++) {
 +              if (isspace(str[i]) && str[i+1] != '$')
 +                      return 1;
 +      }
 +      return 0;
 +}
 +
 +static void ident_drain(struct ident_filter *ident, char **output_p, size_t *osize_p)
 +{
 +      size_t to_drain = ident->left.len;
 +
 +      if (*osize_p < to_drain)
 +              to_drain = *osize_p;
 +      if (to_drain) {
 +              memcpy(*output_p, ident->left.buf, to_drain);
 +              strbuf_remove(&ident->left, 0, to_drain);
 +              *output_p += to_drain;
 +              *osize_p -= to_drain;
 +      }
 +      if (!ident->left.len)
 +              ident->state = 0;
 +}
 +
 +static int ident_filter_fn(struct stream_filter *filter,
 +                         const char *input, size_t *isize_p,
 +                         char *output, size_t *osize_p)
 +{
 +      struct ident_filter *ident = (struct ident_filter *)filter;
 +      static const char head[] = "$Id";
 +
 +      if (!input) {
 +              /* drain upon eof */
 +              switch (ident->state) {
 +              default:
 +                      strbuf_add(&ident->left, head, ident->state);
 +              case IDENT_SKIPPING:
 +                      /* fallthru */
 +              case IDENT_DRAINING:
 +                      ident_drain(ident, &output, osize_p);
 +              }
 +              return 0;
 +      }
 +
 +      while (*isize_p || (ident->state == IDENT_DRAINING)) {
 +              int ch;
 +
 +              if (ident->state == IDENT_DRAINING) {
 +                      ident_drain(ident, &output, osize_p);
 +                      if (!*osize_p)
 +                              break;
 +                      continue;
 +              }
 +
 +              ch = *(input++);
 +              (*isize_p)--;
 +
 +              if (ident->state == IDENT_SKIPPING) {
 +                      /*
 +                       * Skipping until '$' or LF, but keeping them
 +                       * in case it is a foreign ident.
 +                       */
 +                      strbuf_addch(&ident->left, ch);
 +                      if (ch != '\n' && ch != '$')
 +                              continue;
 +                      if (ch == '$' && !is_foreign_ident(ident->left.buf)) {
 +                              strbuf_setlen(&ident->left, sizeof(head) - 1);
 +                              strbuf_addstr(&ident->left, ident->ident);
 +                      }
 +                      ident->state = IDENT_DRAINING;
 +                      continue;
 +              }
 +
 +              if (ident->state < sizeof(head) &&
 +                  head[ident->state] == ch) {
 +                      ident->state++;
 +                      continue;
 +              }
 +
 +              if (ident->state)
 +                      strbuf_add(&ident->left, head, ident->state);
 +              if (ident->state == sizeof(head) - 1) {
 +                      if (ch != ':' && ch != '$') {
 +                              strbuf_addch(&ident->left, ch);
 +                              ident->state = 0;
 +                              continue;
 +                      }
 +
 +                      if (ch == ':') {
 +                              strbuf_addch(&ident->left, ch);
 +                              ident->state = IDENT_SKIPPING;
 +                      } else {
 +                              strbuf_addstr(&ident->left, ident->ident);
 +                              ident->state = IDENT_DRAINING;
 +                      }
 +                      continue;
 +              }
 +
 +              strbuf_addch(&ident->left, ch);
 +              ident->state = IDENT_DRAINING;
 +      }
 +      return 0;
 +}
 +
 +static void ident_free_fn(struct stream_filter *filter)
 +{
 +      struct ident_filter *ident = (struct ident_filter *)filter;
 +      strbuf_release(&ident->left);
 +      free(filter);
 +}
 +
 +static struct stream_filter_vtbl ident_vtbl = {
 +      ident_filter_fn,
 +      ident_free_fn,
 +};
 +
 +static struct stream_filter *ident_filter(const unsigned char *sha1)
 +{
 +      struct ident_filter *ident = xmalloc(sizeof(*ident));
 +
 +      sprintf(ident->ident, ": %s $", sha1_to_hex(sha1));
 +      strbuf_init(&ident->left, 0);
 +      ident->filter.vtbl = &ident_vtbl;
 +      ident->state = 0;
 +      return (struct stream_filter *)ident;
 +}
 +
 +/*
 + * Return an appropriately constructed filter for the path, or NULL if
 + * the contents cannot be filtered without reading the whole thing
 + * in-core.
 + *
 + * Note that you would be crazy to set CRLF, smuge/clean or ident to a
 + * large binary blob you would want us not to slurp into the memory!
 + */
 +struct stream_filter *get_stream_filter(const char *path, const unsigned char *sha1)
 +{
 +      struct conv_attrs ca;
 +      enum crlf_action crlf_action;
 +      struct stream_filter *filter = NULL;
 +
 +      convert_attrs(&ca, path);
 +
 +      if (ca.drv && (ca.drv->smudge || ca.drv->clean))
 +              return filter;
 +
 +      if (ca.ident)
 +              filter = ident_filter(sha1);
 +
 +      crlf_action = input_crlf_action(ca.crlf_action, ca.eol_attr);
 +
 +      if ((crlf_action == CRLF_BINARY) || (crlf_action == CRLF_INPUT) ||
 +          (crlf_action == CRLF_GUESS && auto_crlf == AUTO_CRLF_FALSE))
 +              filter = cascade_filter(filter, &null_filter_singleton);
 +
 +      else if (output_eol(crlf_action) == EOL_CRLF &&
 +               !(crlf_action == CRLF_AUTO || crlf_action == CRLF_GUESS))
 +              filter = cascade_filter(filter, &lf_to_crlf_filter_singleton);
 +
 +      return filter;
 +}
 +
 +void free_stream_filter(struct stream_filter *filter)
 +{
 +      filter->vtbl->free(filter);
 +}
 +
 +int stream_filter(struct stream_filter *filter,
 +                const char *input, size_t *isize_p,
 +                char *output, size_t *osize_p)
 +{
 +      return filter->vtbl->filter(filter, input, isize_p, output, osize_p);
 +}