[ create a new paste ] login | about

Link: http://codepad.org/CKfqOSG2    [ raw code | output | fork ]

C, pasted on May 15:
  /* For printf() */
  #include <stdio.h>
  /* For malloc(), free(), EXIT_SUCCESS, EXIT_FAILURE */
  #include <stdlib.h>
  /* For memcpy() */
  #include <string.h>

  struct string {
      /*
       * Count of characters in the string,
       * excluding any null terminator, in bytes
       */
      size_t len;
      /* Size of the buffer itself, in bytes */
      size_t max_len;
      /* Points to the buffer */
      char * buf;
      /* For allocation convenience, the buffer can co-incide with this */
      char appended_buf[1];
    };
  /* You can use this macro for [wordy] convenience, as an initializer */
  #define STRING_INIT_FROM_STRING_LITERAL(string) \
    {sizeof string - 1, sizeof string, string, 0}

  /* Join non-empty strings with a specified, non-empty delimiter string */
  int join_strings_with_delim(
      struct string * output_str,
      const struct string * const * input_strings,
      const unsigned int input_string_count,
      const struct string * delim,
      int allocation
    ) {
      int i;
      size_t output_size;
      char * buf;

      /* Check output string */
      if (!output_str)
        return EXIT_FAILURE;
      /* Check delimiter string */
      if (!delim || !delim->buf || !delim->len)
        return EXIT_FAILURE;
      /* Check the strings to be joined */
      if (!input_string_count || input_string_count < 2 || !input_strings)
        return EXIT_FAILURE;
      for (i = 0, output_size = 0; i < input_string_count; ++i) {
          /* Check each input string */
          if (!input_strings[i] || !input_strings[i]->buf ||
              !input_strings[i]->len)
            return EXIT_FAILURE;
          /* Compute the output size */
          output_size += input_strings[i]->len;
        }
      /* Include the delimiter string size in the computation */
      output_size += delim->len * (input_string_count - 1);
      /* Include the null terminator */
      ++output_size;
      /* Should we allocate? */
      if (allocation) {
          buf = malloc(output_size);
          if (!buf)
            return EXIT_FAILURE;
          output_str->buf = buf;
          output_str->max_len = output_size;
          /* Exclude the null terminator from the string length */
          output_str->len = output_size - 1;
        } else {
          /* We don't allocate, so the caller ought to have */
          if (!output_str->buf || output_size > output_str->max_len)
            return EXIT_FAILURE;
          buf = output_str->buf;
        }
      /* Perform the join */
      i = 0;
      /* Skip the delimiter the first time around */
      goto skip_delim;
      do {
          size_t slen;
          slen = delim->len;
          memcpy(buf, delim->buf, slen);
          buf += slen;
          skip_delim:
          slen = input_strings[i]->len;
          memcpy(buf, input_strings[i]->buf, slen);
          buf += slen;
          ++i;
        } while (i < input_string_count);
      /* Terminate the string */
      *buf = 0;
      return EXIT_SUCCESS;
    }

  void free_string_buf(struct string * str) {
      if (!str) {
          /* Programmer error! */
          return;
        }
      free(str->buf);
      str->buf = NULL;
      str->len = str->max_len = 0;
      return;
    }

  int main(void) {
      /* These strings don't change, so we use 'static const' */
      static const struct string foo[] = {
          STRING_INIT_FROM_STRING_LITERAL("New York"),
          STRING_INIT_FROM_STRING_LITERAL("New Jersey"),
          STRING_INIT_FROM_STRING_LITERAL("New London"),
        };
      /* An array of pointers to these strings.  It oughtn't to change */
      static const struct string * const foo_ptrs[] =
        {foo, foo + 1, foo + 2};
      /* An output string for the joined strings */
      struct string foo_output;

      /* Or without the macro, we could have used the more redundant: */
      static const struct string bar[] = {
          {sizeof "New York" - 1, sizeof "New York", "New York", 0},
          {sizeof "New Jersey" - 1, sizeof "New Jersey", "New Jersey", 0},
          {sizeof "New London" - 1, sizeof "New London", "New London", 0},
        };
      /* An array of pointers to these strings.  It oughtn't to change */
      static const struct string * const bar_ptrs[] =
        {bar, bar + 1, bar + 2};
      /* An output string for the joined strings */
      struct string bar_output;

      /* The delimiter string.  It does not change */
      static const struct string delim_str =
        STRING_INIT_FROM_STRING_LITERAL(" ");

      /* Track any errors */
      int status;

      /*
       * Join the strings, with the specified delimiter,
       * into the output buffer.  The number of strings to process
       * can be calculated with 'sizeof array / sizeof *array'.
       * We happen to know that it's 3, but code can change over time
       */
      status = join_strings_with_delim(
          &foo_output,
          foo_ptrs,
          sizeof foo_ptrs / sizeof *foo_ptrs,
          &delim_str,
          1 /* Allocate the output buffer */
        );
      if (status == EXIT_FAILURE) {
          printf("Allocating foo_output failed!\n");
          return EXIT_FAILURE;
        }
      printf("foo_output: \"%s\"\n", foo_output.buf);
      /* Free the output buffer */
      free_string_buf(&foo_output);

      /* Same for 'bar' */
      status = join_strings_with_delim(
          &bar_output,
          bar_ptrs,
          sizeof bar_ptrs / sizeof *bar_ptrs,
          &delim_str,
          1 /* Allocate the output buffer */
        );
      if (status == EXIT_FAILURE) {
          printf("Allocating bar_output failed!\n");
          return EXIT_FAILURE;
        }
      printf("bar_output: \"%s\"\n", bar_output.buf);
      /* Free the output buffer */
      free_string_buf(&bar_output);

      return EXIT_SUCCESS;
    }


Output:
1
2
foo_output: "New York New Jersey New London"
bar_output: "New York New Jersey New London"


Create a new paste based on this one


Comments: