Archive for March, 2007

I was unable to find any mention of a function for copying files in the Chicken documentation. However, the Chicken source does have a copy-file function in chicken-setup.scm. It is somewhat brittle as it uses the shell, relying on the fact that you are running the function from the same shell you used to build Chicken.

$ find . | egrep '.scm$' | xargs grep 'copy-file'

(define *windows-shell* (memq *windows* '(msvc mingw32)))
(define *copy-command* (if *windows-shell* 'copy "cp -r"))

(define (copy-file from to)
  (let ((from (if (pair? from) (car from) from))
	(to (if (pair? from) (make-pathname to (cadr from)) to)) )
    (ensure-directory to)
    (run (,*copy-command* ,(quotewrap from) ,(quotewrap to)) ) ) )

A solution with the Win32 function CopyFile would be more robust but would probably need some work to do a recursive copy. I don’t need the recursive functionality and fortunately, it is straight-forward to wrap using Chicken’s foreign function interface. I created a file called win32_lib.impl to keep all the syntax highlighting working.

#include "Windows.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char* w32_error_message()
    char* buffer;

                  | FORMAT_MESSAGE_FROM_SYSTEM
                  (LPTSTR) &buffer,
                  0, NULL);

    buffer[strlen(buffer) - 2] = '';
    return buffer;

int w32_copy_file(const char* file1,
                  const char* file2,
                  int fail_if_exists)
    return CopyFile(file1, file2, fail_if_exists);

The wrapper from Chicken is trivial:
(define-extension win32_lib)

#include "win32_lib.impl"

(define w32-error-message
  (foreign-lambda c-string* "w32_error_message"))

(define w32-copy-file
  (foreign-lambda int "w32_copy_file" c-string c-string int))

The makefile takes care of making a .dll so we can load it into csi (the Chicken REPL) for testing purposes.

all: win32_lib.dll prog.exe

prog.exe: main.scm win32_lib.scm win32_lib.impl
	csc -c main.scm
	csc -c win32_lib.scm
	csc -o prog.exe main.o win32_lib.o

win32_lib.dll: win32_lib.scm
	csc win32_lib.scm -dynamic -dll

	rm *.o prog.exe win32_lib.dll

And finally the test harness:

(declare (uses win32_lib))

(define args (cdr (argv)))
(display args)

(define (wrap-copy-file file1 file2)
  (let ((r (w32-copy-file (car args) (cadr args) 1)))
    (if (= r 0)
        (printf "[~a]~n" (w32-error-message))
        (printf "Success!~n"))))

(wrap-copy-file (car args) (cadr args))

Read Full Post »

I had the pleasure of setting up a new Win32 development environment recently. After installing emacs, the first thing to do was to get MinGW and MSYS installed for the C and C++ compilers and a semi-reasonable shell.

MinGW can be downloaded here but it is slightly difficult to see the latest files for downloading. I think it would be better if they put clear links to at least the latest versions of MinGW and MSYS at the top of the page. Anyway, here they are (as of today – 4th March 2007).

I don’t really want to code in C or C++ outside of work if I can really help it, so the next thing to do is to install a friendlier language. I’m quite comfortable with scheme so I’ll use Chicken for the ability to create Win32 executables although in reality there are many acceptable alternatives here. Chicken is available here and it requires CMake to build.

As of version 2.6, Chicken seems to have improved significantly since I last looked at it. Only a C compiler is required to build it rather than an existing Chicken compiler which makes the bootstrapping procedure somewhat easier. I installed it to c:/chicken, set the PATH and CHICKEN_HOME environment variables and compiled my first test program on this machine. Very nice and straightforward.

Read Full Post »