Example #1
0
void videoipc_exit(OhmPlugin *plugin)
{
    (void)plugin;

    exit_shmem();
    exit_message();
}
Example #2
0
void *param_void(const struct variable *value, uint32_t index)
{
    struct variable *v = param_var(value, index);
    if (NULL == v)
        return NULL;
    switch (v->type) {
        case VAR_NIL:   return NULL;
        case VAR_VOID:  return v->ptr;
        default:
            return exit_message("expected void or nil");
    }
}
/*------------------------------------------------------------------------------------------------------------------
-- FUNCTION: main
--
-- DATE: March 10, 2014
--
-- REVISIONS:
--
-- DESIGNER: Robin Hsieh
--
-- PROGRAMMER: Robin Hsieh
--
-- INTERFACE: int main (int argc , char *argv[])
--              int argc:       The number of the arguments put in from the command line.
--              char *argv[]:   The array of char* of the arguments
--
-- RETURNS: int
--              Returns an int when program terminates.
--
-- NOTES:
-- This function is to start the server program to be able to allow clients to connect, and act as a echo server
-- that will send message from 1 client, to the rest of other clients connected. This program can also star the
-- client program that will be able to connect to a server, and send messages to that server.
--
------------------------------------------------------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
    char username[128];
    char ip[128];
    int port;

    if(argc == 3)
    {
        if(strcmp(argv[1], "server") == 0)
        {
            port = atoi(argv[2]);
            startServer(port);
        }
        else
        {
            exit_message();
        }
    }
    else if(argc == 5)
    {
        if(strcmp(argv[1], "client") == 0)
        {
            strcpy(username, argv[2]);
            strcpy(ip, argv[3]);
            port = atoi(argv[4]);

            startClient(username, ip, port);
        }
        else
        {
            exit_message();
        }
    }
    else
    {
        exit_message();
    }

    return 0;
}
Example #4
0
char *param_str(const struct variable *value, uint32_t index)
{
    if (index >= value->list.ordered->length)
        return NULL;
    const struct variable *strv = (struct variable*)array_get(value->list.ordered, index);
    char *str = NULL;
    switch (strv->type) {
        case VAR_NIL:                                           break;
        case VAR_STR: str = byte_array_to_string(strv->str);    break;
        default:      exit_message("wrong param type");         break;
    }
    return str;
}
Example #5
0
int32_t param_int(const struct variable *value, uint32_t index)
{
    struct variable *result = param_var(value, index);
    if (NULL == result)
        return 0;
    switch (result->type)
    {
        case VAR_INT: return result->integer;
        case VAR_FLT: return (int32_t)result->floater;
        case VAR_NIL: return 0;
        default:
            exit_message("not an int");
            return 0;
    }
}
Example #6
0
//    a                b        c
// <sought> <replacement> [<start>]
// <start> <length> <replacement>
static inline struct variable *cfnc_replace(struct context *context)
{
    struct variable *args = (struct variable*)stack_pop(context->operand_stack);
    struct variable *self = (struct variable*)array_get(args->list.ordered, 0);
    struct variable *a = (struct variable*)array_get(args->list.ordered, 1);
    struct variable *b = (struct variable*)array_get(args->list.ordered, 2);
    struct variable *c = args->list.ordered->length > 3 ?
        (struct variable*)array_get(args->list.ordered, 3) : NULL;

    null_check(self);
    null_check(b);
    assert_message(self->type == VAR_STR, "searching in a non-string");

    struct byte_array *replaced = NULL;

    if (a->type == VAR_STR) { // find a, replace with b

        assert_message(b->type == VAR_STR, "non-string replacement");
        int32_t where = 0;

        if (c) { // replace first match after index c

            assert_message(c->type == VAR_INT, "non-integer index");
            if (((where = byte_array_find(self->str, a->str, c->integer)) >= 0))
                replaced = byte_array_replace(self->str, b->str, where, b->str->length);

        } else {

            replaced = byte_array_replace_all(self->str, a->str, b->str);
        }

    } else if (a->type == VAR_INT ) { // replace at index a, length b, insert c

        assert_message(a || a->type == VAR_INT, "non-integer count");
        assert_message(b || b->type == VAR_INT, "non-integer start");
        replaced = byte_array_replace(self->str, c->str, a->integer, b->integer);

    } else exit_message("replacement is not a string");

    null_check(replaced);
    struct variable *result = variable_new_str(context, replaced);
    byte_array_del(replaced);

    return result;
}
Example #7
0
void
check_display (HINSTANCE hInstance)
{
    HDC hDCGlobal = GetDC (NULL);
    INT iRasterCaps;

    iRasterCaps = GetDeviceCaps (hDCGlobal, RASTERCAPS);
    if (iRasterCaps & RC_PALETTE) {
	exit_message ("Error: display has palette");
    }

    globals.color_depth = GetDeviceCaps (hDCGlobal, BITSPIXEL);
    ReleaseDC (NULL, hDCGlobal);
  
    globals.screen_w = GetSystemMetrics (SM_CXSCREEN);
    globals.screen_h = GetSystemMetrics (SM_CYSCREEN);
    globals.fullscreen_client_w = (INT) GetSystemMetrics (SM_CXFULLSCREEN);
    globals.fullscreen_client_h = (INT) GetSystemMetrics (SM_CYFULLSCREEN);
}
Example #8
0
static inline struct variable *cfnc_insert(struct context *context) // todo: test
{
    struct variable *args = (struct variable*)stack_pop(context->operand_stack);
    struct variable *self = (struct variable*)array_get(args->list.ordered, 0);
    struct variable *insertion = (struct variable*)array_get(args->list.ordered, 1);
    struct variable *start = args->list.ordered->length > 2 ?
        (struct variable*)array_get(args->list.ordered, 2) : NULL;
    null_check(self);
    null_check(insertion);
    assert_message(!start || start->type == VAR_INT, "non-integer index");

    int32_t position = 0;
    switch (self->type) {
        case VAR_LST: {
            struct array *list = array_new_size(1);
            array_set(list, 0, insertion);
            insertion = variable_new_list(context, list);
            position = self->list.ordered->length;
            array_del(list);
        } break;
        case VAR_STR:
            assert_message(insertion->type == VAR_STR, "insertion doesn't match destination");
            position = self->str->length;
            break;
        default:
            exit_message("bad insertion destination");
            break;
    }

    struct variable *first = variable_part(context, variable_copy(context, self), 0, position);
    struct variable *second = variable_part(context, variable_copy(context, self), position, -1);
    struct variable *joined = variable_concatenate(context, 3, first, insertion, second);
    
    if (self->type == VAR_LST) {
        array_del(self->list.ordered);
        self->list.ordered = array_copy(joined->list.ordered);
    } else {
        byte_array_del(self->str);
        self->str = byte_array_copy(joined->str);
    } return joined;
}
Example #9
0
static int32_t default_hashor(const void *x, void *context) {
    const struct variable *key = (const struct variable*)x;
    switch (key->type) {
        case VAR_INT:
            return key->integer;
        case VAR_FNC:
        case VAR_BYT:
        case VAR_STR: {
            const struct byte_array *name = key->str;
            int32_t hash = 0;
            int i = 0;
            for (i = 0; i<name->length; i++)
                hash += name->data[i];
            return hash;
        }
        case VAR_NIL:
            return 0;
            break;
        default:
            exit_message("not handled hash type");
            return 1;
    }
}
Example #10
0
int main(int argc, char **argv)
{
	// Capture settings
	int snapshot_delay = 2000;
	int show_preview_window = 0;
	int list_devices = 0;
	int device_number = 1;
	char device_name[100];
	char filename[100];
	
	// Other variables
	char char_buffer[100];

	// Default device name and output filename
	strcpy(device_name, "");
	strcpy(filename, "image.bmp");
	
	// Information message
	fprintf(stderr, "\n");
	fprintf(stderr, "CommandCam  Copyright (C) 2012  Ted Burke\n");
    fprintf(stderr, "This program comes with ABSOLUTELY NO WARRANTY;\n");
    fprintf(stderr, "This is free software, and you are welcome to\n");
    fprintf(stderr, "redistribute it under certain conditions;\n");
	fprintf(stderr, "See the GNU General Public License v3,\n");
	fprintf(stderr, "<http://www.gnu.org/licenses/gpl.txt>\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "http://batchloaf.wordpress.com\n");
	fprintf(stderr, "This version 21-4-2012\n");
	fprintf(stderr, "\n");
	
	// Parse command line arguments. Available options:
	//
	//		/delay DELAY_IN_MILLISECONDS
	//		/filename OUTPUT_FILENAME
	//		/devnum DEVICE_NUMBER
	//		/devname DEVICE_NAME
	//		/preview
	//		/devlist
	//
	int n = 1;
	while (n < argc)
	{
		// Process next command line argument
		if (strcmp(argv[n], "/preview") == 0)
		{
			// Enable preview window
			show_preview_window = 1;
		}
		else if (strcmp(argv[n], "/devlist") == 0)
		{
			// Set flag to list devices rather than capture image
			list_devices = 1;
		}
		else if (strcmp(argv[n], "/filename") == 0)
		{
			// Set output filename to specified string
			if (++n < argc) //strcpy(filename, argv[n]);
			{
				// Copy provided string into char buffer
				strcpy(char_buffer, argv[n]);
				
				// Trim inverted commas if present and copy
				// provided string into filename char array
				if (char_buffer[0] == '"')
				{
					strncat(filename, char_buffer, strlen(char_buffer)-2);
				}
				else
				{
					strcpy(filename, char_buffer);
				}
			}
			else exit_message("Error: no filename specified", 1);
		}
		else if (strcmp(argv[n], "/delay") == 0)
		{
			// Set snapshot delay to specified value
			if (++n < argc) snapshot_delay = atoi(argv[n]);
			else exit_message("Error: invalid delay specified", 1);
			
			if (snapshot_delay <= 0)
				exit_message("Error: invalid delay specified", 1);
		}
		else if (strcmp(argv[n], "/devnum") == 0)
		{
			// Set device number to specified value
			if (++n < argc) device_number = atoi(argv[n]);
			else exit_message("Error: invalid device number", 1);
			
			if (device_number <= 0)
				exit_message("Error: invalid device number", 1);
		}
		else if (strcmp(argv[n], "/devname") == 0)
		{
			// Set device number to specified value
			if (++n < argc)
			{
				// Copy device name into char buffer
				strcpy(char_buffer, argv[n]);
				
				// Trim inverted commas if present and copy
				// provided string into device_name
				if (char_buffer[0] == '"')
				{
					strncat(device_name, char_buffer, strlen(char_buffer)-2);
				}
				else
				{
					strcpy(device_name, char_buffer);
				}
				
				// Remember to choose by name rather than number
				device_number = 0;
			}
			else exit_message("Error: invalid device name", 1);
		}
		else
		{
			// Unknown command line argument
			fprintf(stderr, "Unrecognised option: %s\n", argv[n]);
			exit_message("", 1);			
		}
		
		// Increment command line argument counter
		n++;
	}
	
	// Intialise COM
	hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
	if (hr != S_OK)
		exit_message("Could not initialise COM", 1);

	// Create filter graph
	hr = CoCreateInstance(CLSID_FilterGraph, NULL,
			CLSCTX_INPROC_SERVER, IID_IGraphBuilder,
			(void**)&pGraph);
	if (hr != S_OK)
		exit_message("Could not create filter graph", 1);
	
	// Create capture graph builder.
	hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL,
			CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2,
			(void **)&pBuilder);
	if (hr != S_OK)
		exit_message("Could not create capture graph builder", 1);

	// Attach capture graph builder to graph
	hr = pBuilder->SetFiltergraph(pGraph);
	if (hr != S_OK)
		exit_message("Could not attach capture graph builder to graph", 1);

	// Create system device enumerator
	hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
			CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));
	if (hr != S_OK)
		exit_message("Could not crerate system device enumerator", 1);

	// Video input device enumerator
	hr = pDevEnum->CreateClassEnumerator(
					CLSID_VideoInputDeviceCategory, &pEnum, 0);
	if (hr != S_OK)
		exit_message("No video devices found", 1);
	
	// If the user has included the "/list" command line
	// argument, just list available devices, then exit.
	if (list_devices != 0)
	{
		fprintf(stderr, "Available capture devices:\n");
		n = 0;
		while(1)
		{
			// Find next device
			hr = pEnum->Next(1, &pMoniker, NULL);
			if (hr == S_OK)
			{
				// Increment device counter
				n++;
				
				// Get device name
				hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
				VARIANT var;
				VariantInit(&var);
				hr = pPropBag->Read(L"FriendlyName", &var, 0);
				fprintf(stderr, "  %d. %ls\n", n, var.bstrVal);
				VariantClear(&var);
			}
			else
			{
				// Finished listing device, so exit program
				if (n == 0) exit_message("No devices found", 0);
				else exit_message("", 0);
			}
		}
	}
	
	// Get moniker for specified video input device,
	// or for the first device if no device number
	// was specified.
	VARIANT var;
	n = 0;
	while(1)
	{
		// Access next device
		hr = pEnum->Next(1, &pMoniker, NULL);
		if (hr == S_OK)
		{
			n++; // increment device count
		}
		else
		{
			if (device_number == 0)
			{
				fprintf(stderr,
					"Video capture device %s not found\n",
					device_name);
			}
			else
			{
				fprintf(stderr,
					"Video capture device %d not found\n",
					device_number);
			}
			exit_message("", 1);
		}
		
		// If device was specified by name rather than number...
		if (device_number == 0)
		{
			// Get video input device name
			hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
			if (hr == S_OK)
			{
				// Get current device name
				VariantInit(&var);
				hr = pPropBag->Read(L"FriendlyName", &var, 0);
				
				// Convert to a normal C string, i.e. char*
				sprintf(char_buffer, "%ls", var.bstrVal);
				VariantClear(&var);
				pPropBag->Release();
				pPropBag = NULL;
				
				// Exit loop if current device name matched devname
				if (strcmp(device_name, char_buffer) == 0) break;
			}
			else
			{
				exit_message("Error getting device names", 1);
			}
		}
		else if (n >= device_number) break;
	}
	
	// Get video input device name
	hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
	VariantInit(&var);
	hr = pPropBag->Read(L"FriendlyName", &var, 0);
	fprintf(stderr, "Capture device: %ls\n", var.bstrVal);
	VariantClear(&var);
	
	// Create capture filter and add to graph
	hr = pMoniker->BindToObject(0, 0,
					IID_IBaseFilter, (void**)&pCap);
	if (hr != S_OK) exit_message("Could not create capture filter", 1);
		
	// Add capture filter to graph
	hr = pGraph->AddFilter(pCap, L"Capture Filter");
	if (hr != S_OK) exit_message("Could not add capture filter to graph", 1);

	// Create sample grabber filter
	hr = CoCreateInstance(CLSID_SampleGrabber, NULL,
		CLSCTX_INPROC_SERVER, IID_IBaseFilter,
		(void**)&pSampleGrabberFilter);
	if (hr != S_OK)
		exit_message("Could not create Sample Grabber filter", 1);
	
	// Query the ISampleGrabber interface of the sample grabber filter
	hr = pSampleGrabberFilter->QueryInterface(
			DexterLib::IID_ISampleGrabber, (void**)&pSampleGrabber);
	if (hr != S_OK)
		exit_message("Could not get ISampleGrabber interface to sample grabber filter", 1);
	
	// Enable sample buffering in the sample grabber filter
	hr = pSampleGrabber->SetBufferSamples(TRUE);
	if (hr != S_OK)
		exit_message("Could not enable sample buffering in the sample grabber", 1);

	// Set media type in sample grabber filter
	AM_MEDIA_TYPE mt;
	ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
	mt.majortype = MEDIATYPE_Video;
	mt.subtype = MEDIASUBTYPE_RGB24;
	hr = pSampleGrabber->SetMediaType((DexterLib::_AMMediaType *)&mt);
	if (hr != S_OK)
		exit_message("Could not set media type in sample grabber", 1);
	
	// Add sample grabber filter to filter graph
	hr = pGraph->AddFilter(pSampleGrabberFilter, L"SampleGrab");
	if (hr != S_OK)
		exit_message("Could not add Sample Grabber to filter graph", 1);

	// Create Null Renderer filter
	hr = CoCreateInstance(CLSID_NullRenderer, NULL,
		CLSCTX_INPROC_SERVER, IID_IBaseFilter,
		(void**)&pNullRenderer);
	if (hr != S_OK)
		exit_message("Could not create Null Renderer filter", 1);
	
	// Add Null Renderer filter to filter graph
	hr = pGraph->AddFilter(pNullRenderer, L"NullRender");
	if (hr != S_OK)
		exit_message("Could not add Null Renderer to filter graph", 1);
	
	// Connect up the filter graph's capture stream
	hr = pBuilder->RenderStream(
		&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,
		pCap,  pSampleGrabberFilter, pNullRenderer);
	if (hr != S_OK)
		exit_message("Could not render capture video stream", 1);
		
	// Connect up the filter graph's preview stream
	if (show_preview_window > 0)
	{
		hr = pBuilder->RenderStream(
				&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,
				pCap, NULL, NULL);
		if (hr != S_OK && hr != VFW_S_NOPREVIEWPIN)
			exit_message("Could not render preview video stream", 1);
	}

	// Get media control interfaces to graph builder object
	hr = pGraph->QueryInterface(IID_IMediaControl,
					(void**)&pMediaControl);
	if (hr != S_OK) exit_message("Could not get media control interface", 1);
	
	// Run graph
	while(1)
	{
		hr = pMediaControl->Run();
		
		// Hopefully, the return value was S_OK or S_FALSE
		if (hr == S_OK) break; // graph is now running
		if (hr == S_FALSE) continue; // graph still preparing to run
		
		// If the Run function returned something else,
		// there must be a problem
		fprintf(stderr, "Error: %u\n", hr);
		exit_message("Could not run filter graph", 1);
	}
	
	// Wait for specified time delay (if any)
	Sleep(snapshot_delay);
	
	// Grab a sample
	// First, find the required buffer size
	long buffer_size = 0;
	while(1)
	{
		// Passing in a NULL pointer signals that we're just checking
		// the required buffer size; not looking for actual data yet.
		hr = pSampleGrabber->GetCurrentBuffer(&buffer_size, NULL);
		
		// Keep trying until buffer_size is set to non-zero value.
		if (hr == S_OK && buffer_size != 0) break;
		
		// If the return value isn't S_OK or VFW_E_WRONG_STATE
		// then something has gone wrong. VFW_E_WRONG_STATE just
		// means that the filter graph is still starting up and
		// no data has arrived yet in the sample grabber filter.
		if (hr != S_OK && hr != VFW_E_WRONG_STATE)
			exit_message("Could not get buffer size", 1);
	}

	// Stop the graph
	pMediaControl->Stop();

	// Allocate buffer for image
	pBuffer = new char[buffer_size];
	if (!pBuffer)
		exit_message("Could not allocate data buffer for image", 1);
	
	// Retrieve image data from sample grabber buffer
	hr = pSampleGrabber->GetCurrentBuffer(
			&buffer_size, (long*)pBuffer);
	if (hr != S_OK)
		exit_message("Could not get buffer data from sample grabber", 1);

	// Get the media type from the sample grabber filter
	hr = pSampleGrabber->GetConnectedMediaType(
			(DexterLib::_AMMediaType *)&mt);
	if (hr != S_OK) exit_message("Could not get media type", 1);
	
	// Retrieve format information
	VIDEOINFOHEADER *pVih = NULL;
	if ((mt.formattype == FORMAT_VideoInfo) && 
		(mt.cbFormat >= sizeof(VIDEOINFOHEADER)) &&
		(mt.pbFormat != NULL)) 
	{
		// Get video info header structure from media type
		pVih = (VIDEOINFOHEADER*)mt.pbFormat;

		// Print the resolution of the captured image
		fprintf(stderr, "Capture resolution: %dx%d\n",
			pVih->bmiHeader.biWidth,
			pVih->bmiHeader.biHeight);
		
		// Create bitmap structure
		long cbBitmapInfoSize = mt.cbFormat - SIZE_PREHEADER;
		BITMAPFILEHEADER bfh;
		ZeroMemory(&bfh, sizeof(bfh));
		bfh.bfType = 'MB'; // Little-endian for "BM".
		bfh.bfSize = sizeof(bfh) + buffer_size + cbBitmapInfoSize;
		bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + cbBitmapInfoSize;
		
		// Open output file
		HANDLE hf = CreateFile(filename, GENERIC_WRITE,
					FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
		if (hf == INVALID_HANDLE_VALUE)
			exit_message("Error opening output file", 1);
		
		// Write the file header.
		DWORD dwWritten = 0;
		WriteFile(hf, &bfh, sizeof(bfh), &dwWritten, NULL);
		WriteFile(hf, HEADER(pVih),
					cbBitmapInfoSize, &dwWritten, NULL);
		
		// Write pixel data to file
		WriteFile(hf, pBuffer, buffer_size, &dwWritten, NULL);
		CloseHandle(hf);
	}
	else 
	{
		exit_message("Wrong media type", 1);
	}
	
	// Free the format block
	if (mt.cbFormat != 0)
	{
		CoTaskMemFree((PVOID)mt.pbFormat);
		mt.cbFormat = 0;
		mt.pbFormat = NULL;
	}
	if (mt.pUnk != NULL)
	{
		// pUnk should not be used.
		mt.pUnk->Release();
		mt.pUnk = NULL;
	}

	// Clean up and exit
	fprintf(stderr, "Captured image to %s", filename);
	exit_message("", 0);
}
Example #11
0
struct variable *builtin_method(struct context *context,
                                struct variable *indexable,
                                const struct variable *index)
{
    enum VarType it = indexable->type;
    char *idxstr = byte_array_to_string(index->str);
    struct variable *result = NULL;

    if (!strcmp(idxstr, FNC_LENGTH)) {
        int n;
        switch (indexable->type) {
            case VAR_LST: n = indexable->list.ordered->length;  break;
            case VAR_STR: n = indexable->str->length;           break;
            case VAR_NIL: n = 0;                                break;
            default:
                free(idxstr);
                exit_message("no length for non-indexable");
                return NULL;
        }
        result = variable_new_int(context, n);
    }
    else if (!strcmp(idxstr, FNC_TYPE)) {
        const char *typestr = var_type_str(it);
        result = variable_new_str_chars(context, typestr);
    }

    else if (!strcmp(idxstr, FNC_STRING)) {
        switch (indexable->type) {
            case VAR_STR:
            case VAR_BYT:
            case VAR_FNC:
                result = variable_copy(context, indexable);
                break;
            default: {
                struct byte_array *vv = variable_value(context, indexable);
                result = variable_new_str(context, vv);
                byte_array_del(vv);
                break;
            }
        }
    }

    else if (!strcmp(idxstr, FNC_LIST))
        result = variable_new_list(context, indexable->list.ordered);

    else if (!strcmp(idxstr, FNC_KEY)) {
        if (indexable->type == VAR_KVP)
            result = indexable->kvp.key;
        else
            result = variable_new_nil(context);
    }

    else if (!strcmp(idxstr, FNC_VAL)) {
        if (indexable->type == VAR_KVP)
            result = indexable->kvp.val;
        else
            result = variable_new_nil(context);
    }

    else if (!strcmp(idxstr, FNC_KEYS))
        result = variable_map_list(context, indexable, &map_keys);

    else if (!strcmp(idxstr, FNC_VALS))
        result = variable_map_list(context, indexable, &map_vals);

    else if (!strcmp(idxstr, FNC_PACK))
        result = variable_new_cfnc(context, &cfnc_pack);

    else if (!strcmp(idxstr, FNC_SERIALIZE))
        result = variable_new_cfnc(context, &cfnc_serialize);
    
    else if (!strcmp(idxstr, FNC_DESERIALIZE))
        result = variable_new_cfnc(context, &cfnc_deserialize);

    else if (!strcmp(idxstr, FNC_SORT)) {
        assert_message(indexable->type == VAR_LST, "sorting non-list");
        result = variable_new_cfnc(context, &cfnc_sort);
    }

    else if (!strcmp(idxstr, FNC_CHAR))
        result = variable_new_cfnc(context, &cfnc_char);

    else if (!strcmp(idxstr, FNC_HAS))
        result = variable_new_cfnc(context, &cfnc_has);

    else if (!strcmp(idxstr, FNC_FIND))
        result = variable_new_cfnc(context, &cfnc_find);

    else if (!strcmp(idxstr, FNC_PART))
        result = variable_new_cfnc(context, &cfnc_part);

    else if (!strcmp(idxstr, FNC_REMOVE))
        result = variable_new_cfnc(context, &cfnc_remove);

    else if (!strcmp(idxstr, FNC_INSERT))
        result = variable_new_cfnc(context, &cfnc_insert);

    else if (!strcmp(idxstr, FNC_REPLACE))
        result = variable_new_cfnc(context, &cfnc_replace);

    free(idxstr);
    return result;
}