lunes, 29 de abril de 2013

Listado de Macros Predefinidas por GCC.


Muchas veces necesitamos conocer cuales son las macros predefinidas por gcc.

Esto puede resultar útil para infinidad de casos; uno de los más útiles tal vez sea la detección de características de la arquitectura actual de la computadora.

El comando en cuestión es:

$ gcc -dM  -E - < /dev/null
#define __DBL_MIN_EXP__ (-1021)
#define __FLT_MIN__ 1.17549435e-38F
#define __DEC64_DEN__ 0.000000000000001E-383DD
#define __CHAR_BIT__ 8
#define __WCHAR_MAX__ 2147483647
#define __NO_MATH_INLINES 1
#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
#define __FLT_EVAL_METHOD__ 0
#define __DBL_MIN_10_EXP__ (-307)
#define __FINITE_MATH_ONLY__ 0
#define __DEC64_MAX_EXP__ 384
#define __SHRT_MAX__ 32767
#define __LDBL_MAX__ 1.18973149535723176502e+4932L
#define __APPLE_CC__ 5658
#define __UINTMAX_TYPE__ long unsigned int
#define __DEC32_EPSILON__ 1E-6DF
#define __block __attribute__((__blocks__(byref)))
#define __SCHAR_MAX__ 127
#define __USER_LABEL_PREFIX__ _
#define __x86_64 1
#define __x86_64__ 1
...

El resultado es claro:
#define NOMBRE_MACRO VALOR.

Para este caso, las últimas dos líneas nos indican dos formas diferentes de obtener la arquitectura actual:

#if __x86_64
 // 64 bits x86.
#endif

Otro ejemplo, para el caso de una compilación para 32 bits (sobre x86):

gcc -m32 -dM  -E - < /dev/null
#define __DBL_MIN_EXP__ (-1021)
#define __FLT_MIN__ 1.17549435e-38F
#define __DEC64_DEN__ 0.000000000000001E-383DD
#define __CHAR_BIT__ 8
#define __WCHAR_MAX__ 2147483647
#define __NO_MATH_INLINES 1
#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
#define __FLT_EVAL_METHOD__ 0
#define __DBL_MIN_10_EXP__ (-307)
#define __FINITE_MATH_ONLY__ 0
#define __DEC64_MAX_EXP__ 384
#define __SHRT_MAX__ 32767
#define __LDBL_MAX__ 1.18973149535723176502e+4932L
#define __APPLE_CC__ 5658
#define __DBL_MAX__ 1.7976931348623157e+308
#define __i386 1
#define i386 1
#define __i386__ 1
...

Las macros definidas serán i386, __i386, __i386__, etc.

Etiquetas: , , , , , ,

jueves, 29 de diciembre de 2011

Vim Word Fuzzy Completion.

El último tiempo estuve probando un editor de texto que para mi es bastante nuevo: sublime2.

Esta genial aplicación tiene muchísimas características interesantes como es un minimap del texto, a la derecha sobre el que se puede navegar, apertura de archivos utilizando fuzzy search sobre el path actual, auto completado 'fuzzy' con la tecla <Tab>, búsqueda por símbolos con el caracter @, indentado de texto muy inteligente, etc.

Inmediatamente me despertó la curiosidad sobre algunas funcionalidades que vim no trae de cajón, y que muy tranquilamente podría tener:

1- Apertura de archivos utilizando fuzzy search.

2- Completado 'fuzzy' de palabras (ej: si en mi archivo tengo la palabra futurama, yo escribo frutur, presiono <Tab> o alguna combinación, y el editor de texto debería sugerirme 'futurama').

El caso (1) lo resolví con el excelente complemento 'CommandT' para vim: enlace.

Sin embargo, me llamó la atención que no pude encontrar una solución para el caso (2), ya que es una funcionalidad relativamente fácil de implementar en un plugin.

Dado lo anterior, me senté unas horas de una tarde y lo resolví creando el plugin 'Word Fuzzy Completion': enlace (mi primer aporte a la comunidad de usuarios vim), el código fuente del plugin está alojado en github: enlace.

El funcionamiento del plugin es sencillo, existen dos combinaciones de teclas para utilizarlo:

"<Ctrl-X><Ctrl-U>" o uno mas corto "<Ctrl-K>".

