FreeBSD/sys/contrib/dev/acpica/components/executer/exconcat.c
/*******************************************************************************
 *
 * FUNCTION:    AcpiExDoConcatenate
 *
 * PARAMETERS:  Operand0            - First source object
 *              Operand1            - Second source object
 *              ActualReturnDesc    - Where to place the return object
 *              WalkState           - Current walk state
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Concatenate two objects with the ACPI-defined conversion
 *              rules as necessary.
 * NOTE:
 * Per the ACPI spec (up to 6.1), Concatenate only supports Integer,
 * String, and Buffer objects. However, we support all objects here
 * as an extension. This improves the usefulness of both Concatenate
 * and the Printf/Fprintf macros. The extension returns a string
 * describing the object type for the other objects.
 * 02/2016.
 *
 ******************************************************************************/
AcpiExDoConcatenate
PARAMETERS:  Operand0            - First source object
Operand1            - Second source object
ActualReturnDesc    - Where to place the return object
WalkState           - Current walk state

Status

Concatenate two objects with the ACPI-defined conversion
rules as necessary.
NOTE:
Per the ACPI spec (up to 6.1), Concatenate only supports Integer,
String, and Buffer objects. However, we support all objects here
as an extension. This improves the usefulness of both Concatenate
and the Printf/Fprintf macros. The extension returns a string
describing the object type for the other objects.
AcpiExDoConcatenate PARAMETERS : Operand0 - First source object Operand1 - Second source object ActualReturnDesc - Where to place the return object WalkState - Current walk state Status Concatenate two objects with the ACPI - defined conversion rules as necessary . NOTE : Per the ACPI spec ( up to 6 . 1 ) Concatenate only supports Integer String and Buffer objects . However we support all objects here as an extension . This improves the usefulness of both Concatenate and the Printf / Fprintf macros . The extension returns a string describing the object type for the other objects .
ACPI_STATUS
AcpiExDoConcatenate (
    ACPI_OPERAND_OBJECT     *Operand0,
    ACPI_OPERAND_OBJECT     *Operand1,
    ACPI_OPERAND_OBJECT     **ActualReturnDesc,
    ACPI_WALK_STATE         *WalkState)
{
    ACPI_OPERAND_OBJECT     *LocalOperand0 = Operand0;
    ACPI_OPERAND_OBJECT     *LocalOperand1 = Operand1;
    ACPI_OPERAND_OBJECT     *TempOperand1 = NULL;
    ACPI_OPERAND_OBJECT     *ReturnDesc;
    char                    *Buffer;
    ACPI_OBJECT_TYPE        Operand0Type;
    ACPI_OBJECT_TYPE        Operand1Type;
    ACPI_STATUS             Status;
    ACPI_FUNCTION_TRACE (ExDoConcatenate);
    switch (Operand0->Common.Type)
    {
    case ACPI_TYPE_INTEGER:
    case ACPI_TYPE_STRING:
    case ACPI_TYPE_BUFFER:
        Operand0Type = Operand0->Common.Type;
        break;
    default:
        Status = AcpiExConvertToObjectTypeString (
            Operand0, &LocalOperand0);
        if (ACPI_FAILURE (Status))
        {
            goto Cleanup;
        }
        Operand0Type = ACPI_TYPE_STRING;
        break;
    }
    switch (Operand1->Common.Type)
    {
    case ACPI_TYPE_INTEGER:
    case ACPI_TYPE_STRING:
    case ACPI_TYPE_BUFFER:
        Operand1Type = Operand1->Common.Type;
        break;
    default:
        Status = AcpiExConvertToObjectTypeString (
            Operand1, &LocalOperand1);
        if (ACPI_FAILURE (Status))
        {
            goto Cleanup;
        }
        Operand1Type = ACPI_TYPE_STRING;
        break;
    }
    switch (Operand0Type)
    {
    case ACPI_TYPE_INTEGER:
        Status = AcpiExConvertToInteger (LocalOperand1, &TempOperand1, 16);
        break;
    case ACPI_TYPE_BUFFER:
        Status = AcpiExConvertToBuffer (LocalOperand1, &TempOperand1);
        break;
    case ACPI_TYPE_STRING:
        switch (Operand1Type)
        {
        case ACPI_TYPE_INTEGER:
        case ACPI_TYPE_STRING:
        case ACPI_TYPE_BUFFER:
            Status = AcpiExConvertToString (
                LocalOperand1, &TempOperand1, ACPI_IMPLICIT_CONVERT_HEX);
            break;
        default:
            Status = AE_OK;
            break;
        }
        break;
    default:
        ACPI_ERROR ((AE_INFO, "Invalid object type: 0x%X",
            Operand0->Common.Type));
        Status = AE_AML_INTERNAL;
    }
    if (ACPI_FAILURE (Status))
    {
        goto Cleanup;
    }
    if ((LocalOperand1 != Operand1) &&
        (LocalOperand1 != TempOperand1))
    {
        AcpiUtRemoveReference (LocalOperand1);
    }
    LocalOperand1 = TempOperand1;
    switch (Operand0Type)
    {
    case ACPI_TYPE_INTEGER:
        ReturnDesc = AcpiUtCreateBufferObject (
            (ACPI_SIZE) ACPI_MUL_2 (AcpiGbl_IntegerByteWidth));
        if (!ReturnDesc)
        {
            Status = AE_NO_MEMORY;
            goto Cleanup;
        }
        Buffer = (char *) ReturnDesc->Buffer.Pointer;
        memcpy (Buffer, &Operand0->Integer.Value,
            AcpiGbl_IntegerByteWidth);
        memcpy (Buffer + AcpiGbl_IntegerByteWidth,
            &LocalOperand1->Integer.Value, AcpiGbl_IntegerByteWidth);
        break;
    case ACPI_TYPE_STRING:
        ReturnDesc = AcpiUtCreateStringObject (
            ((ACPI_SIZE) LocalOperand0->String.Length +
            LocalOperand1->String.Length));
        if (!ReturnDesc)
        {
            Status = AE_NO_MEMORY;
            goto Cleanup;
        }
        Buffer = ReturnDesc->String.Pointer;
        strcpy (Buffer, LocalOperand0->String.Pointer);
        strcat (Buffer, LocalOperand1->String.Pointer);
        break;
    case ACPI_TYPE_BUFFER:
        ReturnDesc = AcpiUtCreateBufferObject (
            ((ACPI_SIZE) Operand0->Buffer.Length +
            LocalOperand1->Buffer.Length));
        if (!ReturnDesc)
        {
            Status = AE_NO_MEMORY;
            goto Cleanup;
        }
        Buffer = (char *) ReturnDesc->Buffer.Pointer;
        memcpy (Buffer, Operand0->Buffer.Pointer,
            Operand0->Buffer.Length);
        memcpy (Buffer + Operand0->Buffer.Length,
            LocalOperand1->Buffer.Pointer,
            LocalOperand1->Buffer.Length);
        break;
    default:
        ACPI_ERROR ((AE_INFO, "Invalid object type: 0x%X",
            Operand0->Common.Type));
        Status = AE_AML_INTERNAL;
        goto Cleanup;
    }
    *ActualReturnDesc = ReturnDesc;
Cleanup:
    if (LocalOperand0 != Operand0)
    {
        AcpiUtRemoveReference (LocalOperand0);
    }
    if (LocalOperand1 != Operand1)
    {
        AcpiUtRemoveReference (LocalOperand1);
    }
    return_ACPI_STATUS (Status);
}
ACPI_STATUS AcpiExDoConcatenate ( ACPI_OPERAND_OBJECT * Operand0 , ACPI_OPERAND_OBJECT * Operand1 , ACPI_OPERAND_OBJECT * * ActualReturnDesc , ACPI_WALK_STATE * WalkState ) { ACPI_OPERAND_OBJECT * LocalOperand0 = Operand0 ; ACPI_OPERAND_OBJECT * LocalOperand1 = Operand1 ; ACPI_OPERAND_OBJECT * TempOperand1 = NULL ; ACPI_OPERAND_OBJECT * ReturnDesc ; char * Buffer ; ACPI_OBJECT_TYPE Operand0Type ; ACPI_OBJECT_TYPE Operand1Type ; ACPI_STATUS Status ; ACPI_FUNCTION_TRACE ( ExDoConcatenate ) ; switch ( Operand0 -> Common . Type ) { case ACPI_TYPE_INTEGER : case ACPI_TYPE_STRING : case ACPI_TYPE_BUFFER : Operand0Type = Operand0 -> Common . Type ; break ; default : Status = AcpiExConvertToObjectTypeString ( Operand0 , & LocalOperand0 ) ; if ( ACPI_FAILURE ( Status ) ) { goto Cleanup ; } Operand0Type = ACPI_TYPE_STRING ; break ; } switch ( Operand1 -> Common . Type ) { case ACPI_TYPE_INTEGER : case ACPI_TYPE_STRING : case ACPI_TYPE_BUFFER : Operand1Type = Operand1 -> Common . Type ; break ; default : Status = AcpiExConvertToObjectTypeString ( Operand1 , & LocalOperand1 ) ; if ( ACPI_FAILURE ( Status ) ) { goto Cleanup ; } Operand1Type = ACPI_TYPE_STRING ; break ; } switch ( Operand0Type ) { case ACPI_TYPE_INTEGER : Status = AcpiExConvertToInteger ( LocalOperand1 , & TempOperand1 , 16 ) ; break ; case ACPI_TYPE_BUFFER : Status = AcpiExConvertToBuffer ( LocalOperand1 , & TempOperand1 ) ; break ; case ACPI_TYPE_STRING : switch ( Operand1Type ) { case ACPI_TYPE_INTEGER : case ACPI_TYPE_STRING : case ACPI_TYPE_BUFFER : Status = AcpiExConvertToString ( LocalOperand1 , & TempOperand1 , ACPI_IMPLICIT_CONVERT_HEX ) ; break ; default : Status = AE_OK ; break ; } break ; default : ACPI_ERROR ( ( AE_INFO , " " , Operand0 -> Common . Type ) ) ; Status = AE_AML_INTERNAL ; } if ( ACPI_FAILURE ( Status ) ) { goto Cleanup ; } if ( ( LocalOperand1 != Operand1 ) && ( LocalOperand1 != TempOperand1 ) ) { AcpiUtRemoveReference ( LocalOperand1 ) ; } LocalOperand1 = TempOperand1 ; switch ( Operand0Type ) { case ACPI_TYPE_INTEGER : ReturnDesc = AcpiUtCreateBufferObject ( ( ACPI_SIZE ) ACPI_MUL_2 ( AcpiGbl_IntegerByteWidth ) ) ; if ( ! ReturnDesc ) { Status = AE_NO_MEMORY ; goto Cleanup ; } Buffer = ( char * ) ReturnDesc -> Buffer . Pointer ; memcpy ( Buffer , & Operand0 -> Integer . Value , AcpiGbl_IntegerByteWidth ) ; memcpy ( Buffer + AcpiGbl_IntegerByteWidth , & LocalOperand1 -> Integer . Value , AcpiGbl_IntegerByteWidth ) ; break ; case ACPI_TYPE_STRING : ReturnDesc = AcpiUtCreateStringObject ( ( ( ACPI_SIZE ) LocalOperand0 -> String . Length + LocalOperand1 -> String . Length ) ) ; if ( ! ReturnDesc ) { Status = AE_NO_MEMORY ; goto Cleanup ; } Buffer = ReturnDesc -> String . Pointer ; strcpy ( Buffer , LocalOperand0 -> String . Pointer ) ; strcat ( Buffer , LocalOperand1 -> String . Pointer ) ; break ; case ACPI_TYPE_BUFFER : ReturnDesc = AcpiUtCreateBufferObject ( ( ( ACPI_SIZE ) Operand0 -> Buffer . Length + LocalOperand1 -> Buffer . Length ) ) ; if ( ! ReturnDesc ) { Status = AE_NO_MEMORY ; goto Cleanup ; } Buffer = ( char * ) ReturnDesc -> Buffer . Pointer ; memcpy ( Buffer , Operand0 -> Buffer . Pointer , Operand0 -> Buffer . Length ) ; memcpy ( Buffer + Operand0 -> Buffer . Length , LocalOperand1 -> Buffer . Pointer , LocalOperand1 -> Buffer . Length ) ; break ; default : ACPI_ERROR ( ( AE_INFO , " " , Operand0 -> Common . Type ) ) ; Status = AE_AML_INTERNAL ; goto Cleanup ; } * ActualReturnDesc = ReturnDesc ; Cleanup : if ( LocalOperand0 != Operand0 ) { AcpiUtRemoveReference ( LocalOperand0 ) ; } if ( LocalOperand1 != Operand1 ) { AcpiUtRemoveReference ( LocalOperand1 ) ; } return_ACPI_STATUS ( Status ) ; }
FUNCTION:    AcpiExDoConcatenate
 PARAMETERS:  Operand0            - First source object
              Operand1            - Second source object
              ActualReturnDesc    - Where to place the return object
              WalkState           - Current walk state
FUNCTION : AcpiExDoConcatenate PARAMETERS : Operand0 - First source object Operand1 - Second source object ActualReturnDesc - Where to place the return object WalkState - Current walk state
/* Operand 0 preprocessing */ /* For all other types, get the "object type" string */ /* Operand 1 preprocessing */ /* For all other types, get the "object type" string */ /*
     * Convert the second operand if necessary. The first operand (0)
     * determines the type of the second operand (1) (See the Data Types
     * section of the ACPI specification). Both object types are
     * guaranteed to be either Integer/String/Buffer by the operand
     * resolution mechanism.
     */ /* Other types have already been converted to string */ /* Take care with any newly created operand objects */ /*
     * Both operands are now known to be the same object type
     * (Both are Integer, String, or Buffer), and we can now perform
     * the concatenation.
     *
     * There are three cases to handle, as per the ACPI spec:
     *
     * 1) Two Integers concatenated to produce a new Buffer
     * 2) Two Strings concatenated to produce a new String
     * 3) Two Buffers concatenated to produce a new Buffer
     */ /* Result of two Integers is a Buffer */ /* Need enough buffer space for two integers */ /* Copy the first integer, LSB first */ /* Copy the second integer (LSB first) after the first */ /* Result of two Strings is a String */ /* Concatenate the strings */ /* Result of two Buffers is a Buffer */ /* Concatenate the buffers */ /* Invalid object type, should not happen here */