Diferencias entre las revisiones 7 y 8
Versión 7 con fecha 2007-12-11 01:25:36
Tamaño: 17693
Comentario:
Versión 8 con fecha 2007-12-11 03:00:20
Tamaño: 35890
Comentario:
Los textos eliminados se marcan así. Los textos añadidos se marcan así.
Línea 8: Línea 8:

Dentro de GLib está implementada una serie de tipos de datos facilita, si cabe, el tratamiento de los datos y además tiene la propiedad de mejorar la portabilidad de los programas. Los tipos que se usan en GLib no son muy diferentes de los utilizados en el estándar de C. Por lo cual no resultará complicado acostumbrarse a su utilización.
De momento, comenzaremos aprendiendo los tipos de GLib que corresponden con los del estándar de C.
Dentro de GLib está implementada una serie de tipos de datos facilita, si cabe, el tratamiento de los datos y además tiene la propiedad de mejorar la portabilidad de los programas. Los tipos que se usan en GLib no son muy diferentes de los utilizados en el estándar de C. Por lo cual no resultará complicado acostumbrarse a su utilización. De momento, comenzaremos aprendiendo los tipos de GLib que corresponden con los del estándar de C.
Línea 21: Línea 19:
Como se observa en la tabla, estos tipos no difieren en grán medida de los utilizados al programar con los tipos del estándar de C, aunque es altamente recomendable poner un poco de esfuerzo para acostumbrarse a estos tipos si se va a trabajar con la plataforma GNOME.
GLib también posee una serie de tipos que nos hacen más sencillo el tratamiento de datos. Algunos tienen su correspondencia en C, pero nos hacen más sencillo su uso; otros nos sirven para mantener el mismo tamaño de datos de una plataforma a otra y, finalmente, hay otros que no tienen correspondencia con el estándar de C, pero que nos resultarán bastante útiles.

Como se observa en la tabla, estos tipos no difieren en grán medida de los utilizados al programar con los tipos del estándar de C, aunque es altamente recomendable poner un poco de esfuerzo para acostumbrarse a estos tipos si se va a trabajar con la plataforma GNOME. GLib también posee una serie de tipos que nos hacen más sencillo el tratamiento de datos. Algunos tienen su correspondencia en C, pero nos hacen más sencillo su uso; otros nos sirven para mantener el mismo tamaño de datos de una plataforma a otra y, finalmente, hay otros que no tienen correspondencia con el estándar de C, pero que nos resultarán bastante útiles.
Línea 26: Línea 24:
||gpointer ||<|2> void *|| gpointer es un puntero sin tipo, que luce mejor que escribir void *. ||
||gconstpointer||gconstpointer es un puntero a una constante. Los datos a los que apuntan no deberían ser cambiados. Este tipo suele usarse en los prototipos de funciones para indicar que el valor al que apunta la función no debería ser cambiado en el interior de la función. ||
||guchar||unsigned char||<(|4>Como se puede observar, estos tipos son idénticos a los tipos de C que carecen de signo, pero con la ventaja de que son más visuales y fáciles de usar.||
||guint||unsigned int||
||gushort||unsigned short||
||gulong||unsigned long||
||gpointer ||<style="text-align: center;" |2> void * || gpointer es un puntero sin tipo, que luce mejor que escribir void *. ||
||gconstpointer ||gconstpointer es un puntero a una constante. Los datos a los que apuntan no deberían ser cambiados. Este tipo suele usarse en los prototipos de funciones para indicar que el valor al que apunta la función no debería ser cambiado en el interior de la función. ||
||guchar ||unsigned char ||<style="text-align: left;" |4>Como se puede observar, estos tipos son idénticos a los tipos de C que carecen de signo, pero con la ventaja de que son más visuales y fáciles de usar. ||
||guint ||unsigned int ||
||gushort ||unsigned short ||
||gulong ||unsigned long ||
Línea 34: Línea 33:
||<:>'''Tipo'''||<:>'''Rango de tamaño del dato.'''||
||gint8||<:>-128 a 127||
||guint8||<:>0 a 255||
||gint16||<:>-32.768 a 32.767||
||guint16||<:>0 a 65535||
||gint32||<:>-2.147.483.648 a 2.147.483.647||
||guint32||<:>0 a 4.294.967.295||
||gint64||<:>-9.223.372.036.854.775.808 a 9.223.372.036.854.775.807||
||guint64||<:>0 a 18.446.744.073.709.551.615||
||<style="text-align: center;">'''Tipo''' ||<style="text-align: center;">'''Rango de tamaño del dato.''' ||
||gint8 ||<style="text-align: center;">-128 a 127 ||
||guint8 ||<style="text-align: center;">0 a 255 ||
||gint16 ||<style="text-align: center;">-32.768 a 32.767 ||
||guint16 ||<style="text-align: center;">0 a 65535 ||
||gint32 ||<style="text-align: center;">-2.147.483.648 a 2.147.483.647 ||
||guint32 ||<style="text-align: center;">0 a 4.294.967.295 ||
||gint64 ||<style="text-align: center;">-9.223.372.036.854.775.808 a 9.223.372.036.854.775.807 ||
||guint64 ||<style="text-align: center;">0 a 18.446.744.073.709.551.615 ||
Línea 45: Línea 45:
||<:>'''Tipos de GLib'''||<:>'''Definición'''||
||gboolean||Este tipo es booleano y sólo contendrá los valores TRUE o FALSE.||
||gsize||Es un entero de treinta y dos bits sin signo que sirve para representar tamaños de estructuras de datos.||
||gssize||Es un entero de 32 bits con signo, que sirve para representar tamaños de estructuras de datos.||
||<style="text-align: center;">'''Tipos de GLib''' ||<style="text-align: center;">'''Definición''' ||
||gboolean ||Este tipo es booleano y sólo contendrá los valores TRUE o FALSE. ||
||gsize ||Es un entero de treinta y dos bits sin signo que sirve para representar tamaños de estructuras de datos. ||
||gssize ||Es un entero de 32 bits con signo, que sirve para representar tamaños de estructuras de datos. ||
Línea 53: Línea 54:

=== Mensajes de salida.  ===
=== Mensajes de salida. ===
Línea 58: Línea 57:
Línea 61: Línea 59:
Línea 68: Línea 65:

#include <glib.h>
#include <glib.h>
Línea 76: Línea 71:
Línea 78: Línea 72:
Línea 81: Línea 74:
}}}      }}}
Línea 97: Línea 88:
Línea 99: Línea 89:

#include <glib.h>
#include <glib.h>
Línea 103: Línea 91:
Línea 106: Línea 93:
Línea 109: Línea 95:
        
Línea 112: Línea 97:
   }

main (){
  
}
main (){
Línea 118: Línea 100:
  
Línea 120: Línea 101:
        
Línea 122: Línea 102:
        
Línea 125: Línea 104:
         }

}}}
   
 
}
}}}
Línea 137: Línea 111:
Línea 150: Línea 123:

#include <glib.h>
#include <glib.h>
Línea 156: Línea 127:
        
Línea 159: Línea 129:
        
Línea 162: Línea 131:
         }
}
Línea 169: Línea 136:
        
Línea 172: Línea 138:
        
Línea 174: Línea 139:
        
Línea 177: Línea 141:
        
Línea 181: Línea 144:
Línea 185: Línea 147:
 (process:457): ** ERROR **: file
  ejemplo.c: line 9 (escribe_linea):
 assertion failed: (cadena !=
  NULL)
 aborting...
}}}
        (process:457): ** ERROR **: file
         ejemplo.c: line 9 (escribe_linea):
        assertion failed: (cadena !=
         NULL)
        aborting...
}}}
Línea 211: Línea 172:
Línea 214: Línea 174:
        
