Skip to content

Instantly share code, notes, and snippets.

@masterl
Created June 10, 2015 03:49
Show Gist options
  • Save masterl/b355c779af940cfda058 to your computer and use it in GitHub Desktop.
Save masterl/b355c779af940cfda058 to your computer and use it in GitHub Desktop.
Struct with generic fields defined on runtime
// The MIT License (MIT)
// Copyright (c) 2015 Leonardo de Oliveira Lourenço
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef enum
{
false = 0,
true
} Bool;
typedef enum
{
INT = 1,
UINT,
LONG,
ULONG,
FLOAT,
DOUBLE,
STRING
} FieldType;
typedef union
{
int i;
unsigned int ui;
long l;
unsigned long ul;
float f;
double d;
char *s;
} GenericField;
typedef struct
{
int size;
GenericField *fields;
FieldType *types;
char **names;
} GenericStruct;
void init_gen_struct( GenericStruct *element );
void destroy_gen_struct( GenericStruct *element );
Bool add_field( GenericStruct *element, char *field_name, GenericField value, FieldType type );
void add_fields( GenericStruct *element );
void clean_buffer( void );
char *get_number_format( FieldType type );
Bool read_number( FieldType type, void * );
Bool read_numeric_field( GenericField *field, FieldType field_type );
void read_string( char *str, int size );
void show_field( GenericStruct *element, int index );
void show_fields( GenericStruct *element );
int main( void )
{
GenericStruct example;
init_gen_struct( &example );
add_fields( &example );
show_fields( &example );
destroy_gen_struct( &example );
return 0;
}
void init_gen_struct( GenericStruct *element )
{
if( element )
{
element->size = 0;
element->fields = NULL;
element->types = NULL;
element->names = NULL;
}
}
void destroy_gen_struct( GenericStruct *element )
{
int i;
if( !element )
{
return;
}
if( element->fields )
{
free( element->fields );
element->fields = NULL;
}
if( element->types )
{
free( element->types );
element->types = NULL;
}
if( element->names )
{
for( i = 0; i < element->size; ++i )
{
if( element->names[i] )
{
free( element->names[i] );
}
}
free( element->names );
element->names = NULL;
}
element->size = 0;
}
Bool add_field( GenericStruct *element, char *field_name, GenericField value, FieldType type )
{
GenericStruct temp;
init_gen_struct( &temp );
if( !element )
{
return false;
}
temp.size = element->size + 1;
temp.fields = (GenericField *)realloc( element->fields, temp.size );
temp.types = (FieldType *)realloc( element->types, temp.size );
temp.names = (char **)realloc( element->names, temp.size );
if( ( !temp.fields ) || ( !temp.types ) || ( !temp.names ) )
{
printf( "\nCouldn't add new field. Memory allocation error\n" );
// Copying any fields that were successfully allocated so the memory can be freed later
if( temp.fields )
{
element->fields = temp.fields;
}
if( temp.types )
{
element->types = temp.types;
}
if( temp.names )
{
element->names = temp.names;
}
return false;
}
temp.names[element->size] = (char *)malloc( ( strlen( field_name ) + 1 ) * sizeof( char ) );
if( temp.names[element->size] == NULL )
{
printf( "\nCouldn't add new field name. Memory allocation error\n" );
return false;
}
strcpy( temp.names[element->size], field_name );
temp.types[element->size] = type;
if( type == STRING )
{
temp.fields[element->size].s = (char *)malloc( ( strlen( value.s ) + 1 ) * sizeof( char ) );
if( temp.fields[element->size].s == NULL )
{
printf( "\nError adding new string field. Memory allocation error\n" );
}
else
{
strcpy( temp.fields[element->size].s, value.s );
}
}
else
{
temp.fields[element->size] = value;
}
element->fields = temp.fields;
element->types = temp.types;
element->names = temp.names;
element->size = temp.size;
return true;
}
void add_fields( GenericStruct *element )
{
int option;
char field_name[61];
char str_field[512];
GenericField field;
FieldType field_type;
do
{
printf( "\n----- ADD FIELD -----\n" );
printf( "\nWhat's the new value type?"
"\n(An invalid choice will cancel the operation)"
"\n 1 - int"
"\n 2 - unsigned int"
"\n 3 - long"
"\n 4 - unsigned long"
"\n 5 - float"
"\n 6 - double"
"\n 7 - string"
"\n > " );
read_number( INT, &option );
if( ( option < INT ) || ( option > STRING ) )
{
printf( "%d\n", option );
printf( "\nCanceled...\n" );
return;
}
printf( "\nType in the field name (max size: 60) " );
read_string( field_name, 61 );
field_type = option;
if( field_type == STRING )
{
printf( "Type in the field value (string): " );
read_string( str_field, 512 );
if( str_field[0] == '\0' )
{
printf( "Field can't be blank\n" );
continue;
}
field.s = str_field;
}
else
{
printf( "Type in the field value (numeric): " );
read_numeric_field( &field, field_type );
}
add_field( element, field_name, field, field_type );
} while( true );
}
void clean_buffer( void )
{
while( getchar() != '\n' )
;
}
char *get_number_format( FieldType type )
{
int index = type - 1;
static char formats[6][4] = {"%d", "%u", "%ld", "%lu", "%f", "%d"};
if( ( index >= 0 ) && ( index < 6 ) )
{
return formats[index];
}
return NULL;
}
Bool read_number( FieldType type, void *ptr )
{
int fields_read;
Bool invalid_input = true;
char *format = get_number_format( type );
if( !format || !ptr )
{
return false;
}
do
{
printf( "\nReading with format = %s\n", format );
fields_read = scanf( format, ptr );
if( fields_read != 1 )
{
printf( "Please type in a valid integer number...\n" );
}
else
{
invalid_input = false;
}
clean_buffer();
} while( invalid_input );
return true;
}
Bool read_numeric_field( GenericField *field, FieldType field_type )
{
Bool result;
switch( field_type )
{
case INT:
result = read_number( field_type, &field->i );
break;
case UINT:
result = read_number( field_type, &field->ui );
break;
case LONG:
result = read_number( field_type, &field->l );
break;
case ULONG:
result = read_number( field_type, &field->ul );
break;
case FLOAT:
result = read_number( field_type, &field->f );
break;
case DOUBLE:
result = read_number( field_type, &field->d );
break;
default:
result = false;
}
return result;
}
void read_string( char *str, int size )
{
char format[20];
// -1 for \0
snprintf( format, 20, " %%%d[^\n]", size - 1 );
scanf( format, str );
clean_buffer();
}
void show_field( GenericStruct *element, int index )
{
if( ( !element ) || ( index < 0 ) || ( index >= element->size ) )
{
return;
}
printf( " Field name: %s\n", element->names[index] );
switch( element->types[index] )
{
case INT:
printf( "Field value: %d\n", element->fields[index].i );
break;
case UINT:
printf( "Field value: %u\n", element->fields[index].ui );
break;
case LONG:
printf( "Field value: %ld\n", element->fields[index].l );
break;
case ULONG:
printf( "Field value: %lu\n", element->fields[index].ul );
break;
case FLOAT:
printf( "Field value: %f\n", element->fields[index].f );
break;
case DOUBLE:
printf( "Field value: %lf\n", element->fields[index].d );
break;
case STRING:
printf( "Field value: %s\n", element->fields[index].s );
break;
}
}
void show_fields( GenericStruct *element )
{
int i;
if( !element )
{
return;
}
if( element->size == 0 )
{
printf( "\nStruct have no fields!\n" );
return;
}
for( i = 0; i < element->size; ++i )
{
show_field( element, i );
}
}
@masterl
Copy link
Author

masterl commented Jun 10, 2015

Naive implementation just for an example

@Pompeu
Copy link

Pompeu commented Jun 10, 2015

nice

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment