Previous: Side Effects Operators, Up: Infix Binary Operators


2.9.1 String Attribution Operator Example

For all its usefulness, the libx1f4i0 infix binary operators set does not provide the string attribution operator. That is due to the operator requirements: it needs to allocate memory to make a copy of its right side operand and just as well, it needs to free the memory reserved by its left side operand (just before setting it to the copy of the right side). And it needs to allocate and free memory with respect to the application memory management policies. In turn, the memory operations are due to the immediate character of the intrinsic string type: data of this type is exactly what it appears to be and no fancy management mechanism is tracking it.

See C Infix Binary Operators Set.

The intrinsic string attribution operator is to be defined much like any infix operator, with the necessary amendments.

See Infix Operator Definition Example.

See struct x1f4_operator_type.

The definition of operator:

const struct x1f4_operator_type tset = {
    "=",
    text_set,
    0400,
    X1f4_E4_TEXT,
    text2,
    X1f4_E4_LEFT_XSET,
    1,
    NULL,
    NULL
};

The priority field specifies the operator evaluation priority - it is here set to match the priority of attribution operators in the libx1f4i0 infix binary operators set.

The args field specifies the types of the operator arguments and is assumed defined as:

int text2[] = { X1f4_E4_TEXT, X1f4_E4_TEXT };

The flags field specifies this operator sets its left operand and thus is set as X1f4_E4_LEFT_XSET. Without this bit in flags definition the attribution will fail.

See Side Effects Operators.

The routine performing the operator logic may be something like:

static int
text_set(void *context, void *output, void **input)
{
    char *text_0, *text_1;
    int status;

    text_0 = *(X1f4_E4_TEXT *) input[0];
    text_1 = *(X1f4_E4_TEXT *) input[1];

Some code around libx1f4i0 library uses a special definition for empty string: x1f4_c1_empty_string - a constant empty string.

See x1f4_c1_empty_string.

If the right side operand has this value there is no need to allocate a new string, just set the left side operand to this value. Set output as well.

    if (text_1 == x1f4_c1_empty_string) {
	char **out;

	out = output;
	*out = text_1;

	out = input[0];
	*out = text_1;

	if (text_0 != x1f4_c1_empty_string) {
	    free left side operand and set the operation status accordingly

	    status = ...;
	} else {
	    status = 0;
	}
    } else {

Otherwise, make a copy of right side operand, free left side operand, set left side operand and output to the made copy.

	unsigned length;
	void *string;

	length = strlen(text_1) + 1;

	allocate at least _length_ bytes for the copy, set operation status to
	indicate how it all went

	if (status) {
	} else {
	    char **out;

	    memcpy(string, text_1, length);

	    out = output;
	    *out = string;

	    out = input[0];
	    *out = string;

	    if (text_0 != x1f4_c1_empty_string) {
		free left side operand and set the operation status accordingly

		status = ...;
	    }
	}

Copy made (or at least the failure is so indicated).

    }

Indicate to the surrounding code how it all went, 0 for success, non zero for failure.

    return status;
}

If memory is to be allocated and free via malloc and free the routine may be written as:

static int
text_set(void *context, void *output, void **input)
{
    char *text_0, *text_1;
    int status;

    text_0 = *(X1f4_E4_TEXT *) input[0];
    text_1 = *(X1f4_E4_TEXT *) input[1];

    if (text_1 == x1f4_c1_empty_string) {
	char **out;

	out = output;
	*out = text_1;

	out = input[0];
	*out = text_1;

	status = 0;

	if (text_0 != x1f4_c1_empty_string) {
	    free(text_0);
	}
    } else {
	unsigned length;
	void *string;

	length = strlen(text_1) + 1;

	string = malloc(length);
	if (!string) {
	    status = -1;
	} else {
	    char **out;

	    memcpy(string, text_1, length);

	    out = output;
	    *out = string;

	    out = input[0];
	    *out = string;

	    status = 0;

	    if (text_0 != x1f4_c1_empty_string) {
		free(text_0);
	    }
	}
    }

    return status;
}