c_str.c
author viric@llimona
Wed, 04 Jul 2007 21:44:29 +0200
changeset 11 0ef0d9c52f82
parent 7 fcde17ef6af6
child 8 4ecd557ebebf
permissions -rw-r--r--
Added compile time flag for verbose

#include <stdio.h>

#include "sreplace.h"

/* Complete set of backslash sequences:

 From K&R, The C Programming Language, Chapter 2, Constants.

 \b backspace
 \?  question mark
 \f formfeed
  \' single quote
 \n newline
 \" double quote
 \r carriage return
 \ooo octal number
 \t horizontal tab
 \xhh hexadecimal number 
 \v vertical tab

 (\\ backslash)
*/

/* Returns length */
int parse_backslashes(unsigned char *str)
{
  int was_backslash = 0;
  int was_octal = 0; /* 0 to 3 */
  int was_hex = 0; /* 0 to 2 */
  unsigned char *write_str = str;
  unsigned char *start = str;
  unsigned char newchar;

  while (*str != 0)
  {
    if (*str == '\\' && !was_backslash)
      was_backslash = 1;
    else
    {
      if (was_octal)
      {
        if (was_octal < 3 && *str >= '0' && *str <= '7')
        {
          newchar = (newchar * 8) + (*str - '0');
          was_octal += 1;
          if (was_octal == 3)
          {
            *(write_str++) = newchar;
            was_octal = 0;
          }
        } else /* Didn't come octal char. End of oct string. */
        {
          *(write_str++) = newchar;
          *(write_str++) = *str;
          was_octal = 0;
        }
      }
      else if (was_hex)
      {
        unsigned char base = 0;

        if (*str >= '0' && *str <= '9')
          base = '0';
        else if (*str >= 'a' && *str <= 'f')
          base = 'a' - 10;
        else if (*str >= 'A' && *str <= 'F')
          base = 'A' - 10;

        if (base != 0) /* Came hex char */
        {
          newchar = (newchar * 16) + (*str - base);
          was_hex += 1;

          if (was_hex == 3) /* End of hex string */
          {
            *(write_str++) = newchar;
            was_hex = 0;
          }
        }
        else /* Non-hex char came. End of hex string */
        {
          *(write_str++) = newchar;
          *(write_str++) = *str;
          was_hex = 0;
        }
      }
      else if (was_backslash)
      { switch(*str)
        {
          case '\\':
            *(write_str++) = '\\';
            break;
          case 'n':
            *(write_str++) = '\n';
            break;
          case 't':
            *(write_str++) = '\t';
            break;
          case 'r':
            *(write_str++) = '\r';
            break;
          case 'v':
            *(write_str++) = '\v';
            break;
          case 'f':
            *(write_str++) = '\f';
            break;
          case 'b':
            *(write_str++) = '\b';
            break;
          case '0':
          case '1':
          case '2':
          case '3':
          case '4':
          case '5':
          case '6':
          case '7':
            was_octal = 1;
            newchar = 0;
            break;
          case 'x':
            was_hex = 1;
            newchar = 0;
            break;
          default:
            *(write_str++) = *str;
        }
        was_backslash = 0;
      }
      else
        *(write_str++) = *str;
    }
    ++str;
  }
  *(write_str) = '\0';

  /* We calculate length with distance between the last
   * written char and the start of the string */
  return write_str - start;
}

void print_hex(FILE *out, const struct String *str)
{
    int i;

    fprintf(out, "Length: %i\n", str->length);
    for (i = 0; i < str->length; ++i)
        fprintf(out, "%02hhx", str->ptr[i]);
}