Flymake or how to transform Emacs into an IDE

04/06/2009

Emacs doesn’t handle by default error detection “on the fly” like some IDEs, fortunately, there’s a minor mode for that: Flymake:

To install it, the only thing to do is loading flymake.el for instance by adding it in the site-lisp directory, and to add a new rule in the makefile of your C projects:

1
2
3
# Required by Flymake
check-syntax:
        $(CC) -W -Wall -pedantic -ansi -Wstrict-prototypes -fsyntax-only $(SRC) $(CFLAGS)

Let’s add some shortcuts in the .emacs file so as to quickly switch from one error to another.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
;; Flymake Mode                                                                                                                   
(defun next-flymake-error ()
  (interactive)
  (let ((err-buf nil))
    (condition-case err
        (setq err-buf (next-error-find-buffer))
      (error))
    (if err-buf
        (next-error)
      (progn
        (flymake-goto-next-error)
        (let ((err (get-char-property (point) 'help-echo)))
          (when err
            (message err)))))))
 
(global-set-key [f8] 'flymake-mode)
(global-set-key [f6] 'next-flymake-error)
(global-set-key [f7] 'flymake-goto-next-error)

With this configuration, to enable flymake-mode, just type [f8], and each time the file will be saved, flymake will recheck errors which will easily be accessed with [f6] and [f7].

aimxhaisse Programmation C, Snippet , , ,

SDL, Threads and FreeBSD

17/05/2009

I’ve recently played with SDL and its thread API which easily enables to port a program on several platforms, but it seems that by default on FreeBSD, a call to SDL_ThreadCreate() will result in a Bad system call (core dump).

(gdb) backtrace
#0  0x282db16b in ksem_init () from /lib/libc.so.7
#1  0x282d0a89 in sem_init () from /lib/libc.so.7
#2  0x280db420 in SDL_CreateSemaphore () from /usr/local/lib/libSDL-1.2.so.11
#3  0x2808ff12 in SDL_CreateThread () from /usr/local/lib/libSDL-1.2.so.11
(gdb)

One solution is to force SDL to use pthread’s library by adding some compilation flags:

-D_RENTRANT -D_THREAD_SAFE -lpthread

And everything goes well : )

aimxhaisse Programmation C , , , , ,

PHP-CGI: Une ligne de commande éditable avec GNU Readline

06/04/2009

PHP inclut la librairie C GNU Readline qui permet de construire très facilement une invite de commandes avec édition de ligne, complétion, historique, …, bref, tout un tas de super fonctionnalités très chiantes à faire à la main.

Avant tout, vérifiez que votre version de php possède bien l’extension readline:

1
2
$ php -r "readline("hello");"
hello

Si ca n’affiche pas “hello”, c’est qu’il faut probablement recompiler PHP avec readline:

1
2
3
$ ./configure --with-readline
$ make
$ make install
Première étape: prompt et récuperation des commandes

On veut afficher un prompt et récuperer la commande tapée, pour cela, on utilise la fonction readline qui prend en paramètre le prompt à afficher. Elle se charge de lire sur l’entrée standart tout en permettant des opérations d’édition (retour en arrière dans la ligne, insertion, …).

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
 
define('PROMPT', '$> ');
 
$input = '';
 
while ($input != 'exit')
{
      $input = readline(PROMPT);
      echo $input;
}
 
?>
Deuxième etape: l’historique

On veut maintenant pouvoir consulter un historique des commandes tapées, c’est très simple, il suffit d’ajouter à l’historique la commande tapée à l’aide de la fonction readline_add_history :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
 
define('PROMPT', '$> ');
 
$input = '';
 
while ($input != 'exit')
{
      $input = readline(PROMPT);
      echo $input;
      readline_add_history($input);
}
 
?>

On peut à présent naviguer dans l’historique a l’aide des flèches, comme dans un shell.

Troisième étape: interprétation des commandes

Imaginons un tableau associatif contenant le nom des commandes et la fonction à appeler lors de son appel:

1
2
3
4
5
$gl_commands = array('one' => 'function_one',
                                       'two'  => 'function_two',
                                       'three' => 'function_three',
                                       'four' => 'function_four',
                                       'five' => 'function_five');

Faisons en sorte qu’à chaque commande tapée, la fonction soit appelée:

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
<?php
 
define('PROMPT', '$> ');
 
$gl_commands = array('one' => 'function_one',
                                       'two'  => 'function_two',
                                       'three' => 'function_three',
                                       'four' => 'function_four',
                                       'five' => 'function_five');
 
$input = '';
 
while ($input != 'exit')
{
      $input = readline(PROMPT);
      $array = explode(" \t", $input);
      if (count($array) > 0)
      {
          foreach ($gl_commands as $key => $value)
            if ($array[0] == $key)
                $value($array);
      }
      readline_add_history($input);
}
 
?>

Ainsi, si l’utilisateur tape “one”, la fonction “function_one” est appelée.

Quatrième étape: la complétion

Pour finir, on aimerait faire comme les vrais shells et proposer une complétion lorsque l’utilisateur tape un debut de commande, là aussi, pas besoin de s’embêter, readline propose une autre fonction: readline_completion_function qui prend en paramètre une fonction à appeler, qui se chargera de renvoyer un tableau contenant les résultats à afficher.

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
<?php
 
define('PROMPT', '$> ');
 
$gl_commands = array('one' => 'function_one',
                                       'two'  => 'function_two',
                                       'three' => 'function_three',
                                       'four' => 'function_four',
                                       'five' => 'function_five');
 
function    treat_completion($input)
{
   global $gl_commands;
 
    $result = array(""); 
    if (!strlen($input))
    {
      foreach ($gl_commands as $key => $value)
        $result[] = $key;
      return $result;
    }
 
    foreach ($gl_commands as $key => $value)
    if (!strncmp($key, $input, strlen($input)))
            $result[] = $key;
    return $result;
}
 
$input = '';
readline_completion_function('treat_completion');
while ($input != 'exit')
{
      $input = readline(PROMPT);
      $array = explode(" \t", $input);
      if (count($array) > 0)
      {
          foreach ($gl_commands as $key => $value)
            if ($array[0] == $key)
                $value($array);
      }
      readline_add_history($input);
}
 
?>

A noter un petit bug rigolo dans readline_completion_function, si le tableau renvoyé par la fonction treat_command est un tableau vide, PHP fait un joli segmentation fault, d’où la necessité de mettre une chaine vide par default.

aimxhaisse php , ,

PHP: How to know if a request comes from AJAX

30/03/2009

It’s sometimes necessary to know if a request comes from AJAX, for instance not to to include the full template in the answer, but a lighter one (or none). Here’s a way to do it:

1
2
3
4
5
6
7
function      is_ajax_request()
{
     if (isset($_SERVER['HTTP_X_REQUESTED_WITH']))
         if (strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')
             return (TRUE);
    return (FALSE);
}

aimxhaisse Snippet , ,

How to create a PHP extension (1)

22/03/2009

There’s an easy way to embed C code into PHP by creating extensions. That’s the way external libraries such as GD or CURL are available in PHP. I’ll try to explain how it works and why it’s cool through sereval articles, this is the very first one.

The first thing to do is to get PHP sources, so as to be able to use some internal tools to make this task easier :

1
2
wget "http://www.php.net/get/php-5.2.9.tar.bz2/from/fr.php.net/mirror"
tar -xf php-5.2.9.tar.bz2

Now we are ready to play, let’s have a look at a directory that might interest us: ext, it already contains several extensions that are bundled by default with PHP. If we look at the structure of one extension, for instance GD, here is what we can see:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ cd php-5.2.9/ext/
$ ls -l gd/
total 252
-rw-r--r-- 1 seb seb  16475 2007-07-03 19:25 config.m4
-rw-r--r-- 1 seb seb   2136 2007-04-17 17:31 config.w32
-rw-r--r-- 1 seb seb    118 2003-06-15 22:16 CREDITS
-rw-r--r-- 1 seb seb 141580 2009-01-31 16:28 gd.c
-rw-r--r-- 1 seb seb   4985 2005-01-09 22:05 gdcache.c
-rw-r--r-- 1 seb seb   2866 2003-12-28 22:08 gdcache.h
-rw-r--r-- 1 seb seb   4855 2008-12-31 12:17 gd_ctx.c
-rw-r--r-- 1 seb seb  15665 2005-04-10 21:07 gd.dsp
-rw-r--r-- 1 seb seb  23054 2005-01-09 22:05 gdttf.c
-rw-r--r-- 1 seb seb    461 2000-02-26 04:20 gdttf.h
drwxr-xr-x 2 seb seb   4096 2009-02-25 16:39 libgd
-rw-r--r-- 1 seb seb   6158 2008-12-31 12:17 php_gd.h
drwxr-xr-x 2 seb seb   4096 2009-02-25 16:39 tests

The files config.m4 and config.w32 are used to compile the extension (config.m4 is for unix systems, config.w32 for windows). The folder tests contains some tests, these are performed during the `make test` operation, if you have time to waste, you can try it just for fun like this:

1
2
3
4
$ pwd
/tmp/php-5.2.9
$ ./configure
$ make test

Let’s go back to the ext/gd directory. The most important files here are php_gd.h and gd.c, which tells PHP how to deal with C functions. Internal functions are present in the libgd folder, they can’t be called directly by PHP, but they can be called by functions from gd.c. This is an easy way to export an existing library to PHP, you only have to register some wrappers without changing your library code.

To make easier the building of extensions, PHP provides a tool to do the borring stuff: ext_skel, we can find it in the ext folder, here is what happens when executing it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ ./ext_skel
 
./ext_skel --extname=module [--proto=file] [--stubs=file] [--xml[=file]]
           [--skel=dir] [--full-xml] [--no-help]
 
  --extname=module   module is the name of your extension
  --proto=file       file contains prototypes of functions to create
  --stubs=file       generate only function stubs in file
  --xml              generate xml documentation to be added to phpdoc-cvs
  --skel=dir         path to the skeleton directory
  --full-xml         generate xml documentation for a self-contained extension
                     (not yet implemented)
  --no-help          don't try to be nice and create comments in the code
                     and helper functions to test if the module compiled

As we are just hippies, we’ll only create an extension containing one function that prints a pyramid (yeah that’s useless) :

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
$ ./ext_skel --extname=pyramid
 
Creating directory pyramid
Creating basic files: config.m4 config.w32 .cvsignore pyramid.c php_pyramid.h CREDITS EXPERIMENTAL tests/001.phpt pyramid.php [done].
 
To use your new extension, you will have to execute the following steps:
 
1.  $ cd ..
2.  $ vi ext/pyramid/config.m4
3.  $ ./buildconf
4.  $ ./configure --[with|enable]-pyramid
5.  $ make
6.  $ ./php -f ext/pyramid/pyramid.php
7.  $ vi ext/pyramid/pyramid.c
8.  $ make
 
Repeat steps 3-6 until you are satisfied with ext/pyramid/config.m4 and
step 6 confirms that your module is compiled into PHP. Then, start writing
code and repeat the last two steps as often as necessary.
 
$ cd pyramid
$ ls -l
total 32
-rw-r--r-- 1 seb seb 2071 2009-03-21 18:55 config.m4
-rw-r--r-- 1 seb seb  303 2009-03-21 18:55 config.w32
-rw-r--r-- 1 seb seb    7 2009-03-21 18:55 CREDITS
-rw-r--r-- 1 seb seb    0 2009-03-21 18:55 EXPERIMENTAL
-rw-r--r-- 1 seb seb 2743 2009-03-21 18:55 php_pyramid.h
-rw-r--r-- 1 seb seb 5264 2009-03-21 18:55 pyramid.c
-rw-r--r-- 1 seb seb  505 2009-03-21 18:55 pyramid.php
drwxr-xr-x 2 seb seb 4096 2009-03-21 18:55 tests

ext_skel has prepared everything for us, we only have to edit pyramid.c and php_pyramid.h to be able to add our C code.

Let’s open php_pyramid.h, it already contains a list of defines, let’s add to it our function :

1
PHP_FUNCTION(pyramid);

Now in pyramid.c, we need to register our function in the global array “zend_function_entry“, so that PHP can include it in its core:

1
2
3
4
5
zend_function_entry pyramid_functions[] = {
    PHP_FE(confirm_pyramid_compiled,    NULL)       /* For testing, remove later. */
    PHP_FE(pyramid, NULL)
    {NULL, NULL, NULL}  /* Must be the last line in pyramid_functions[] */
};

That’s it, last step, add our pyramid() function, but we must pay attention to some rules:

  • to return a value, we have to use RETURN_XXXX where XXXX is the type of the value (BOOLEAN, STRING, …)
  • the function must be registered through the define PHP_FUNCTION(x) where x is the name of the function

Here is a first version that doesn’t handle parameters (perhaps I’ll talk of them in another article) :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
 
PHP_FUNCTION(pyramid)
{
    int         i;
    int         j;
    int         result;
    int         size;
 
    size = 10;
    result = 0;
    for (i = 1; i <= size; i++)
	{
            for (j = size; j > i; j--)
		result += printf(" ");
            for (j = 1; j < (i * 2); j++)
		result += printf("+");
            if (result)
		result += printf("\n");
	}
    RETURN_LONG(result);
}

It simply outputs a pyramid according to a size, and returns the character’s number printed. Now we have to compile it with PHP, for that we need to re-build the configure script so as to have the option –enable-pyramid:

1
2
3
4
$ pwd
/tmp/php-5.2.9
$ ./buildconf --force
$ ./configure --prefix=/tmp/php-devel --enable-pyramid

Finally, we can build it :

1
2
$ make
$ make install

Now we have a PHP version with our extension, let’s test it :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ pwd
/tmp/php-devel/bin
$ cat test.php
<?php
var_dump(pyramid());
?>
$ ./php test.php
         +
        +++
       +++++
      +++++++
     +++++++++
    +++++++++++
   +++++++++++++
  +++++++++++++++
 +++++++++++++++++
+++++++++++++++++++
int(145)

Yaw it works! I’ll talk in another article what’s so cool with a c-pyramid!

aimxhaisse Developpement Web, Programmation C, php , , ,