Skip to main content

Grandes frases

Hoy me encontré con esto, ¿quien no lo pensó alguna vez?... ¿quien no lo pone en práctica todos los días :P?

Calvin y Hobbes

Hobbes: Pensé que íbamos a hacer la cama.

Calvin: ¿!¿ Y Hacer todo ese trabajo ?!? ¡No, vamos a inventar un robot que haga la cama por nosotros!

Hobbes: ¿Inventar un robot no es más trabajo que hacer la cama?

Calvin: Solo es trabajo si alguien te obliga a que lo hagas.

Escribiendo un salvapantallas para Gnu/Linux [C]

Los salvapantallas son algo que siempre me llamó poderosamente la antención pero hasta hace poco no sabía como se escribían, hoy aprenderemos a hacer uno para el XScreensaver de Gnu/Linux.

El primer paso es hacernos con el archivo vroot.h del xscreensaver (si hacemos apt-get source xscreensaver nos lo encontraremos en el directorio utils/ [o aquí]), y meterlo en el mismo directorio en el que desarrollaremos el resto del código. vroot.h es un archivo (bajo licencia de estilo BSD) usado comunmente para tomar al ventana_raíz, en la que tenemos que escribir si, por ejemplo, queremos hacer un salvapantallas.

Empezamos entonces con nuestro archivo, lo llamaremos salvapantallas.c y empezamos con el código, si bien va todo junto los comentarios hacen las "presentaciones":

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Cabeceras de X11 */
#include <X11/Xlib.h>
#include "vroot.h"

/* Esto no es necesario para el programa en si,
   per es muy útil en el caso de querer hacer
   comprobaciones y en el caso de que resulten
   mal, detener el programa.
*/
#include <assert.h>



/* Esta será la función que dibuje el salvapantallas
   por ahora no hace nada
*/
void drawScreen(Display* display, Window window,
                XWindowAttributes window_attributes,
                GC gc){

}

/* En la función principal tomaremos la ventana en
   la que escribiremos y la pasamos a la función anterior.
*/
int main (int argc, char **argv){

    /* Tomamos el identificador de pantalla. */
    char *display_id = getenv("DISPLAY");

    /* Suponemos que el display_id no es nulo. */
    assert(display_id != NULL);

    /* Conectamos con la pantalla. */
    Display *display = XOpenDisplay(display_id);

    /* Obtenemos la ventana, es la que mostrará el programa. */
    Window root = DefaultRootWindow(display);

    /* Creamos un contexto gráfico, este es el lienzo
       donde dibujamos.
    */
    GC gc = XCreateGC(display, root, 0, NULL);

    /* Por último leemos las dimensiones de la ventana, 
       que siempre es bueno saber cuales son
    */
    XWindowAttributes window_attributes; 
    XGetWindowAttributes(display, root, &window_attributes);

    /* Y solo queda dar vueltas esperando al usuario */
    while (1){
        /* Dibujamos algo. */
        drawScreen(display, root, window_attributes, gc);

        /* Forzamos los cambios. */
        XFlush(display);

    /* Y le damos un respiro a CPU. */
        usleep(2000);
    }

    /* Esto solo está para que el compilador esté tranquilo ;)  */
    return 0;
}

