473,397 Members | 1,961 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,397 software developers and data experts.

C data container similar to Perl style key-value array?

I am converting a Perl script over to "C" for a potential open source
project. I need some open source "C" code that will give me the same
functionality of a Perl Style associative array:

someArray["a_key_label"] = 6;

I know I can't get the same syntactic sugar as Perl offers, with the usage
of a string as the array key surrounded by square brackets. I just want the
general functionality, that's all. That is, a data container that will
maintain an internal list of key value pairs, with the ability to walk the
keys in sorted order. Also, the container should "auto-insert" a key-value
pair if it doesn't already exist in the container, when a particular key
value pair is referenced.

Do any of you know of any open source "C" code that provides a container
with the same behavior as Perl style arrays? URL's if you got 'em please.

Thanks.
Nov 14 '05 #1
5 3202
"Robert Oschler" <no************@nospam.com> writes:
I am converting a Perl script over to "C" for a potential open source
project. I need some open source "C" code that will give me the same
functionality of a Perl Style associative array:

someArray["a_key_label"] = 6;


I think that's the syntax Awk uses; Perl uses
$someArray{"a_key_label"} = 6;
(and refers to the data structure as a "hash", not as an "associative
array").

In a Perl hash, the key is a string, and the value can be any
arbitrary scalar value (string, number, reference, undef). You're not
going to get the same functionality in C without substantial syntactic
overhead. The closest C equivalent to a Perl scalar would be a
structure consisting of an enumeration value indicating a type, and a
union of all the types that can be stored in it. The job is simpler
if you can limit the stored values to one type (int, char*, etc.).

Perl, unlike C, also takes care of storage management for you. For
example, if you do:
$foo{"bar"} = "some string value";
$foo{"bar"} = "Some Other String Value";
the second assignment will cause the memory allocated for "some string
value" to be deallocated. In C, you'll have to take care of this
yourself (though a well-designed interface can make it easier).

<OT>
I think some of container classes in the C++ standard library do some
of what you're looking for. You might consider writing a C wrapper
for one of them -- or just implementing the project in C++. If you go
that route, of course, this isn't the place to ask about it.
</OT>

Sorry I don't have a good answer for you, but perhaps I've helped nail
down the question a bit.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #2
In article <BI********************@adelphia.com>,
Robert Oschler <no************@nospam.com> wrote:
I am converting a Perl script over to "C" for a potential open source
project. I know I can't get the same syntactic sugar as Perl offers, with the usage
of a string as the array key surrounded by square brackets. I just want the
general functionality, that's all. That is, a data container that will
maintain an internal list of key value pairs, with the ability to walk the
keys in sorted order.


There is no built-in ability in perl to walk the keys in sorted
order. If you walk the keys, you will get them in hash order,
and the perl implementers guarantee that the order *will* change
from time to time with different versions of perl. If I recall
correctly, newer versions of perl will use a -different- order
each time unless you use some perl magic.

In order to walk the elements in key-sorted order in perl, you have
to extract the keys, sort the resulting list according to
your sort criteria, and then iterate through the resulting
list
--
Usenet is like a slice of lemon, wrapped around a large gold brick.
Nov 14 '05 #3
ro******@ibd.nrc-cnrc.gc.ca (Walter Roberson) writes:
In article <BI********************@adelphia.com>,
Robert Oschler <no************@nospam.com> wrote:
I am converting a Perl script over to "C" for a potential open source
project.

I know I can't get the same syntactic sugar as Perl offers, with the usage
of a string as the array key surrounded by square brackets. I just want the
general functionality, that's all. That is, a data container that will
maintain an internal list of key value pairs, with the ability to walk the
keys in sorted order.


There is no built-in ability in perl to walk the keys in sorted
order. If you walk the keys, you will get them in hash order,
and the perl implementers guarantee that the order *will* change
from time to time with different versions of perl. If I recall
correctly, newer versions of perl will use a -different- order
each time unless you use some perl magic.

In order to walk the elements in key-sorted order in perl, you have
to extract the keys, sort the resulting list according to
your sort criteria, and then iterate through the resulting
list


Which, as it turns out, is very easy to do, since "sort" is a built-in
operator:

foreach my $key (sort keys %hash) {
print "$key => $hash{$key}\n";
}

Or, if that's too verbose for you:

map { print "$_ => $hash{$_}\n" } sort keys %hash;

A C version of this would almost certainly be more verbose, with more
explicit code to take care of things that Perl does behind the scenes.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #4
Robert Oschler wrote:
I am converting a Perl script over to "C" for a potential open source
project. I need some open source "C" code that will give me the same
functionality of a Perl Style associative array:

someArray["a_key_label"] = 6;

I know I can't get the same syntactic sugar as Perl offers, with the usage
of a string as the array key surrounded by square brackets. I just want the
general functionality, that's all. That is, a data container that will
maintain an internal list of key value pairs, with the ability to walk the
keys in sorted order. Also, the container should "auto-insert" a key-value
pair if it doesn't already exist in the container, when a particular key
value pair is referenced.

Do any of you know of any open source "C" code that provides a container
with the same behavior as Perl style arrays? URL's if you got 'em please.

Thanks.

You will have to do the sorting yourself, however I have attached my
implementation which I use in other projects that works great for this
type of thing (it's actually a configuration parser). Hope this helps.

Joe Estock

--BEGIN config.h:

/* $Id: config.h,v 1.3 2005/03/06 00:23:49 joe Exp $ */

#ifndef _CONFIG_H
#define _CONFIG_H

struct config_settings
{
char **key;
char **value;
};

int config_set(struct config_settings *, char *, char *);
int config_set_ex(struct config_settings *, int, char *);
char *config_get(struct config_settings *, char *);
char *config_get_ex(struct config_settings *, int);
void rehash_config(struct config_settings *, char *);
int save_config(struct config_settings *, char *);
void deinit_config(struct config_settings *);
void trim(char *);
int init_config(struct config_settings *, char *);

#endif /* !defined(_CONFIG_H) */

--END config.h

--BEGIN config.c

/* $Id: config.c,v 1.6 2005/03/12 07:59:40 joe Exp $ */

/**
* This is a general configuration parser. Nothing fancy
* is done here and nothing specific to the main configuration
* file is handled here. This file contains the building blocks
* for handling the configuration files by parsing the file and
* splitting up the various configuration settings and their
* values.
*/

#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "config.h"
#include "stdbool.h"

/**
* Sets the specified key with the specified value. If an
* error is encountered, -1 is returned otherwise the index
* of the newly inserted key is returned.
*
* @param config Pointer to a previously malloced config_settings
* @param key Key to change or set
* @param value value for key
* @return -1 on failure, index of item otherwise
*/
int config_set(struct config_settings *config, char *key, char *value)
{
unsigned int i;

if(key == NULL || config == NULL || config->key == NULL)
{
return(-1);
}

for(i = 0; config->key[i] != NULL; i++)
{
if(!strcasecmp(config->key[i], key))
{
return(config_set_ex(config, i, value));
}
}

return(-1);
}

/**
* Sets the specified key with the specified value. If an
* error is encountered, -1 is returned otherwise the index
* of the newly inserted key is returned.
*
* @see config_set()
* @param config Pointer to a previously malloced config_settings
* @param index index of key to change or set
* @param value value for key
* @return -1 on failure, index of item otherwise
*/
int config_set_ex(struct config_settings *config, int index, char *value)
{
char *tmp;

if((tmp = malloc(strlen(value) + 1)) == NULL)
{
perror("malloc");
return(-1);
}
memset(tmp, '\0', strlen(value) + 1);
strcpy(tmp, value);

free(config->value[index]);
config->value[index] = tmp;

return(index);
}

/**
* Returns the value associated with key
*
* @param config Pointer to a previously malloced config_settings
* @param key Key to retreive value for
* @return Value of key or NULL if nonexistant or empty
*/
char *config_get(struct config_settings *config, char *key)
{
unsigned int i;

if(key == NULL || config == NULL || config->key == NULL)
{
return(NULL);
}

for(i = 0; config->key[i] != NULL; i++)
{
if(!strcasecmp(config->key[i], key))
{
return(config->value[i]);
}
}

return(NULL);
}

/**
* Returns the value associated with key
*
* @see config_get()
* @param config Pointer to a previously malloced config_settings
* @param index Index of key to retreive value for
* @return Value of key or NULL if nonexistant or empty
*/
char *config_get_ex(struct config_settings *config, int index)
{
return(config->value[index]);
}

/**
* Reloads the configuration file
*
* @see save_config()
* @param config Pointer to a previously malloced config_settings
* @param filename Filename to read configuration data from
*/
void rehash_config(struct config_settings *config, char *filename)
{
deinit_config(config);
init_config(config, filename);
}

/**
* Saves the new configuration parameters to specified file
*
* @see rehash_config()
* @param config Pointer to a previously malloced config_settings
* @param filename Filename to store keys and values in
* @return true on success, false on failure
*/
bool save_config(struct config_settings *config, char *filename)
{
FILE *fp;
unsigned int i;

if(config == NULL || config->key == NULL || filename == NULL)
{
return(false);
}

if((fp = fopen(filename, "w")) == NULL)
{
return(false);
}

fprintf(fp, "# %s - %s\n",
filename,
"Automatically generated by geekbot via save_config");
for(i = 0; config->key[i] != NULL; i++)
{
fprintf(fp, "%s = \"%s\"\n", config->key[i], config->value[i] == NULL
? "" : config->value[i]);
}

fclose(fp);
return(true);
}

/**
* Free up any resources used for specified configuration
*
* @see init_config()
* @param config Pointer to a previously malloced config_settings
*/
void deinit_config(struct config_settings *config)
{
unsigned int i;

if(config == NULL || (config->key == NULL && config->value == NULL))
{
return;
}

for(i = 0; config->key[i] != NULL; i++)
{
if(config->key[i] != NULL) { free(config->key[i]); }
if(config->value[i] != NULL) { free(config->value[i]); }
}

free(config->key);
free(config->value);
}

/**
* Removes leading and trailing spaces as well as any
* newlines from the end of a string
*
* @param s string to trim
*/
void trim(char *s)
{
unsigned int len = strlen(s);
unsigned int i = 0;

if(len == 0)
{
return;
}

for(i = 0; i < len && isspace(s[i]); i++) ; /* nothing */
if(i > 0)
{
memmove(s, &s[i], strlen(&s[i]) + 1);
}

if((len = strlen(s)) == 0)
{
return;
}

i = len;
while(s[i - 1] == '\r' || s[i - 1] == '\n' || isspace(s[i - 1]))
{
s[i - 1] = '\0';
i--;
}

/*while(s[strlen(s) - 1] == '\r' || s[strlen(s) - 1] == '\n' ||
isspace(s[strlen(s) - 1]))
{
s[strlen(s) - 1] = '\0';
}*/
}

/**
* Initializes the configuration found in specified filename
*
* @param config Pointer to a previously malloced config_settings
* @param filename Filename to read keys and values from
* @return true on success, false on failure
*/
int init_config(struct config_settings *config, char *filename)
{
FILE *fp;
char buf[2048];
char *tokenptr;
unsigned int i;
char **test;

if(config == NULL)
return(false);

if(!(fp = fopen(filename, "r")))
{
return(false);
}

config->key = malloc(sizeof(char *) * 1);
config->value = malloc(sizeof(char *) * 1);
config->key[0] = NULL;
config->value[0] = NULL;

memset(buf, '\0', 2048);

i = 0;
while(!feof(fp))
{
memset(buf, '\0', 2048);
if(fgets(buf, 2048, fp) == NULL)
break;

trim(buf);

if(buf == NULL || strlen(buf) == 0 || buf[0] == '#')
continue;

tokenptr = strtok(buf, "=");

if(tokenptr != NULL)
{
trim(tokenptr);
if((config->key[i] = malloc(strlen(tokenptr) + 1)) == NULL)
return(false);
memset(config->key[i], '\0', strlen(tokenptr) + 1);
strcpy(config->key[i], tokenptr);

tokenptr = strtok(NULL, "=");

if(tokenptr != NULL)
{
trim(tokenptr);

if(tokenptr[0] == '"')
memmove(tokenptr, &tokenptr[1], strlen(&tokenptr[1]) + 1);

if(tokenptr[strlen(tokenptr) - 1] == '"')
tokenptr[strlen(tokenptr) - 1] = '\0';

if(strlen(tokenptr) == 0)
{
config->value[i] = NULL;
}
else
{
if((config->value[i] = malloc(strlen(tokenptr) + 1)) == NULL)
return(false);
memset(config->value[i], '\0', strlen(tokenptr) + 1);
strcpy(config->value[i], tokenptr);
}
}
else
{
config->value[i] = malloc(2);
strcpy(config->value[i], "\0");
}

i++;
if((test = realloc(config->key, sizeof(char *) * (i + 1))) == NULL)
return(false);

config->key = test;
config->key[i] = NULL;

if((test = realloc(config->value, sizeof(char *) * (i + 1))) == NULL)
return(false);

config->value = test;
config->value[i] = NULL;
}
}

fclose(fp);

return(true);
}

--END config.c
Nov 14 '05 #5
Robert Oschler wrote:
I am converting a Perl script over to "C" for a potential open source
project. I need some open source "C" code that will give me the same
functionality of a Perl Style associative array:


As others mentioned, you have to do the sorting yourself, but you might
look at the glib library (part of gtk+, but not dependent on having X
running). It has a number of utility functions for C, that makes C a
lot easier to use.

Jon
----
Learn to program using Linux assembly language
http://www.cafeshops.com/bartlettpublish.8640017
Nov 14 '05 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Ney André de Mello Zunino | last post by:
Hello. The issue is quite known: you have a block-level container holding a set of floated elements and you need that the container's content height take the floated elements' dimensions into...
3
by: Colin Young | last post by:
I'm having a bit of a problem with my DataList when I try to update from the user's input. I've included relevant excerpts at the end of this message. In the UpdateCommand code, the...
0
by: Alex | last post by:
Interested in more .NET stuff visit www.dedicatedsolutions.co.uk The DataList is not as powerful as the DataGrid. It requires more work from you since it has no default data presentation format....
2
by: John Holmes | last post by:
I am using radioButton controls in a data repeater and would like to incorporate the 'key' field into the 'id' attribute of the radioButton controls and name them something like: 'rad' + '<%#...
5
by: tshad | last post by:
Is there a way to carry data that I have already read from the datagrid from page to page? I am looking at my Datagrid that I page through and when the user says get the next page, I have to go...
16
by: Sensei | last post by:
Hi! I'm looking for something similar to the map container, but with a slight modification, a unique key, with multiple assignments to each one. I think some container in the STL has it, but I...
3
by: David Golightly | last post by:
I'm taking a stab at making CSS sparklines - see http://www.edwardtufte.com/bboard/q-and-a-fetch-msg?msg_id=0001OR&topic_id=1&topic= <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC...
1
by: Stephen Barrett | last post by:
I have an application that was originally built with ASP.Net 1.1. We finally got permission to migrate to 2.0. Due to time constraints we migrated the web projects to 2.0 web application...
3
by: jacob navia | last post by:
Abstract: Continuing the discussion about abstract data types, in this discussion group, a string collection data type is presented, patterned after the collection in C# and similar languages...
162
by: Sh4wn | last post by:
Hi, first, python is one of my fav languages, and i'll definitely keep developing with it. But, there's 1 one thing what I -really- miss: data hiding. I know member vars are private when you...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.