Suponiendo que estamos editando un buffer que contiene lo siguiente:

-------- buffer ----------
The simpsons
Futurama
Back to the future
Features
-------- buffer ----------

Si escribimos:

1) sminsons<Ctrl-k>
La palabra será cambiada a:
simpsons
2) smi<Ctrl-k>
La palabra cambiará nuevamente a:
simpsons
3) furure<Ctrl-k>
La palabra cambiará a:
future
4) Furu<Ctrl-k>
Se mostrará el listado de palabras similares:
Fururama
Future
Features

La implementación del plugin está escrita en python, y utiliza el algoritmo de Distancia de Levenshtein para medir distancias entre las palabras del buffer actual.

Se que hay muchas cosas para mejorarle, la primera es cambiar la combinación de teclas '<Ctrl-K>' ya que está pisando una funcionalidad de vim, y la segunda es el buscado de palabras en todos los buffers abiertos. Cuando esté con un poco de tiempo libre lo implementaré.

Enlaces:

Sublime2: enlace.
Vim: enlace.
WordFuzzyCompletion Plugin: enlace (fuentes: enlace).
CommandT Plugin: enlace.
Distancia de Levenshtein: enlace.

martes, 23 de agosto de 2011

Es muy habitual en c++ o en c, manejar archivos en parejas, por ejemplo al editar un archivo llamado "archivo.cc" es muy probable que editemos también a un archivo "archivo.hh" para reflejar cambios de interface y viceversa.

Este mapeo para vim define una forma fácil de abrir fichero compañero en un split vertical con solo presionar la combinación Ctrl+h.

Simplemente debe agregarse la siguiente línea al archivo ~/.vimrc:

if has('python')
map <C-h> :py import vim; vim.command("vsplit %s.%s" % ("".join(vim.current.buffer.name.split(".")[0:-1]), {"cpp":"hpp","cc":"hh","hpp":"cpp","hh":"cc","c":"h","h":"c"}[vim.current.buffer.name.split(".")[-1]]))<CR><CR>
end

Este es uno de los maps para vim que uso con mas frecuencia. Por ello le he definido varias parejas. Lo siguiente significa que si editamos el primero de cada línea que sigue, y presionamos ctrl+h, entonces se abrirá el segundo en un split vertical.

cc -> hh
hh -> cc
hpp -> cpp
cpp -> hpp
h -> c
c -> h

Ejemplo: Cuando se está editando un archivo "archivo.hh", presionar la tecla Escape, y luego utilizar la abreviatura Ctrl+H.

viernes, 19 de febrero de 2010

Como ver conexiones de red por proceso en MacOSX.

Cuando uno quiere ver cuales son las conexiones de red asociadas a sus respectivas PID en el sistema, en linux podemos utilizar:

my_linux_box $ netstat -pn

el cual nos arrojará un lindo listado de conexiones asociadas a las respectivas PIDs del sistema.

Quien hace esto posible es el switch 'p', pero, al parecer, este no es un standard, y para colmo, no está disponible en la versión de netstat disponible para MacOSX.

Esto además significa que los scripts que (con tanto amor) generemos no serían portables a otros sistemas Unix, ya que por lo que pude averiguar, hay varios UNIXs mas que sufren esto.

Por lo tanto una alternativa (en teoría 100% compatible con todos los unix) es utilizar el viejo y conocido lsof, de la siguiente forma:


snake-island:/Us*/jo*/Do*/data-integration: jonatan$ lsof -i -n
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
SystemUIS 170 jonatanalexisanauati 10u IPv4 0x3d69d90 0t0 UDP *:*
firefox-b 771 jonatanalexisanauati 67u IPv4 0xa966a68 0t0 TCP 186.13.221.96:49801->74.125.47.83:https (ESTABLISHED)
firefox-b 771 jonatanalexisanauati 69u IPv4 0x9e50270 0t0 TCP 186.13.221.96:49816->74.125.47.83:https (ESTABLISHED)
firefox-b 771 jonatanalexisanauati 72u IPv4 0xa964a68 0t0 TCP 186.13.221.96:49758->74.125.47.191:http (ESTABLISHED)
firefox-b 771 jonatanalexisanauati 82u IPv4 0x85b7270 0t0 TCP 186.12.227.84:54534->17.149.160.21:http (CLOSED)
firefox-b 771 jonatanalexisanauati 89u IPv4 0xa96866c 0t0 TCP 186.13.221.96:49732->74.125.47.191:http (ESTABLISHED)
NewsFire 8831 jonatanalexisanauati 7u IPv4 0xa964270 0t0 TCP 186.13.221.96:49761->74.125.47.133:http (CLOSE_WAIT)
NewsFire 8831 jonatanalexisanauati 10u IPv4 0xa968a68 0t0 TCP 186.13.221.96:49762->74.125.47.191:http (CLOSE_WAIT)
NewsFire 8831 jonatanalexisanauati 11u IPv4 0xa966e64 0t0 TCP 186.13.221.96:49810->74.125.47.191:http (ESTABLISHED)


