// **********************************************************************
//
// Copyright (c) 1999
// Object Oriented Concepts, Inc.
// Billerica, MA, USA
//
// All Rights Reserved
//
// **********************************************************************

#include <OB/CORBA.h>

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

// ----------------------------------------------------------------------
// Convert strings with escape sequences
// ----------------------------------------------------------------------

void
IdlAddEscapes(char*& str, bool addQuotes)
{
    char* s = str;
    CORBA_String_var result = CORBA_string_dup("");

    if(addQuotes)
	result += '"';

    while(*s)
    {
	switch(*s)
	{
	case '\n':
	    result += "\\n";
	    break;

	case '\t':
	    result += "\\t";
	    break;

	case '\v':
	    result += "\\v";
	    break;

	case '\b':
	    result += "\\b";
	    break;

	case '\r':
	    result += "\\r";
	    break;

	case '\f':
	    result += "\\f";
	    break;

	case '\a':
	    result += "\\a";
	    break;

	case '\\':
	    result += "\\\\";
	    break;
	    
 	case '\?':
 	    result += "\\?";
 	    break;
	    
	case '\'':
	    result += "\\'";
	    break;

	case '"':
	    result += "\\\"";
	    break;

	default:
	    if(isprint(*s))
		result += *s;
	    else
	    {
		CORBA_Char c = *s;
		char str[5];
		sprintf(str, "\\%.3o", c);
		result += str;
	    }
	    break;
	}
	
	s++;
    }

    if(addQuotes)
	result += '"';

    CORBA_string_free(str);
    str = result._retn();
}

bool
IdlRemoveEscapes(char*& str, bool removeQuotes)
{
    char* s = str;
    CORBA_String_var result = CORBA_string_dup("");
    bool b = true;

    if(removeQuotes && *s == '"')
	s++;

    while(*s)
    {
	if(removeQuotes && *(s + 1) == 0 && *s == '"')
	    break;

	if(*s != '\\')
	{
	    result += *s;
	    s++;
	}
	else
	{
	    switch(*(s + 1))
	    {
	    case 'n':
		result += '\n';
		s += 2;
		break;

	    case 't':
		result += '\t';
		s += 2;
		break;

	    case 'v':
		result += '\v';
		s += 2;
		break;

	    case 'b':
		result += '\b';
		s += 2;
		break;

	    case 'r':
		result += '\r';
		s += 2;
		break;

	    case 'f':
		result += '\f';
		s += 2;
		break;

	    case 'a':
		result += '\a';
		s += 2;
		break;

	    case '\\':
		result += '\\';
		s += 2;
		break;

	    case '?':
		result += '\?';
		s += 2;
		break;

	    case '\'':
		result += '\'';
		s += 2;
		break;

	    case '"':
		result += '\"';
		s += 2;
		break;

	    case 'x':
	    {
		if((*(s + 2) >= '0' && *(s + 2) <= '9') ||
		   (*(s + 2) >= 'a' && *(s + 2) <= 'f') ||
		   (*(s + 2) >= 'A' && *(s + 2) <= 'F'))
		{
		    char* s2;
		    CORBA_Char c = (CORBA_Char)strtol(s + 2, &s2, 16);

 		    if(c == 0)
			b = false;

		    result += c;

		    s = s2;
		}
		else
		{
		    result += '\\';
		    s++;
		}

		break;
	    }
	    
	    case '0':
	    case '1':
	    case '2':
	    case '3':
	    case '4':
	    case '5':
	    case '6':
	    case '7':
	    {
		char* s2;
		CORBA_Char c = (CORBA_Char)strtol(s + 1, &s2, 8);
		
 		if(c == 0)
		    b = false;
			
		result += c;

		s = s2;

		break;
	    }

	    default:
		result += '\\';
		s++;
		break;
	    }
	}
    }

    CORBA_string_free(str);
    str = result._retn();

    return b;
}

// ----------------------------------------------------------------------
// Check for recursion
// ----------------------------------------------------------------------

bool
IdlCheckForRecursion(const char* id, CORBA_TypeCode_ptr type)
{
    //
    // Check for recursive sequences
    //
    if(type -> kind() == CORBA_tk_sequence && type -> offset() != 0)
    {
	CORBA_TypeCode_var contentType = type -> content_type();
	if(strcmp(id, contentType -> id()) == 0)
	    return true;
    }

    //
    // Check for non-recursive sequences, arrays and aliases
    //
    if((type -> kind() == CORBA_tk_sequence && type -> offset() == 0) ||
       type -> kind() == CORBA_tk_array ||
       type -> kind() == CORBA_tk_alias)
    {
	CORBA_TypeCode_var contentType = type -> content_type();
	return IdlCheckForRecursion(id, contentType);
    }

    //
    // Check for structs, unions and exceptions
    //
    if(type -> kind() == CORBA_tk_struct ||
       type -> kind() == CORBA_tk_union ||
       type -> kind() == CORBA_tk_except)
    {
	if(strcmp(id, type -> id()) == 0)
	    return true;

	for(CORBA_ULong i = 0 ; i < type -> member_count() ; i++)
	{
	    CORBA_TypeCode_var memberType = type -> member_type(i);

	    if(IdlCheckForRecursion(id, memberType))
		return true;
	}
    }

    return false;
}