Y ya tenemos el esqueleto de un salvapantallas, vamos a meter algún relleno en drawScreen y ya lo configuramos, así ya se puede ir probando antes de meterse a hacer alguna animación en concreto.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/* Esta es la función que dibuja el salvapantallas. */
void drawScreen(Display* display, Window window,
                XWindowAttributes window_attributes,
                GC gc){

    /* Creamos un segundo buffer, en este se van haciendo los
       cambios antes de pasarlos a la pantalla, de esta forma
       conseguimos que todo valla suave.
       (Realmente ahora no hace falta, pero es una técnica
       que es bueno saber si se va a trabajar con los gráficos
       directamente.

    Creamos entonces un bitmap basado en la ventana con la
       misma altura, anchura y profundidad.
    */ 
    Pixmap double_buffer = XCreatePixmap(display, window,
                                         window_attributes.width,
                                         window_attributes.height,
                                         window_attributes.depth);

    /* Pintamos de negro. */
    XSetForeground(display, gc, 0);

    /* Y limpiamos el doble buffer. */
    XFillRectangle(display, double_buffer, gc,
                   0, 0, window_attributes.height,
                   window_attributes.width);

    /* El código de ejemplo dibuja un cuadrado de 4 pixeles
       que va dando vueltas alrededor del centro de la pantalla.
    */

    /* Primero determinamos la posición. */
    static int next_position = 0;


    /* Esto abulta mucho pero no tiene gran misterio,
       solo calcula la posición en la que deberá­a estar el cuadrado.
    */
    int x_center = window_attributes.width / 2,
        y_center = window_attributes.height / 2;

int x_position, y_position;

if (next_position < 128){      // Borde superior
        x_position = x_center + (next_position - 64);
        y_position = y_center - 64;
    }
    else if (next_position < 256){ // Borde derecho
        x_position = x_center + 64;
        y_position = y_center + ((next_position % 128) - 64);
    }
    else if (next_position < 384){ // Borde inferior
        x_position = x_center + (64 - (next_position % 128));
        y_position = y_center + 64;
    }
    else{                          // Borde izquierdo
        x_position = x_center - 64;
        y_position = y_center + (64 - (next_position % 128));
    }
    next_position = (next_position + 1) % 512;

    /* Ahora dibujamos el rectángulo.

       (Hay que tener en cuenta que la posición indica la 
       distancia desde la esquina superior izquierda.)
    */
    /* De color blanco. */
    XSetForeground(display, gc, 0xFFFFFF);

    /* Con centro en x_position, y_position . */
    XFillRectangle(display, double_buffer, gc,
                   x_position - 2, y_position - 2, 4, 4);

    /* Y lo pasamos a la pantalla. */
    XCopyArea(display, double_buffer, window,
              gc, 0, 0, 
              window_attributes.width, window_attributes.height,
              0, 0);


    /* Por último eliminamos el doble buffer de la memoria. */
    XFreePixmap(display, double_buffer);
}

El grupo de if/elses se hace un poco pesando, pero es lo más simple que encontré que pudiese producir una animación coherente y mostrase un poco de todo :/. Bien, ahora a probarlo, primero lo compilamos, hace falta avisarle al

1
2
gcc de que tiene que enlazarlo con la librería de X11:
gcc salvapantallas.c -o salvapantallas -lX11

Hecho esto, tenemos que guardarlo en /usr/lib/xscreensaver/ sudo mv salvapantallas /usr/lib/xscreensaver/

Luego solo queda añadirlo al archivo .xscreensaver de la carpeta $HOME, al final de la lista para poder encontrarlo fácilmente:

- salvapantallas -root \n\

Y ya lo podemos probar, lanzamos xscreensaver-demo y seleccionandolo se nos muestra una animación:

Bien, así se hace un salvapantallas, ahora vamos a ponerle otra animación, lo primero: borrar todo el código de drawAnimation :), vamos a dibujar la curva del dragón

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/* Esta es la función que dibuja el salvapantallas. */
void drawScreen(Display* display, Window window,
                XWindowAttributes window_attributes,
                GC gc){


    static int step = 0; // nº de paso
    static int lastg = 0; // Último valor calculado (necesario para el fractal)
    static int x_position = -1; // Posicion actual en la horizontal
    static int y_position = -1; // Posicion actual en la vertical
    static int direction = 0; // 0 = arriba, 1 = derecha, 2 = abajo, 3 = izquierda
    static long color = 0;    // Color actual, 0 = negro, 0xFFFFFF = blanco

    /* Si es la primeira vez o salímos de la pantaia, reiniciamos las coordeadas, la
       dirección y el número de paso y vamos cambiando el color entre blanco y negro.
    */
    if ((x_position < 0) || (x_position >= window_attributes.width) ||
        (y_position < 0) || (y_position >= window_attributes.height)){

        x_position = window_attributes.width / 2;
        y_position = window_attributes.height / 2 ;

        // Dirección, numero de paso y último valor calculado a 0
        direction = step = lastg = 0;

        color ^= 0xFFFFFF; // Si es negro cambia a blanco y al revés
    }

    XSetForeground(display, gc, color);

    // Cálculos del fractal
    int g = step ^ (step >> 1);
    int t = (~g) & lastg;
    lastg = g;

    if (t == 0){ // Se t == 0, giramos 90 graos
        direction = (direction + 1) % 4;
    }
    else{
        // Dado que en C (-1 % 4) == -1,
        // usamos 3 como equivalente % 4
        direction = (direction + 3) % 4;
    }

    // Avanzamos según la dirección
    switch(direction){
    case 0:
        y_position--;
        break;

    case 1:
        x_position++;
        break;

    case 2:
        y_position++;
        break;

    case 3:
        x_position--;
        break;
    }

    XFillRectangle(display, window, gc,
                   x_position, y_position,
                   1, 1);

    // Nos preparamos para el siguiente paso
    step++;
}