el switch 'i' hace la magia, y hasta se puede ser un poco mas específico,
por ejemplo si lo que se quiere es ver todas las conexiones tcp:


snake-island:/Us*/jo*/taller: jonatan$ lsof -itcp -n
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
firefox-b 771 jonatanalexisanauati 67u IPv4 0xa964e64 0t0 TCP 186.13.221.96:49769->74.125.47.17:https (ESTABLISHED)
firefox-b 771 jonatanalexisanauati 69u IPv4 0xa966a68 0t0 TCP 186.13.221.96:49755->74.125.47.191:http (ESTABLISHED)
firefox-b 771 jonatanalexisanauati 71u IPv4 0x9e50270 0t0 TCP 186.13.221.96:49757->74.125.47.191:http (ESTABLISHED)
firefox-b 771 jonatanalexisanauati 72u IPv4 0xa964a68 0t0 TCP 186.13.221.96:49758->74.125.47.191:http (ESTABLISHED)
firefox-b 771 jonatanalexisanauati 74u IPv4 0x9e5066c 0t0 TCP 186.13.221.96:49760->74.125.47.83:https (ESTABLISHED)
firefox-b 771 jonatanalexisanauati 82u IPv4 0x85b7270 0t0 TCP 186.12.227.84:54534->17.149.160.21:http (CLOSED)
firefox-b 771 jonatanalexisanauati 89u IPv4 0xa96866c 0t0 TCP 186.13.221.96:49732->74.125.47.191:http (ESTABLISHED)
NewsFire 8831 jonatanalexisanauati 7u IPv4 0xa964270 0t0 TCP 186.13.221.96:49761->74.125.47.133:http (CLOSE_WAIT)
NewsFire 8831 jonatanalexisanauati 10u IPv4 0xa968a68 0t0 TCP 186.13.221.96:49762->74.125.47.191:http (CLOSE_WAIT)
NewsFire 8831 jonatanalexisanauati 11u IPv4 0xa966e64 0t0 TCP 186.13.221.96:49763->74.208.86.247:http (CLOSE_WAIT)


Este switch ('i') acepta el siguiente formato (según el man):

[46][protocol][@hostname|hostaddr][:service|port]

where:
46 specifies the IP version, IPv4 or IPv6
that applies to the following address.
'6' may be be specified only if the UNIX
dialect supports IPv6. If neither '4' nor
'6' is specified, the following address
applies to all IP versions.
protocol is a protocol name - TCP or UDP.
hostname is an Internet host name. Unless a
specific IP version is specified, open
network files associated with host names
of all versions will be selected.
hostaddr is a numeric Internet IPv4 address in
dot form; or an IPv6 numeric address in
colon form, enclosed in brackets, if the
UNIX dialect supports IPv6. When an IP
version is selected, only its numeric
addresses may be specified.
service is an /etc/services name - e.g., smtp -
or a list of them.
port is a port number, or a list of them.


Por lo que si queremos ver todas las conexiones tcp sobre ipv4, que se relacionen con google, se puede hacer algo como sigue:


snake-island:/Us*/jo*/Do*/data-integration: jonatan$ lsof -i4tcp@www.google.com -n
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
firefox-b 771 jonatanalexisanauati 70u IPv4 0xa96566c 0t0 TCP 186.13.221.96:49805->74.125.47.106:http (ESTABLISHED)
firefox-b 771 jonatanalexisanauati 71u IPv4 0xa965e64 0t0 TCP 186.13.221.96:49806->74.125.47.103:http (ESTABLISHED)
firefox-b 771 jonatanalexisanauati 73u IPv4 0xa964e64 0t0 TCP 186.13.221.96:49807->74.125.47.103:http (ESTABLISHED)