Línea 218: Línea 177:

Línea 223: Línea 180:
Línea 226: Línea 182:
        
Línea 231: Línea 186:

main (){
        
main (){
Línea 237: Línea 190:
        
Línea 240: Línea 192:
        
Línea 243: Línea 194:
        
Línea 246: Línea 196:
        
Línea 249: Línea 198:
         }
}}}
}
}}}
Línea 255: Línea 202:
{{{     esto es una cadena
   esto es una cadena

 
-- escribe_linea2 ha devuelto TRUE --

 
(process:578): ** CRITICAL **: file glib-g_return_fail.c: line 6 (escribe_linea):
  assertion `cadena != NULL' failed

 
(process:578): ** CRITICAL **: file glib-g_return_fail.c: line 18 (escribe_linea2):
  assertion `cadena != NULL' failed

 
-- escribe_linea2 ha devuelto FALSE --
 

}}}       
{{{
          esto es una cadena
          esto es una cadena
        
-- escribe_linea2 ha devuelto TRUE --
         (process:578): ** CRITICAL **: file glib-g_return_fail.c: line 6 (escribe_linea):
         assertion `cadena != NULL' failed
         (process:578): ** CRITICAL **: file glib-g_return_fail.c: line 18 (escribe_linea2):
         assertion `cadena != NULL' failed
         -- escribe_linea2 ha devuelto FALSE --
}}}
Línea 276: Línea 217:
Línea 292: Línea 232:
Línea 294: Línea 233:
Línea 296: Línea 234:
Línea 298: Línea 235:
Línea 306: Línea 242:
     
Línea 309: Línea 244:
        
Línea 312: Línea 246:
Línea 315: Línea 248:
        
Línea 318: Línea 250:
Línea 321: Línea 252:
        
Línea 324: Línea 254:
Línea 327: Línea 256:
        
Línea 330: Línea 258:

main (){
        
main (){
Línea 339: Línea 265:
Línea 342: Línea 267:
{{{
   Message: Yo soy solamente un mensaje de aviso


   (process:603): ** WARNING **: Esto es un aviso, algo puede ir mal


   (process:603): ** CRITICAL **: Esto se pone difícil :(


   (process:603): ** ERROR **: 3, 2, 1... acabo de morirme. RIP

   aborting...
   `trap' para punto de parada/seguimiento (core dumped)
 
}}}

Como se puede ver, todas las funciones y macros que se han mostrado en este apartado nos serán especialmente útiles a la hora de realizar un programa y nos posibilitarán una vía estandarizada y muy flexible de emisión de información al exterior. Facilitando la corrección del código y haciendo más facil la tarea del programador.
{{{
          Message: Yo soy solamente un mensaje de aviso
          (process:603): ** WARNING **: Esto es un aviso, algo puede ir mal
          (process:603): ** CRITICAL **: Esto se pone difícil :(
          (process:603): ** ERROR **: 3, 2, 1... acabo de morirme. RIP
          aborting...
          `trap' para punto de parada/seguimiento (core dumped)
}}}
Como se puede ver, todas las funciones y macros que se han mostrado en este apartado nos serán especialmente útiles a la hora de realizar un programa y nos posibilitarán una vía estandarizada y muy flexible de emisión de información al exterior. Facilitando la corrección del código y haciendo más facil la tarea del programador.

== Trabajar con cadenas. ==
=== Manipular el contenido de una cadena. ===

La manipulación de cadenas es muy común en la vida diaria de un desarrollador. El desarrollador necesita realizar tareas como duplicar cadenas, transformarlas en mayúsculas o verificar si algún caracter corresponde a un tipo en especial. Para este tipo de tareas, esta librería dispone de una serie de funciones cuyo uso no dista mucho de las ya desarrolladas en la Libc.
==== Duplicación de cadenas. ====

Si lo que se desea es duplicar cadenas, las funciones ''g_strdup'' y ''g_strndup'' resolverán esa necesidad. Las dos funciones realizan el mismo trabajo: duplican la cadena que se le ha pasado como parámetro. La diferencia radica en que la segunda limita el número de caracteres que devuelve a un número que le es indicado por un segundo parámetro de la función.

`gchar * g_strdup (const gchar * cadena_para_duplicar );`

`gchar * g_strndup (const gchar * cadena_para_duplicar , gsize longitud_maxima );`

==== Verificación de caracteres. ====

El título se refiere al conjunto de funciones capaces de responder a preguntas como: ¿Este carácter es un dígito? o ¿este carácter es una letra?... Este tipo de funciones es muy usado en el tratamiento de cadenas y su funcionamiento es muy simple. Estas funciones reciben un carácter y devuelven cierto o falso. La siguiente tabla explica cuáles son esas funciones y cuál es la verificación que realizan. Se recomienda la observación del prototipo de la función ''g_ascii_isalnum'', usado como ejemplo para una mejor comprensión de la tabla, ya que todas las funciones comparten el mismo prototipo.

`gboolean g_ascii_isalnum (gchar caracter );`

'''Tabla 6-3.1. ''Funciones de verificación de caracteres.'''''
||'''Nombre de función'''||'''Es cierto si...'''||
||g_ascii_isalnum||Es un carácter alfanumérico.||
||g_ascii_isalpha||Es un carácter del alfabeto.||
||g_ascii_iscntrl||Es un carácter de control.||
||g_ascii_isdigit||Es un dígito.||
||g_ascii_isgraph||Es un carácter imprimible y no es un espacio.||
||g_ascii_islower||Es una letra minúscula.||
||g_ascii_isprint||Es un carácter imprimible.||
||g_ascii_ispunct||Es un carácter de puntuación.||
||g_ascii_isspace||Es un espacio.||
||g_ascii_isupper||Es una letra mayúscula.||

==== Copia y concatenación de cadenas. ====

Otra acción típica para el programador es la copia de una cadena o la concatenación de de múltiples cadenas. Para realizar esta tarea podemos utilizar la función ''g_stpcpy''. Esta función desempeña la tarea de copiar una cadena que nosotros le pasemos como parámetro a una cadena destino, también pasada como parámetro. Esta función tiene la particularidad de devolver un puntero a la última posición de la cadena destino, de tal modo que, si se quisiera concatenar cadenas, sólo se tendría que pasar el puntero devuelto por el primer ''g_stpcpy'' al segundo como si fuera el destino. Así el segundo ''g_stpcpy'' entendería que ha de copiar la segunda cadena al final de la primera que hemos copiado anteriormente y así sucesivamente. Siguiendo este método, se podría concatenar una cadena tras otra.

`gchar * g_stpcpy (gchar * cadena_destino , const gchar * cadena_origen );`

=== GString : la otra manera de ver una cadena. ===

GString es un TAD (tipo abstracto de datos) que implementa GLib. Este TAD es un buffer de texto que tiene la capacidad de expandirse, realojando memoria automáticamente, sin que el programador tenga que actuar. Esto es realmente útil para el trabajo con cadenas, porque cuando nosotros reservamos memoria para texto y, más adelante, se nos queda pequeña, el programador tiene que tomarse la molestia de reservar más. Por eso GLib implementa GString, que facilita enormemente el manejo de cadenas sin necesidad de estar pendientes de su gestión de memoria.

Para empezar a estudiar este TAD, lo primero que tenemos que conocer es la estructura de datos sobre la que esta diseñada y después estudiaremos las funciones que interactúan con esa estructura.

{{{
    struct GString
    {
        gchar *str; (1)
        gsize len; (2)
        gsize allocated_len;
    };
}}}

[#1 (1)]
 * En este puntero a una cadena de caracteres es donde se almacenará el contenido de la cadena que nosotros especifiquemos. De este modo, si en algún momento se necesita el contenido de la cadena, sólo es necesario acudir a este campo.

[#2 (2)]
 * Este campo hace referencia a la longitud total de la cadena que está alojada en el campo str de la estructura GString. De este modo, si en str está alojada la cadena "hola", el campo len contendrá el número 4.

Ahora ya sabemos cómo es la estructura GString. El siguiente paso será ver las funciones que trabajan sobre GString con el fin de sacarle el mayor partido a este tipo abstracto de datos.
Cómo se aloja una cadena con GString.

Alojar una cadena con GString es extremadamente sencillo e intuitivo. Para ello usaremos la función ''g_string_new'' (), que tiene la forma:

`GString * g_string_new (const gchar * cadena_inicial );`

Esta función recibe como parámetro una cadena y devuelve la estructura GString. De este modo, dentro de la estructura GString, tendremos toda la información y, si el lector se ha percatado, en la creación de la cadena, nosotros no hemos tenido que realizar ningún movimiento para alojar memoria.

'''Ejemplo 6. Crear una cadena con GString.'''
{{{
/* ejemplo del uso de g_string_new */
#include <glib.h>

main (){
        
        GString *cadena ;
        
        cadena = g_string_new ("!Qué fácil es hacer una cadena!");
        
        g_print ("la cadena que hemos alojado : %s\n", cadena->str);
        g_print ("la longitud de la cadena es : %d\n", cadena->len);
}
}}}

Como se puede ver en la ejecución de este ejemplo, la creación de una cadena con GString es muy sencilla. Pero, además, GLib nos proporciona otra función para crear cadenas. La sinopsis de esta función es:

`GString * g_string_new_len (const gchar * cadena_inicial , gssize longitud_inicial );`

La ventaja que tiene el uso de ''g_string_new_len'' es que nos permite especificar una longitud inicial y esto trae consigo que la cadena que introducimos no tiene necesariamente que estar terminada con el caracter NULL ("\0") y, además, puede tener varios caracteres NULL embebidos dentro de la cadena en cuestión.

==== Cómo puedo liberar un GString ====

Siendo GString una estructura, lo suyo sería liberar uno a uno todos los campos pero, gracias a la implementación que nos ofrece GLib, disponemos de una función que nos ayuda con la liberación de memoria que hemos reservado con la creación de un GString. La sinopsis de esta función sería:

`gchar * g_string_free (GString * cadena , gboolean liberar_contenido_cadena );`

Con la función ''g_string_free'', nosotros podremos liberar el GString que le pasemos como primer argumento a la función. Además, esta función también nos da la posibilidad de liberar o no la cadena que estaría dentro de GString. Y esto se conseguiría si como segundo parámetro le pasásemos el booleano TRUE. En caso contrario, si pasásemos un booleano FALSE, la cadena de caracteres no sería liberada.
==== Añadir, insertar y borrar cadenas en un GString. ====

Con los conocimientos necesarios para crear y liberar este tipo de datos, ha llegado el momento de aprender a trabajar con la funciones que tratan la información que aloja y, para empezar, vamos aprender como se puede añadir texto a una cadena creada como GString. A la hora de añadir texto, nos puede interesar añadir texto al final o al principio de la cadena y podemos hacerlo con GString. Las funciones que pasaremos a ver ahora son exactamente iguales, salvo que contienen las palabras append o prepend, que indican que la función añade el texto al final o al principio respectivamente.

`GString * g_string_append (GString * cadena , gchar * cadena_para_añadir_al_final );`

`GString * g_string_prepend (GString * cadena , gchar * cadena_para_añadir_al_principio );`

Estas son las primeras funciones para el añadido de texto que vamos a ver. La primera, ''g_string_append'', se encargará de añadir el texto pasado como parámetro al final de la cadena contenida dentro del GString y la segunda, ''g_string_prepend'', se encargara de añadir el texto al principio.

Con el siguiente ejemplo, el lector entenderá el uso práctico de estas funciones.

'''Ejemplo 7. Añadir cadena a un GString.'''
{{{
/* ejemplo del uso de g_string_append y g_string_prepend */
#include <glib.h>

main (){

        GString *cadena ;
        
        cadena = g_string_new ("*");
        cadena = g_string_append (cadena, "| texto añadido al final");
        cadena = g_string_prepend (cadena, "texto añadido al principio |");
        
        g_print ("\n%s\n", cadena->str);
}
}}}

Una vez que el programador sabe añadir texto por delante y por detrás de la cadena contenida dentro del GString, el siguiente paso natural sería aprender cómo se pueden introducir datos dentro de las cadenas, es decir, insertar una cadena. Imagíne que tiene un GString con una cadena. Con la función ''g_string_insert'' se puede insertar, en la posición elegida, la cadena que desee. Como puede observar, en la sinopsis de la función y en el siguiente ejemplo, Lo único que tiene que hacer es indicar la posición en la que quiere insertar la cadena y la cadena que se insertará.

`GString * g_string_insert (GString * cadena , gssize posicion , gchar * cadena_para_insertar );`

'''Ejemplo 8. Insertar una cadena a un GString.'''
{{{
/* ejemplo del uso de g_string_insert */
#include <glib.h>

main (){
        
        GString *cadena ;
        gchar *cadena_para_insertar = "muy muy ";
        
        cadena = g_string_new ("El día esta soleado");
        cadena = g_string_insert (cadena, 13, cadena_para_insertar);
        
        g_print ("\n%s\n", cadena->str);
        
        g_string_free (cadena, TRUE);
        
}
}}}

Con las funciones mostradas anteriormente, podemos añadir información a un GString. Si lo que deseamos es borrar, tenemos la función ''g_string_erase''. Sólo hay que indicar la posición desde la que quiere empezar a borrar y el número de caracteres que desea borrar desde esa posición.

`GString * g_string_erase (GString * cadena , gssize posicion , GString * numero_de_caracteres_que_desea_borrar );`

'''Ejemplo 9. Borrar una cadena a un GString.'''
{{{
/* ejemplo del uso de g_string_erase */
#include <glib.h>

main (){
        
        GString *cadena ;
        
        cadena = g_string_new ("Esto es una cadena --esto sera borrado--");
        cadena = g_string_erase (cadena, 19, 21);
        
        g_print ("\n%s\n", cadena->str);
        g_string_free (cadena, TRUE);
}
}}}

==== Introducir texto preformateado a un GString. ====

Esta es una de las aplicaciones más interesantes que podemos dar a un GString. Este tipo de datos nos permite trabajar con texto preformateado, como cuando trabajamos con un ''printf''. Esta opción siempre es interesante, pues una vez que tengamos ese texto dentro del GString, podremos aprovecharnos de las múltiples facetas que posee este tipo.

La siguiente función, ''g_string_printf'', recordará al lector a la ya conocida ''sprintf()'' de C estándar; la diferencia está en que el buffer tiene la capacidad de crecer automáticamente. Otra cosa a tener en cuenta en el uso de esta función es que cuando se usa, el contenido anterior existente (si existiese) es destruido.

`void g_string_printf (GString * cadena , const gchar formato , ... );`

'''Ejemplo 10. Crear texto preformateado con GString.'''
{{{
/* ejemplo del uso de g_string_printf */
#include <glib.h>

main (){
        
        GString *cadena ;
        gchar *frase = "lo bueno, si breve, dos veces bueno" ;
        gint numero = 7 ;
        
        cadena = g_string_new ("");
        g_string_printf (cadena, "FRASE TIPICA : %s\nNUMERO DE LA SUERTE : %d",
                         frase, numero);
        
        g_print ("%s\n",cadena->str);
        g_string_free (cadena, TRUE);
        
}
}}}

GLib también dispone de una función similar a la anterior. La única diferencia estriba en que esta función añade el texto preformateado. Es decir, si tuvieramos un texto dentro del GString, el texto formateado se añadiría detrás del texto existente. Esto le puede resultar útil en el sentido de que la anterior función destruía el contenido anterior y puede que eso no le convenga.

`void g_string_append_printf (GString * cadena , const gchar formato , ... );`

'''Ejemplo 11. Añadir texto preformateado con GString.'''
{{{
/* ejemplo del uso de g_string_append_printf */
#include <glib.h>

main (){
        
        GString *cadena ;
        gchar *frase = "lo bueno, si breve, dos veces bueno" ;
        gint numero = 7 ;
        
        cadena = g_string_new ("Línea ya existente\n");
        g_string_append_printf (cadena, "FRASE TIPICA : %s\nNUMERO DE LA SUERTE : %d",
                                frase, numero);
        g_print ("%s\n",cadena->str);
        g_string_free (cadena, TRUE);
        
}
}}}

==== Otras funciones útiles para el manejo de GString. ====

En las secciones anteriores se han explicado las funciones más comunes con las que poder manejar una estructura del tipo GString, pero estas funciones no son las únicas que existen para trabajar con este tipo de datos. En la siguiente sección, se explicarán otras que, aunque no son tan fundamentales, pueden resultar útiles.

Para empezar, puede que al programador no le interese insertar o añadir una cadena y sólo quiera trabajar con un carácter. Para ello dispone de estas funciones que, aunque surten el mismo efecto que si usase ''g_string_append'' y similares, con un sólo carácter, puede que estas funciones le sirvan para dar más legibilidad a su código en un momento dado.

`GString * g_string_append_c (GString * cadena , gchar caracter );`

`GString * g_string_prepend_c (GString * cadena , gchar caracter);`

`GString * g_string_insert_c (GString * cadena , gssize posicion , gchar * caracter );`

'''Ejemplo 12. Añadir e insertar caracteres a un GString.'''
{{{
/* ejemplo del uso de g_string_{insert|append|prepend}_c */
#include <glib.h>

main (){
        
        GString *cadena;
        gchar caracter ;
        
        cadena = g_string_new ("");
        
        caracter = 'c' ;
        cadena = g_string_append_c (cadena, caracter);
        caracter = 'a' ;
        cadena = g_string_prepend_c (cadena, caracter);
        caracter = 'b' ;
        cadena = g_string_insert_c (cadena, 1, caracter);
        
        g_print ("la cadena resultante es... %s\n",cadena->str);
        g_string_free (cadena, TRUE);
        
}
}}}

Otras acciones que pueden interesarle son la capacidad de truncar un texto por el lugar que usted desee y la capacidad de convertir todo el texto a mayúsculas o minúsculas. Pues para este tipo de necesidades usted dispone de ''g_string_truncate'', cuya sintaxis se muestra a continuación.

`GString * g_string_truncate (GString * cadena , gsize longitud );`

longitud se refiere al número de caracteres desde el principio de la cadena que desea que permanezcan una vez terminada la función.

`GString * g_string_up (GString * cadena );`

`GString * g_string_down (GString * cadena );`

La primera función, ''g_string_up'', es la que convierte a mayúsculas un texto íntegro del GString y la segunda, ''g_string_down'' la que lo convierte en minúsculas.

=== Quarks. ===

Los Quarks son asociaciones entre una cadena de texto y un identificador numérico (gunint32). Ya sea proporcionando el GQuark o la cadena de texto es posible obtener la infomación relacionada el uno con el otro. Los Quarks son utilizados en los Datasets y en los Keyed Data List.

Para crear un Quark nuevo de una cadena de texto se usa ''g_quark_form_string'' () o ''g_quark_from_static_string'' (). Para encontrar la cadena de texto correspondiente a un GQuark use ''g_quark_to_string'' (). Y para encontrar el Quark de una cadena de texto use ''g_quark_try_string'' ().

`GQuark g_quark_from_string (const gchar *string );`

Obtiene el identificador GQuark de la cadena que se pase como parámetro. Si la cadena de texto no tiene asociado un GQuark, un nuevo GQuark es creado, usando una copia de la cadena de texto.

`GQuark g_quark_from_static_string (const gchar *string );`

Obtiene el identificador GQuark de una cadena de texto estática. Si la cadena de texto no tiene asociado un GQuark, un nuevo GQuark es creado, vinculándolo con la cadena.

Tenga en cuenta que esta función es identica a ''g_quark_from_string'' () excepto que si un GQuark es creado la propia cadena de texto es usada en lugar que una copia. Esto ahorra memoria, pero solo puede usarse si la cadeba de texto siempre existe. Esto puede usarse con cadenas de texto que estan alojadas estáticamente en el programa principal, pero no con las alojadas en memoria en el módulo cargado dinámicamente.

`const gchar * g_quark_to_string (GQuark quark );`

Obtiene la cadena de texto asociada con un GQuark.

`GQuark g_quark_try_string (const gchar * string );`

Obtiene el GQuark asociado con la cadena de texto. Regresa el GQuark asociado con la cadena de texto, o 0 si no hay un GQuark asociado con la cadena de texto.

GQuark es usado junto con Keyed Data Lists y Datasets, que son listas para organizar elementos que son accedidos por medio de una cadena de texto o por medio de un identificador GQuark, y Datasets es utilizado para asociar grupos de datos con posiciones de memoria.

Glib

TableOfContents()

La biblioteca GLib es una de las más importantes que existen en GNOME. Esta biblioteca es, junto a la biblioteca GTK+, el pilar sobre el que se sustentan todas las aplicaciones.

Tipos de datos de GLib

Dentro de GLib está implementada una serie de tipos de datos facilita, si cabe, el tratamiento de los datos y además tiene la propiedad de mejorar la portabilidad de los programas. Los tipos que se usan en GLib no son muy diferentes de los utilizados en el estándar de C. Por lo cual no resultará complicado acostumbrarse a su utilización. De momento, comenzaremos aprendiendo los tipos de GLib que corresponden con los del estándar de C.

Tabla 6-1.1. Tipos de GLib que corresponden con los del estándar C.

Tipos GLib.

Tipos estándar C.

gchar

char

gint

int

gshort

short

glong

long

gfloat

float

gdouble

double

Como se observa en la tabla, estos tipos no difieren en grán medida de los utilizados al programar con los tipos del estándar de C, aunque es altamente recomendable poner un poco de esfuerzo para acostumbrarse a estos tipos si se va a trabajar con la plataforma GNOME. GLib también posee una serie de tipos que nos hacen más sencillo el tratamiento de datos. Algunos tienen su correspondencia en C, pero nos hacen más sencillo su uso; otros nos sirven para mantener el mismo tamaño de datos de una plataforma a otra y, finalmente, hay otros que no tienen correspondencia con el estándar de C, pero que nos resultarán bastante útiles.

Tabla 6-1.2. Tipos de GLib que facilitan el uso de tipos del estándar C.

Tipos de GLib

Tipos del C estándar.

Definición

gpointer

void *

gpointer es un puntero sin tipo, que luce mejor que escribir void *.

gconstpointer

gconstpointer es un puntero a una constante. Los datos a los que apuntan no deberían ser cambiados. Este tipo suele usarse en los prototipos de funciones para indicar que el valor al que apunta la función no debería ser cambiado en el interior de la función.

guchar

unsigned char

Como se puede observar, estos tipos son idénticos a los tipos de C que carecen de signo, pero con la ventaja de que son más visuales y fáciles de usar.

guint

unsigned int

gushort

unsigned short

gulong

unsigned long

Tabla 6-1.3. Tipos de GLib que aseguran el tamaño del dato entre plataformas.

Tipo

Rango de tamaño del dato.

gint8

-128 a 127

guint8

0 a 255

gint16

-32.768 a 32.767

guint16

0 a 65535

gint32

-2.147.483.648 a 2.147.483.647

guint32

0 a 4.294.967.295

gint64

-9.223.372.036.854.775.808 a 9.223.372.036.854.775.807

guint64

0 a 18.446.744.073.709.551.615

Tabla 6-1.4. Tipos de GLib nuevos que no están en el estándar de C.

Tipos de GLib

Definición

gboolean

Este tipo es booleano y sólo contendrá los valores TRUE o FALSE.

gsize

Es un entero de treinta y dos bits sin signo que sirve para representar tamaños de estructuras de datos.

gssize

Es un entero de 32 bits con signo, que sirve para representar tamaños de estructuras de datos.

Quizás, nuestro lector más novato haya saltado de su asiento al ver algunos tipos como gint8, gint16, gsize, etc. Para aliviarle esta posible preocupación, es interesante denotar que cuando se programa con GLib, los tipos más usados son los char, int, double, etc., aunque ahora usará los mismos, pero con una "g" delante del tipo.

Mensajes de salida.

Mensajes de salida.

GLib implementa una serie de funciones para el envío de mensajes al exterior del programa. Al igual que en el ANSI C se dispone de la mítica función printf (), GLib posee una función que se asemeja en todo menos en el nombre; esta función es g_print () y su prototipo de función sería:

void g_print (const gchar *format, ...);

Como se puede ver, el uso de g_print () es idéntico al de printf (). Es una función que recibe como parámetros un formato y las variables que se usan dentro de las características del formato, igual que printf ().

Ejemplo 6-2.1. Mensajes de salida.

/* ejemplo del uso de g_print */
#include <glib.h>
int
main (int argc, char *argv[])
{
        gint numero = 1;
        gchar *palabra = "hola";
        g_print ("glib te saluda : %s\nglib te dice un número : %d\n", palabra, numero);
        return 0;
}

Además, GLib provee de un método para dar formato todos los mensajes de salida que se emitan con la función g_print (), por lo que se podría decir que, cada vez que mandamos un mensaje con formato a g_print (), éste debe salir por pantalla con algún tipo de mensaje adicional. Esto es debido a la función g_print_set_handler (), que tiene como parámetros un puntero a función. Esta función, que es representada por el puntero a función, será definida por el programador y, con ella, se podrá decir qué mensaje adicional queremos que se vea. Para entenderlo mejor, se mostrará a continuación la sinopsis de esta función, así como un ejemplo.

GPrintFunc g_print_set_handler (GPrintFunc funcion);

Esta sería la sinopsis de la función g_pint_set_handlet (), que recibiría como parámetro un puntero a función. Esta función tendría este aspecto

void (* GPrintFunc) (const gchar * cadena );

Éste sería el aspecto que ha de tener la función que se le pasará como parámetro a g_print_set_handler. El siguiente ejemplo ha sido concebido con la intención de facilitar su comprensión.

Ejemplo 6-2.2. Personalización de mensajes de salida.

/* ejemplo de cómo añadir información a los mensajes de g_print */
#include <glib.h>
void funcion_personal (const gchar *cadena);
/* funcion_personal es la función que le pasaremos a
   g_print_set_handler como parámetro */
void
funcion_personal (const gchar *cadena){
        printf ("** Soy tu programa y te digo ** ");
        printf (cadena);
}
main (){
        /* g_print normal */
        g_print ("Soy un mensaje normal de salida\n");
        /* g_print personalizado */
        g_set_print_handler (funcion_personal);
        g_print ("mensaje de salida personalizado\n");
}

GLib también nos provee de una función para comunicar mensajes de salida por la salida de errores estándar (stderr). Para el envío de mensajes tenemos la función g_printerr que funciona exactamente igual que g_print. Existe también una función como g_set_print_handler, llamada g_set_printerr_handler que funciona igual que la anterior.

Se puede ver, en conclusión, que el formateo personalizado de los mensajes de salida en GLib es bastante simple.

Funciones de depuración.

La depuración de un programa siempre es un trasiego por el cual todo programador, ya sea principiante o avanzado, ha de pasar. Y para hacer la vida más fácil al programador de GNOME, GLib nos ofrece una serie de funciones que harán más sencilla la depuración del código.

Estas funciones son útiles para comprobar que se cumple una serie de condiciones lógicas delimitadas por el programador. En caso de no ser cumplida, GLib emitirá un mensaje por consola, explicando que la condición que el programador ha puesto no se ha cumplido e indicando el archivo, la línea y la función en las que se ha roto la condición.

#define g_assert ( expresion );

La primera función de este tipo que vamos a ver es g_assert. Esta función recibe como parámetro un enunciado lógico y comprueba su validez. Por poner un ejemplo de su uso, podríamos exponer el caso en el que a una función se le pase un puntero. Y nosotros podríamos poner g_assert (ptr != NULL) para certificar que ese caso no se dé nunca. De hecho, si se diese ese caso, la función g_assert comprobaría que esa expresión no es válida y mandaría interrumpir la ejecución del programa. Para tener más claro este concepto, obsérvese la ejecución del siguiente ejemplo:

Ejemplo 6-2.3. Depuración de programas con g_assert.

/* ejemplo del uso de g_assert */
#include <glib.h>
void
escribe_linea (gchar *cadena)
{
        /* si a la función se le pasa un puntero a NULL
           el programa cesara en la ejecución */
        g_assert (cadena != NULL);
        g_print ("%s\n", cadena);
}
main ()
{
        gchar *cadena="esto es una cadena";
        gchar *no_es_cadena = NULL;
        /* como no se pasa un NULL sino una cadena, se escribirá
           la cadena "esto es una cadena" por pantalla */
        escribe_linea (cadena);
        /* como se le pasa un NULL el assert de la función
           escribe_linea surtirá efecto */
        escribe_linea (no_es_cadena);
}

Si se compila este programa, en la salida del mismo, se podrá observar que cuando entra por segunda vez en la función escribe_linea, cesa la ejecución del programa. Además, por la consola saldrá este mensaje o uno parecido.

        (process:457): ** ERROR **: file
          ejemplo.c: line 9 (escribe_linea):
        assertion failed: (cadena !=
          NULL)
        aborting...

El mensaje da información del proceso donde se rompió la condición y muestra por pantalla información del archivo, de la línea y de la función en las que se viola la condición por la cual g_assert ha parado la ejecución. También indica qué expresión se ha incumplido, porque se puede dar el caso de tener varios g_assert en una misma función.

Quizá un método tan drástico como parar la ejecución del programa no sea lo mejor. Es probable que sólo se busque algo que termine la ejecución de la función y avise que una condición no ha sido cumplida. Para estos casos existen varias macros que facilitarán mucho la vida de los programadores. Estas macros son:

#define g_return_if_fail ()( expresion );

#define g_return_val_if_fail ()( expresion , val );

Las dos macros son similares en su funcionamiento, ya que comprueban si la expresión lógica que se les pasa como primer parámetro es verdadera o falsa. En el caso de ser falsa, aparecerá por consola un mensaje explicando que esa condición no ha sido cumplida. Esto es muy parecido a lo que hacía g_assert (); la diferencia estriba en que estas dos funciones no finalizan la ejecución del programa, sino que simplemente hacen un retorno dentro de la propia función y, en consecuencia, el resto del programa seguirá ejecutándose.

Como se dijo antes, estas macros son similares. La diferencia es que la segunda, g_return_val_if_fail, hace que la función devuelva el valor que se le pasa como segundo parámetro.

Obviamente, g_return_if_fail se usará en funciones que no devuelvan ningún valor y g_return_val_if_fail en funciones que devuelvan algún valor. Para entender mejor estas funciones obsérvese el siguiente ejemplo.

Ejemplo 6-2.4. Depuración de programas con g_return_if_fail y g_return_val_if_fail.

/* ejemplo del uso de g_return_if_fail y f_return_val_if_fail */
#include <glib.h>
void
escribe_linea (gchar *cadena){
        g_return_if_fail (cadena != NULL);
        g_print ("%s\n", cadena);
}
/* escribe línea 2 devolverá
   TRUE si la ha escrito bien
   FALSE si incumple la expresión */
gboolean
escribe_linea2 (gchar *cadena){
        g_return_val_if_fail (cadena != NULL, FALSE);
        g_print ("%s\n", cadena);
        return  TRUE;
}
main (){
        gchar *cadena="esto es una cadena";
        gchar *no_es_cadena = NULL;
        gboolean resultado ;
        escribe_linea (cadena);
        resultado = escribe_linea2 (cadena);
        if (resultado == TRUE)
                g_print ("\n-- escribe_linea2 ha devuelto TRUE --\n");
        escribe_linea (no_es_cadena);
        resultado = escribe_linea2 (no_es_cadena);
        if (resultado == FALSE)
                g_print ("\n-- escribe_linea2 ha devuelto FALSE --\n");
}

Y, por consiguiente, la salida de este programa sería la siguiente:

          esto es una cadena
          esto es una cadena
          -- escribe_linea2 ha devuelto TRUE --
          (process:578): ** CRITICAL **: file glib-g_return_fail.c: line 6 (escribe_linea):
          assertion `cadena != NULL' failed
          (process:578): ** CRITICAL **: file glib-g_return_fail.c: line 18 (escribe_linea2):
          assertion `cadena != NULL' failed
          -- escribe_linea2 ha devuelto FALSE --

Como se puede ver, su ejecución también ofrece información sobre el lugar donde no se ha cumplido la expresión como ya lo hacía la función g_assert, salvo que no detiene la ejecución del programa.

Y estas son las funciones para depuración que se pueden encontrar dentro de la librería GLib. Aunque no son las únicas, sí son las más comunes.

Funciones de registro.

GLib tiene cuatro macros básicas para el tratamiento mensajes, por niveles de importancia. Estas macros permiten al programador realizar una registro del recorrido del programa especificando el nivel de importancia de los sucesos acontecidos dentro del mismo.

Las cuatro macros de las que estamos hablando reciben parámetros de la misma forma que lo hacían g_print o printf. De este modo, no sólo se tendrá una registro por niveles, sino que, además, se podrá especificar un texto preformateado. De este modo, los mensajes pueden representar por pantalla el contenido de variables o cualquier otra información que nos pudiera ser útil. Las cuatro macros de las que estamos hablando son :

#define g_message (...);

#define g_warning (...);

#define g_critical (...);

#define g_error (...);

Como se puede observar, las cuatro macros tienen nombres bastante intuitivos. Para empezar, el lector se habrá dado cuenta, por los nombres de las funciones, de que están ordenadas de menor a mayor importancia, siendo g_message menos importante que g_error. A continuación se explicará lo que hace cada una de ellas.

  • g_message es una macro que emite un mensaje normal con la información que se le ha pasado como parámetro. La información que emite esta macro no tiene por que estar asociada a un error en el programa. Su principal aplicación es el envío de mensajes con la información que se crea conveniente en el proceso de realización del programa.

  • g_warning emite un mensaje de aviso con la información que le ha sido pasada como parámetro. Esta información puede servir para ser avisados de situaciones peligrosas que se podrían dar en el programa.

  • g_critical cumple la misma función que g_warning, sólo que éste además tiene la posibilidad de abortar el programa usando la función g_log_set_always_fatal().

  • g_erroremite el mensaje que le haya sido pasado como argumento y además aborta irremediablemente la ejecución del programa. Esta macro se usa para obtener información de donde ha sucedido el error irrecuperable con la seguridad de que, a causa de este error, el programa terminara abortando su ejecución de todas maneras.

Para una mejor comprensión se muestra el siguiente ejemplo. En él se han definido cuatro funciones, cada una de las cuales emite un mensaje diferente. En este ejemplo no se hace que g_critical tenga capacidad de abortar el programa porque si no, no veríamos como funciona g_error.

Ejemplo 6-2.5. Uso de mensajes de registro.

/* ejemplo del uso de g_warning, g_critical, ... */
#include <glib.h>
void
funcion_con_mensaje (){
        g_message ("Yo soy solamente un mensaje de aviso\n");
}
void
funcion_con_aviso (){
        g_warning ("Esto es un aviso, algo puede ir mal\n");
}
void
funcion_con_aviso_critico (){
        g_critical ("Esto se pone difícil :( \n");
}
void
funcion_con_un_error (){
        g_error ("3, 2, 1... acabo de morirme. RIP\n");
}
main (){
        funcion_con_mensaje ();
        funcion_con_aviso ();
        funcion_con_aviso_critico ();
        funcion_con_un_error ();
}

Aunque este ejemplo no tiene mucha funcionalidad, sirve para ver en acción a las cuatro macros en un mismo programa y da la posibilidad de contemplar en la salida de este programa los mensajes que envía a la consola. Si se ejecuta el ejemplo su salida sería:

          Message: Yo soy solamente un mensaje de aviso
          (process:603): ** WARNING **: Esto es un aviso, algo puede ir mal
          (process:603): ** CRITICAL **: Esto se pone difícil :(
          (process:603): ** ERROR **: 3, 2, 1... acabo de morirme. RIP
          aborting...
          `trap' para punto de parada/seguimiento (core dumped)

Como se puede ver, todas las funciones y macros que se han mostrado en este apartado nos serán especialmente útiles a la hora de realizar un programa y nos posibilitarán una vía estandarizada y muy flexible de emisión de información al exterior. Facilitando la corrección del código y haciendo más facil la tarea del programador.

Trabajar con cadenas.

Manipular el contenido de una cadena.

La manipulación de cadenas es muy común en la vida diaria de un desarrollador. El desarrollador necesita realizar tareas como duplicar cadenas, transformarlas en mayúsculas o verificar si algún caracter corresponde a un tipo en especial. Para este tipo de tareas, esta librería dispone de una serie de funciones cuyo uso no dista mucho de las ya desarrolladas en la Libc.

Duplicación de cadenas.

Si lo que se desea es duplicar cadenas, las funciones g_strdup y g_strndup resolverán esa necesidad. Las dos funciones realizan el mismo trabajo: duplican la cadena que se le ha pasado como parámetro. La diferencia radica en que la segunda limita el número de caracteres que devuelve a un número que le es indicado por un segundo parámetro de la función.

gchar * g_strdup (const gchar * cadena_para_duplicar );

gchar * g_strndup (const gchar * cadena_para_duplicar , gsize longitud_maxima );

Verificación de caracteres.

El título se refiere al conjunto de funciones capaces de responder a preguntas como: ¿Este carácter es un dígito? o ¿este carácter es una letra?... Este tipo de funciones es muy usado en el tratamiento de cadenas y su funcionamiento es muy simple. Estas funciones reciben un carácter y devuelven cierto o falso. La siguiente tabla explica cuáles son esas funciones y cuál es la verificación que realizan. Se recomienda la observación del prototipo de la función g_ascii_isalnum, usado como ejemplo para una mejor comprensión de la tabla, ya que todas las funciones comparten el mismo prototipo.

gboolean g_ascii_isalnum (gchar caracter );

Tabla 6-3.1. Funciones de verificación de caracteres.

Nombre de función

Es cierto si...

g_ascii_isalnum

Es un carácter alfanumérico.

g_ascii_isalpha

Es un carácter del alfabeto.

g_ascii_iscntrl

Es un carácter de control.

g_ascii_isdigit

Es un dígito.

g_ascii_isgraph

Es un carácter imprimible y no es un espacio.

g_ascii_islower

Es una letra minúscula.

g_ascii_isprint

Es un carácter imprimible.

g_ascii_ispunct

Es un carácter de puntuación.

g_ascii_isspace

Es un espacio.

g_ascii_isupper

Es una letra mayúscula.

Copia y concatenación de cadenas.

Otra acción típica para el programador es la copia de una cadena o la concatenación de de múltiples cadenas. Para realizar esta tarea podemos utilizar la función g_stpcpy. Esta función desempeña la tarea de copiar una cadena que nosotros le pasemos como parámetro a una cadena destino, también pasada como parámetro. Esta función tiene la particularidad de devolver un puntero a la última posición de la cadena destino, de tal modo que, si se quisiera concatenar cadenas, sólo se tendría que pasar el puntero devuelto por el primer g_stpcpy al segundo como si fuera el destino. Así el segundo g_stpcpy entendería que ha de copiar la segunda cadena al final de la primera que hemos copiado anteriormente y así sucesivamente. Siguiendo este método, se podría concatenar una cadena tras otra.

gchar * g_stpcpy (gchar * cadena_destino , const gchar * cadena_origen );

GString : la otra manera de ver una cadena.

GString es un TAD (tipo abstracto de datos) que implementa GLib. Este TAD es un buffer de texto que tiene la capacidad de expandirse, realojando memoria automáticamente, sin que el programador tenga que actuar. Esto es realmente útil para el trabajo con cadenas, porque cuando nosotros reservamos memoria para texto y, más adelante, se nos queda pequeña, el programador tiene que tomarse la molestia de reservar más. Por eso GLib implementa GString, que facilita enormemente el manejo de cadenas sin necesidad de estar pendientes de su gestión de memoria.

Para empezar a estudiar este TAD, lo primero que tenemos que conocer es la estructura de datos sobre la que esta diseñada y después estudiaremos las funciones que interactúan con esa estructura.

                  struct GString
                  {
                      gchar  *str;                                      (1)
                      gsize len;                                        (2)
                      gsize allocated_len;
                  };

[#1 (1)]

  • En este puntero a una cadena de caracteres es donde se almacenará el contenido de la cadena que nosotros especifiquemos. De este modo, si en algún momento se necesita el contenido de la cadena, sólo es necesario acudir a este campo.

[#2 (2)]

  • Este campo hace referencia a la longitud total de la cadena que está alojada en el campo str de la estructura GString. De este modo, si en str está alojada la cadena "hola", el campo len contendrá el número 4.

Ahora ya sabemos cómo es la estructura GString. El siguiente paso será ver las funciones que trabajan sobre GString con el fin de sacarle el mayor partido a este tipo abstracto de datos. Cómo se aloja una cadena con GString.

Alojar una cadena con GString es extremadamente sencillo e intuitivo. Para ello usaremos la función g_string_new (), que tiene la forma:

GString * g_string_new (const gchar * cadena_inicial );

Esta función recibe como parámetro una cadena y devuelve la estructura GString. De este modo, dentro de la estructura GString, tendremos toda la información y, si el lector se ha percatado, en la creación de la cadena, nosotros no hemos tenido que realizar ningún movimiento para alojar memoria.

Ejemplo 6. Crear una cadena con GString.

/* ejemplo del uso de g_string_new */
#include <glib.h>

main (){
        
        GString *cadena ;
        
        cadena = g_string_new ("!Qué fácil es hacer una cadena!");
        
        g_print ("la cadena que hemos alojado : %s\n", cadena->str);
        g_print ("la longitud de la cadena es : %d\n", cadena->len);
}

Como se puede ver en la ejecución de este ejemplo, la creación de una cadena con GString es muy sencilla. Pero, además, GLib nos proporciona otra función para crear cadenas. La sinopsis de esta función es:

GString * g_string_new_len (const gchar * cadena_inicial , gssize longitud_inicial );

La ventaja que tiene el uso de g_string_new_len es que nos permite especificar una longitud inicial y esto trae consigo que la cadena que introducimos no tiene necesariamente que estar terminada con el caracter NULL ("\0") y, además, puede tener varios caracteres NULL embebidos dentro de la cadena en cuestión.

Cómo puedo liberar un GString

Siendo GString una estructura, lo suyo sería liberar uno a uno todos los campos pero, gracias a la implementación que nos ofrece GLib, disponemos de una función que nos ayuda con la liberación de memoria que hemos reservado con la creación de un GString. La sinopsis de esta función sería:

gchar * g_string_free (GString * cadena , gboolean liberar_contenido_cadena );

Con la función g_string_free, nosotros podremos liberar el GString que le pasemos como primer argumento a la función. Además, esta función también nos da la posibilidad de liberar o no la cadena que estaría dentro de GString. Y esto se conseguiría si como segundo parámetro le pasásemos el booleano TRUE. En caso contrario, si pasásemos un booleano FALSE, la cadena de caracteres no sería liberada.

Añadir, insertar y borrar cadenas en un GString.

Con los conocimientos necesarios para crear y liberar este tipo de datos, ha llegado el momento de aprender a trabajar con la funciones que tratan la información que aloja y, para empezar, vamos aprender como se puede añadir texto a una cadena creada como GString. A la hora de añadir texto, nos puede interesar añadir texto al final o al principio de la cadena y podemos hacerlo con GString. Las funciones que pasaremos a ver ahora son exactamente iguales, salvo que contienen las palabras append o prepend, que indican que la función añade el texto al final o al principio respectivamente.

GString * g_string_append (GString * cadena , gchar * cadena_para_añadir_al_final );

GString * g_string_prepend (GString * cadena , gchar * cadena_para_añadir_al_principio );

Estas son las primeras funciones para el añadido de texto que vamos a ver. La primera, g_string_append, se encargará de añadir el texto pasado como parámetro al final de la cadena contenida dentro del GString y la segunda, g_string_prepend, se encargara de añadir el texto al principio.

Con el siguiente ejemplo, el lector entenderá el uso práctico de estas funciones.

Ejemplo 7. Añadir cadena a un GString.

/* ejemplo del uso de g_string_append y g_string_prepend */
#include <glib.h>

main (){

        GString *cadena ;
        
        cadena = g_string_new ("*");
        cadena = g_string_append (cadena, "| texto añadido al final");
        cadena = g_string_prepend (cadena, "texto añadido al principio |");
        
        g_print ("\n%s\n", cadena->str);
}

Una vez que el programador sabe añadir texto por delante y por detrás de la cadena contenida dentro del GString, el siguiente paso natural sería aprender cómo se pueden introducir datos dentro de las cadenas, es decir, insertar una cadena. Imagíne que tiene un GString con una cadena. Con la función g_string_insert se puede insertar, en la posición elegida, la cadena que desee. Como puede observar, en la sinopsis de la función y en el siguiente ejemplo, Lo único que tiene que hacer es indicar la posición en la que quiere insertar la cadena y la cadena que se insertará.

GString * g_string_insert (GString * cadena , gssize posicion , gchar * cadena_para_insertar );

Ejemplo 8. Insertar una cadena a un GString.

/* ejemplo del uso de g_string_insert */
#include <glib.h>

main (){
        
        GString *cadena ;
        gchar *cadena_para_insertar = "muy muy ";
        
        cadena = g_string_new ("El día esta soleado");
        cadena = g_string_insert (cadena, 13, cadena_para_insertar);
        
        g_print ("\n%s\n", cadena->str);
        
        g_string_free (cadena, TRUE);
        
}

Con las funciones mostradas anteriormente, podemos añadir información a un GString. Si lo que deseamos es borrar, tenemos la función g_string_erase. Sólo hay que indicar la posición desde la que quiere empezar a borrar y el número de caracteres que desea borrar desde esa posición.

GString * g_string_erase (GString * cadena , gssize posicion , GString * numero_de_caracteres_que_desea_borrar );

Ejemplo 9. Borrar una cadena a un GString.

/* ejemplo del uso de g_string_erase */
#include <glib.h>

main (){
        
        GString *cadena ;
        
        cadena = g_string_new ("Esto es una cadena --esto sera borrado--");
        cadena = g_string_erase (cadena, 19, 21);
        
        g_print ("\n%s\n", cadena->str);
        g_string_free (cadena, TRUE);
}

Introducir texto preformateado a un GString.

Esta es una de las aplicaciones más interesantes que podemos dar a un GString. Este tipo de datos nos permite trabajar con texto preformateado, como cuando trabajamos con un printf. Esta opción siempre es interesante, pues una vez que tengamos ese texto dentro del GString, podremos aprovecharnos de las múltiples facetas que posee este tipo.

La siguiente función, g_string_printf, recordará al lector a la ya conocida sprintf() de C estándar; la diferencia está en que el buffer tiene la capacidad de crecer automáticamente. Otra cosa a tener en cuenta en el uso de esta función es que cuando se usa, el contenido anterior existente (si existiese) es destruido.

void g_string_printf (GString * cadena , const gchar formato , ... );

Ejemplo 10. Crear texto preformateado con GString.

/* ejemplo del uso de g_string_printf */
#include <glib.h>

main (){
        
        GString *cadena ;
        gchar *frase = "lo bueno, si breve, dos veces bueno" ;
        gint numero = 7 ;
        
        cadena = g_string_new ("");
        g_string_printf (cadena, "FRASE TIPICA : %s\nNUMERO DE LA SUERTE : %d",
                         frase, numero);
        
        g_print ("%s\n",cadena->str);
        g_string_free (cadena, TRUE);
        
}

GLib también dispone de una función similar a la anterior. La única diferencia estriba en que esta función añade el texto preformateado. Es decir, si tuvieramos un texto dentro del GString, el texto formateado se añadiría detrás del texto existente. Esto le puede resultar útil en el sentido de que la anterior función destruía el contenido anterior y puede que eso no le convenga.

void g_string_append_printf (GString * cadena , const gchar formato , ... );

Ejemplo 11. Añadir texto preformateado con GString.

/* ejemplo del uso de g_string_append_printf */
#include <glib.h>

main (){
        
        GString *cadena ;
        gchar *frase = "lo bueno, si breve, dos veces bueno" ;
        gint numero = 7 ;
        
        cadena = g_string_new ("Línea ya existente\n");
        g_string_append_printf (cadena, "FRASE TIPICA : %s\nNUMERO DE LA SUERTE : %d",
                                frase, numero);
        g_print ("%s\n",cadena->str);
        g_string_free (cadena, TRUE);
        
}

Otras funciones útiles para el manejo de GString.

En las secciones anteriores se han explicado las funciones más comunes con las que poder manejar una estructura del tipo GString, pero estas funciones no son las únicas que existen para trabajar con este tipo de datos. En la siguiente sección, se explicarán otras que, aunque no son tan fundamentales, pueden resultar útiles.

Para empezar, puede que al programador no le interese insertar o añadir una cadena y sólo quiera trabajar con un carácter. Para ello dispone de estas funciones que, aunque surten el mismo efecto que si usase g_string_append y similares, con un sólo carácter, puede que estas funciones le sirvan para dar más legibilidad a su código en un momento dado.

GString * g_string_append_c (GString * cadena , gchar caracter );

GString * g_string_prepend_c (GString * cadena , gchar caracter);

GString * g_string_insert_c (GString * cadena , gssize posicion , gchar * caracter );

Ejemplo 12. Añadir e insertar caracteres a un GString.

/* ejemplo del uso de g_string_{insert|append|prepend}_c */
#include <glib.h>

main (){
        
        GString *cadena;
        gchar caracter ;
        
        cadena = g_string_new ("");
        
        caracter = 'c' ;
        cadena = g_string_append_c (cadena, caracter);
        caracter = 'a' ;
        cadena = g_string_prepend_c (cadena, caracter);
        caracter = 'b' ;
        cadena = g_string_insert_c (cadena, 1, caracter);
        
        g_print ("la cadena resultante es... %s\n",cadena->str);
        g_string_free (cadena, TRUE);
        
}

Otras acciones que pueden interesarle son la capacidad de truncar un texto por el lugar que usted desee y la capacidad de convertir todo el texto a mayúsculas o minúsculas. Pues para este tipo de necesidades usted dispone de g_string_truncate, cuya sintaxis se muestra a continuación.

GString * g_string_truncate (GString * cadena , gsize longitud );

longitud se refiere al número de caracteres desde el principio de la cadena que desea que permanezcan una vez terminada la función.

GString * g_string_up (GString * cadena );

GString * g_string_down (GString * cadena );

La primera función, g_string_up, es la que convierte a mayúsculas un texto íntegro del GString y la segunda, g_string_down la que lo convierte en minúsculas.

Quarks.

Los Quarks son asociaciones entre una cadena de texto y un identificador numérico (gunint32). Ya sea proporcionando el GQuark o la cadena de texto es posible obtener la infomación relacionada el uno con el otro. Los Quarks son utilizados en los Datasets y en los Keyed Data List.

Para crear un Quark nuevo de una cadena de texto se usa g_quark_form_string () o g_quark_from_static_string (). Para encontrar la cadena de texto correspondiente a un GQuark use g_quark_to_string (). Y para encontrar el Quark de una cadena de texto use g_quark_try_string ().

GQuark g_quark_from_string (const gchar *string );

Obtiene el identificador GQuark de la cadena que se pase como parámetro. Si la cadena de texto no tiene asociado un GQuark, un nuevo GQuark es creado, usando una copia de la cadena de texto.

GQuark g_quark_from_static_string (const gchar *string );

Obtiene el identificador GQuark de una cadena de texto estática. Si la cadena de texto no tiene asociado un GQuark, un nuevo GQuark es creado, vinculándolo con la cadena.

Tenga en cuenta que esta función es identica a g_quark_from_string () excepto que si un GQuark es creado la propia cadena de texto es usada en lugar que una copia. Esto ahorra memoria, pero solo puede usarse si la cadeba de texto siempre existe. Esto puede usarse con cadenas de texto que estan alojadas estáticamente en el programa principal, pero no con las alojadas en memoria en el módulo cargado dinámicamente.

const gchar * g_quark_to_string (GQuark quark );

Obtiene la cadena de texto asociada con un GQuark.

GQuark g_quark_try_string (const gchar * string );

Obtiene el GQuark asociado con la cadena de texto. Regresa el GQuark asociado con la cadena de texto, o 0 si no hay un GQuark asociado con la cadena de texto.

GQuark es usado junto con Keyed Data Lists y Datasets, que son listas para organizar elementos que son accedidos por medio de una cadena de texto o por medio de un identificador GQuark, y Datasets es utilizado para asociar grupos de datos con posiciones de memoria.

Documentacion/Desarrollo/Glib (última edición 2008-12-04 08:48:53 efectuada por localhost)