Este es el resultado:

Que os parece, animaos a hacer uno vosotros también, todo sea por mirar los colorinchos :P.

ps: Aúa que tirara de tantos static, no se debe hacer, fue para evitar andar a hacer cambios por todo el código, non es algo que se deba hacer en código limpio ;)

Saludos

Activando los logs generales de MySQL sobre la marcha [tip]

Suponed que estamos programando algo que hace uso de una base de datos MySQL y que de repente comienza a comportarse de forma extraña, como podemos saber que peticiones hace, pues activando los logs generales así:

1
2
3
set global general_log_file = '/var/log/mysql/mysql.log';
-- El archivo puede ser cualquiera, no?
set global general_log = 1;

Lo malo es que hace falta ser root para poder hacerlo (y que el rendimiento cae, claro, no es algo que deba estar siempre activo).

Happy debugging.

Llevando la contraria sobre la sintaxis de arrays en C

Hola, hoy quería mostrar una pequeña ida de olla, hechadle un vistazo al siguiente código:

1
2
3
4
5
6
7
8
int main(int argc, char  **argv){ 
    char *x = "Hola, mundo!\n";
    int i;
    for (i = 0; i[x] != '\0';i++){
         putchar(i[x]);
    }
    return 0;
}

Compila, y hace lo que parece, pero tiene algo extraño... el orden variable [posición] está invertido, por que sigue funcionando.

Lo que pasa es que la posición de memoria se calcula como <dirección a la que apunta 'variable'> + (<posición> * <tamaño de una unidad de la variable>). Para los strings, el "tamaño de una unidad" es 1, así que queda como: <dirección a la que apunta variable> + <posición>, la suma es conmutativa, así que las posiciónes se pueden intercambiar.

ps: Obviamente esto no se debería hacer en código "real", por lo que pueda pasar si cambian los tipos de datos ;)

Saludos

Queda dicho

Leyendo Mimi and Eunice me encontré esto:

Mimi and Eunice

  • Te denuncio por robar los potenciales beneficios de mi cliente.
  • Eso tiene sentido potencial.
  • Aquí tienes cien mil potenciales dólares.

One liners (13): sacar un número de urandom en python

 

1
reduce(lambda x, y: x * 256 + y, map(lambda x: ord(x), os.urandom(1024)))
  • os.urandom(1024) Lee 1024 bytes de urandom.
  • map(lambda x: ord(x), ...) Convierte la cadena en un array con los valores de los caracteres.
  • reduce(lambda x, y: x * 256 + y, ...) Junta los bytes respetando el valor dado por la posición.

Recuperando un archivo eliminado pero abierto por otro proceso

Hoy, hace escasos 10 minutos estaba limpiando el disco, así que me dirijí a la carpeta de vídeos y... ¡raaaaca!, 20 archivos a alimentar la bestia del espacio libre. Pero al ver los archivos que habían sobrevivído a la limpieza sobrevino la preocupación sobre el paradero de uno de ellos, y es que quizá al fin y al cabo saltarse el paso de la papelera de reciclaje no fuera buena idea.

El problema era que me había cargado una película que tenía pensado compartir y con más bien pocos seeders, así que tocaba recuperarlo. Por suerte el transmission seguía abierto y seedeando, así que aún había esperanza, al fin y al cabo aún contaría con la información del archivo.

Los pasos a seguir fueron localizar primero el proceso

1
2
3
$ ps aux|grep transmission
1000      8546  0.0  0.0  12956   920 pts/5    S+   16:33   0:00 grep --color=auto transmission
1000     26127  5.6  2.3 402320 23784 ?        Ssl  11:54  15:40 transmission-gtk