Referencias:
    lsof(8).

Etiquetas: , , , ,

sábado, 7 de noviembre de 2009

Expresiones regulares en C.

El siguiente es un ejemplo de como utilizar expresiones regulares (POSIX RegEx) en C.

Para windows, existe una implementación del módulo regex aquí. Con este sería posible compilar la aplicación (yo lo probé y funcionó), basta con agregar los directorios de includes y librerías, y decirle al compilador que enlace con la librería de regex.

 1 /* Ejemplo simple de expresiones regulares en C.
 2  * Para compilar:
 3  * linux:   $ gcc ejemplo_regex.c -o ejemplo_regex -D_GNU_SOURCE -D__LINUX__
 4  * macosx:  $ gcc ejemplo_regex.c -o ejemplo_regex -D__BSD__
 6 */
 7 //#define _GNU_SOURCE
 8 #include <stdio.h>
 9 #include <stdlib.h>
10 #include <string.h>
11
12 #ifndef _POSIX_C_SOURCE
13 # define _POSIX_C_SOURCE
14 #endif
15 #include <regex.h>
16
17 #ifndef __LINUX__
18 char * strndup (char * from, int len)
19 {
20     char * ret_str = NULL;
21     
22     ret_str= (char *)malloc ((len+1)*sizeof(char));
23     if (ret_str)
24     {
25         strncpy (ret_str,from, len);
26         ret_str[len]='\0';
27     }
28     return ret_str;
29 }
30 #endif
31
32 char * get_string (char * str, regmatch_t m)
33 {
34     char * dup = NULL;
35     int from = m.rm_so;
36     int to   = m.rm_eo;
37
38     if (from != -1)
39     {
40         dup = strndup(str+from, (size_t)to-from);
41     }
42     return dup;
43 }
44
45 main ()
46 {
47     regex_t regex;
48     regmatch_t m[4];
49     int i=0;
50     char * pattern ="(^[^\t]+)(\t)([^\t]+$)";  
51     char * target = "hola\tchau";
52
53     char * temp;
54
55     regcomp (&regex, pattern, REG_EXTENDED);
56     regexec (&regex, target, 4, m, 0);
57     regfree (&regex);
58     for (i=0; i<4; i++)
59     {
60         temp = get_string (target, m[i]);
61         if (temp)
62         {
63             printf ("match: --%s--\n", temp);
64             free (temp);
65         }
66     }
67 }

viernes, 3 de julio de 2009

Django strftime template filter.

A continuación el filtro, que vale aclarar que es muuuuy sencillo:

strftime_filter.py:

from django.template import Library
register = Library()

@register.filter
def strftime (source,format_string):
    return source.strftime(str(format_string))


y el caso práctico de uso:

{% load strftime_filter %}
<html>
    <body>
        <span> {{myDate|strftime:"%d/%m/%Y"}}</span>
    </body>
</html>



Y debería imprimir la fecha con el formato dd/mm/aaaa.

domingo, 24 de mayo de 2009

Pkcs7 en C con OpenSSL.

En esta entrada muestro código de ejemplo para poder firmar un mensaje según la especificación Pkcs 7. Para hacerlo aprovecho el api que brinda el proyecto OpenSSL. Por razones obvias el lenguaje de programación es C.

Una vez generado el binario ejecutable del siguiente código, tendremos una aplicación de terminal, que recibe tres parámetros:
- ruta del archivo del certificado X509. Dicho archivo puede estar en formato PEM o DER.
- ruta del archivo de la clave privada. También el formato puede ser PEM o DER.
- mensaje para firmar.
Para finalizar se imprime por stdout el resultado.

Para compilar:
jaa@dino-thunder_ng ~/taller $ gcc pkcs7_sign.c -o pkcs7_sign -lssl


Evidentemente deben estar instalados OpenSSL y sus headers de desarrollo para poder compilar.

A continuación el ejemplo:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/x509.h>

extern FILE *stderr;

char * pkcs7_sign
    (char * certfile,
    char * keyfile,
    char * message,
    char * cert_passwd,
    char * key_passwd);

