c_str.c
author viric@llimona
Thu, 31 May 2007 00:17:52 +0200
changeset 7 fcde17ef6af6
child 8 4ecd557ebebf
permissions -rw-r--r--
Separated backslash C parser library.

#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]);
}