Proceso 26127, lo siguiente sería saltar al lugar donde se guarda la información describiendo los archivos abiertos, este es /proc//fd/, es decir

1
2
3
4
5
$ cd /proc/26127/
$ ls fd/
0   11  14  17  2   22  25  28  30  33  36  39  41  44  47  5   52  55  8
1   12  15  18  20  23  26  29  31  34  37  4   42  45  48  50  53  6   9
10  13  16  19  21  24  27  3   32  35  38  40  43  46  49  51  54  7   96

A continuación toca buscar el que nos interesa, no podemos llevarnos todos (o sí, pero no es necesario :P)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ file fd/*
fd/0:  symbolic link to `/dev/null`
fd/1:  symbolic link to `/home/kenkeiras/.xsession-errors`
fd/10: broken symbolic link to `socket:[745308]`
fd/11: broken symbolic link to `anon_inode:[eventfd]`
[...]
fd/7:  broken symbolic link to `pipe:[745550]`
fd/8:  broken symbolic link to `anon_inode:[eventpoll]`
fd/9:  broken symbolic link to `socket:[745307]`
fd/96: broken symbolic link to `/home/kenkeiras/Vídeos/La.Estrategia.del.caracol.avi (deleted)`

El que nos interesa en este caso es entonces el último, hacemos caso omiso al '(deleted)' y guardaremos todo lo que contenga, en este caso al archivo 'save' (¡cuidado!, si ya existe un archivo con este nombre lo sobreescribirá).

1
$ cat fd/96 > ~/Vídeos/save

Cuando acabe y lo hayamos probado ya podemos renombrarlo

1
[~/Vídeos]$ mv save La.Estrategia.del.caracol.avi

Y ya está, como si no hubiera pasado nada.

...Aquí queda como apunte por si alguien se encuentra alguna vez en la misma situación ;)

Diccionarios a lo Javascript en Python

Los "diccionarios" en javascript tienen una propiedad curiosa, que se pueden manejar los elementos como si fuera un array índicando el índice (con una variable) o como si fuera un atributo del objeto:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
> var x = {}
> x
{}
> x.name = "joe"
'joe'
> x
{ name: 'joe' }
> x['name']
'joe'
> x.name
'joe'
>

En python los diccionarios no tienen esa propiedad, pero es fácil de hacer una clase que sí, apoyandose en que cada objeto tiene un diccionario interno, self.dict que almacena sus atributos, jugando con él (al menos si no nos metemos con los atributos que define la clase :P)...

Read more…

`true` o `false`, cuantas variaciónes son posibles?

true y false son comandos unix que al ejecutarlos simplemente se finalizan con código 0 y 1 respectivamente, algo que suele significar que hayan acabado correctamente (0) y haber fallado (no 0).

Cuanta diferencia puede haber entre el código en distintas implementaciones? No mucha verdad?, al fin y al cabo es más simple que un Hola mundo. Pues tiene gracia la cosa =) ...

(Sin ningún órden en concreto)

GNU: escrito en C, jugando con el preprocesador, ¿por que no?.
true.c (78 líneas)
false.c (2 líneas)
80 líneas físicas, SLOCCOUNT: 52

OpenBSD: en bash, un simple exit.
true.sh (3 líneas)
false.sh (3 líneas)
6 líneas físicas, SLOCCOUNT: 2

FreeBSD: en C, la mitad es licencia :P .
true.c (46 líneas)
false.c (46 líneas)
92 líneas físicas, SLOCCOUNT: 28

Solaris: en C, lo siento, no alcanzo a comprender a que viene _exit() y después return() ¿?.
true.c (41 líneas)
false.c (41 líneas)
82 líneas físicas, SLOCCOUNT: 16

Busybox: en C, no encontré un repo con los archivos en texto plano, hay que verlos aquí.
true.c (31 líneas)
false.c (31 líneas)
62 líneas físicas, SLOCCOUNT: 12

NetBSD: en bash, lo mínimo... o menos!
true.sh (2 líneas)
false.sh (2 líneas)
4 líneas físicas, SLOCCOUNT: 2

ps: hay una discusión sobre esto en r/programming.