int main (int argc, char ** argv)
{
    char * pk7sm= NULL;
    if (argc != 4)
    {
        printf ("MODO DE USO: %s cert_file key_file, message\\n",argv[0]);
        exit (1);
    }
    pk7sm=pkcs7_sign (argv[1],argv[2],argv[3],NULL,NULL);
    if (pk7sm != NULL)
        printf ("%s",pk7sm);
    else
    {
        fprintf (stderr, "Error inesperado.\\n");
        exit (1);
    }
    exit (0);
}

X509 * load_file (char * fname)
{
    FILE * fp   = NULL;
    X509 * cert = NULL;

    fp = fopen ((const char *)fname, "r");
    if (fp == NULL)
    {
        perror ("fopen()");
        return NULL;
    }
    cert = d2i_X509_fp(fp, NULL);
    if (cert != NULL)
        goto success;
    if (cert == NULL)
    {
        rewind (fp);
        cert = (X509 *)PEM_read_X509 (fp, NULL, NULL, NULL);
    }
    success:
        fclose (fp);
        return cert;
}

EVP_PKEY * load_key_file (char * fname)
{
    FILE * fp   = NULL;
    EVP_PKEY * pkey = NULL;

    fp = fopen ((const char *)fname, "r");
    if (fp == NULL)
    {
        perror ("fopen()");
        return NULL;
    }
    pkey = d2i_PrivateKey_fp (fp, NULL);
    if (pkey != NULL)
        goto success;
    if (pkey == NULL)
    {
        rewind (fp);
        pkey = (EVP_PKEY *) PEM_read_PrivateKey (fp, NULL, NULL, NULL);
    }
    success:
        fclose (fp);
        return pkey;
}

char * pkcs7_sign
    (char * certfile,
    char * keyfile,
    char * message,
    char * cert_passwd,
    char * key_passwd)
{
    PKCS7       * scms          = NULL;
    X509        * cert          = NULL;
    EVP_PKEY    * pkey          = NULL;
    BIO         * message_bio   = NULL;
    BIO         * signed_message= NULL;

    char * bio_data_ptr         = NULL;
    char * smessage             = NULL;
    long   bio_data_len         = 0;

    cert = load_file (certfile);
    if (cert == NULL)
    {
        fprintf (stderr,"Formato de certificado no valido: DER o PEM\\n");
        goto finally;
    }
    pkey = load_key_file (keyfile);
    if (pkey == NULL)
    {
        fprintf (stderr,"Formato de clave no valido: DER o PEM\\n");
        goto finally;
    }
    message_bio = BIO_new_mem_buf (message, strlen(message));
    if (message_bio == NULL)
    {
        fprintf (stderr,"Error creando buffer.\\n");
        goto finally;
    }
    SSL_library_init();
    scms = PKCS7_sign (cert, pkey, NULL, message_bio, PKCS7_DETACHED);
    if (scms == NULL)
    {
        long err= ERR_get_error ();
        char * err_txt = (char *)ERR_error_string (err);
        fprintf (stderr,"Error firmando pkcs7 (%i): %s\\n",\\
                (int)err,((err_txt==NULL)?" ":err_txt));
        goto finally;
    }

    signed_message = BIO_new (BIO_s_mem());
    if (signed_message == NULL)
    {
        fprintf (stderr,"Error creando buffer.\\n");
        goto finally;
    }
    if (PEM_write_bio_PKCS7 (signed_message, scms) <= 0)
    {
        fprintf (stderr,"Error transportando a PEM.\\n");
        goto finally;
    }
    bio_data_len =BIO_get_mem_data (signed_message, &bio_data_ptr);
    smessage = (char *)malloc (bio_data_len + 1);
    if (smessage == NULL)
    {
        perror ("malloc ()");
        goto finally;
    }
    memcpy (smessage, bio_data_ptr, bio_data_len);
    *(smessage+bio_data_len)=\'\\0\';
    finally:
        if (message_bio != NULL)
            BIO_free(message_bio);
        if (signed_message != NULL)
            BIO_free(signed_message);
        if (cert != NULL)
            X509_free(cert);
        if (pkey != NULL)
            EVP_PKEY_free(pkey);
        return smessage;
}

Etiquetas: , , , ,