[GRASS-dev] Some native Windows changes committed

I've committed quite a few MINGW-related changes to CVS there now. I hope that in the long run they will make it easier to make further changes to port GRASS to native Windows, although in the meantime I'm slightly worried they might upset the way GRASS can be cross-compiled for Windows from Linux; that needs to be tested and I can't do that. More detail on the changes below.

Configure script and Makefiles

Make an effort to separate the use of variables GISBASE and ARCH_DISTDIR. GISBASE is the location of the temporary location and used when creating manpages - this path needs to be in a form understood by the native operating system (i.e. c:/grass/grassdata format is OK) for opening files etc. ARCH_DISTDIR is where things are installed during the build process and should be in Msys format (i.e. /c/grass/grassdata-style). GISBASE and ARCH_DISTDIR are used interchangeably in Makefiles and unfortunately GISBASE was used far too widely to make it feasible to change it so there is a new variable called RUN_GISBASE which is used when needed for the fake/demo location.

Originally I had it that the configure script tested if the pwd command accepts a -W option (for Windows-style pathnames) and if so used that to populate RUN_GISBASE. The Msys-style pathname goes into ARCH_DISTDIR and is used for everything else. But some pwds seem to return true even when used with a non-existent flag so I've changed that to a simple test for MINGW32.

Apart from that removed all explicit MinGW conditional stuff from Makefiles and configure script (I think). It means the shared library status and stuff is detected and configured for MINGW the same as for other systems now. MinGW conditionals were a bit mixed up with Cross-compiling conditionals but should be OK now. Wasn't too sure about the GDAL cross-compiling test - couldn't see what it did so have left it out for now. This might affect the stuff Radim does with the Windows GRASS/QGIS combination? I will try to fix it if anyone has any problems as a result of the changes.

Also removed the fmode.o stuff that was linked against all the Windows binaries. Saw some discussion about this on the list - binary mode? but everything is working fine for me without it so have left it out. If it needs to go back in it should go in some of the variables in the MinGW section in aclocal.m4 I think.

One thing that I'm really not too sure about is the code that creates a copy of the GRASS shared libraries with the GRASS version number (6.3.cvs) as part of the filename and then creates symlinks to those without the version number in the filename.
I'm not sure why it does this. It was disabled for Mingw but I re-enabled it for consistency. Maybe it leads to two copies of the libraries now if the Windows filesystem doesn't support symlinks. But can anybody say what it is really needed for?

Display lib and PNGdriver fixes

As discussed on the mailing list:
http://grass.itc.it/pipermail/grass-dev/2006-October/026963.html

Directory separator charcter stuff

New macros added to gis.h:
GRASS_DIRSEP and HOST_DIRSEP

The idea being that internal to GRASS, as much as possible we use GRASS_DIRSEP (which is /). HOST_DIRSEP and GRASS_DIRSEP are used by the following new functions:

/* paths.c */
int G_is_dirsep(char);
char *G_convert_dirseps_to_host(char *);
char *G_convert_dirseps_from_host(char *);

I've used G_convert_dirseps_to_host() in a few places already. Mostly when passing pathnames to the system() function.

In that file there is also
int G_mkdir(const char *);

and also I've changed G_clear_screen() so that it uses cls instead of clear on Windows.

In lib/gis/env.c I've removed all the MINGW stuff as discussed on the list.

datum and ellipsoid reading functions fixed to handle DOS line endings in text files and handle GRASS_PAGER environment variable in a cross-platform way.
g.parser changed to handle scripts with DOS line endings. {G_strip() --> G_chop()}

Started to abandon the use of G_system() because it hardcodes the use of /bin/sh. The way it stops Ctrl-C interrupts being passed to the parent calling program is useful in some situations but I'm not sure how to make it work on Windows.

Chane Init.sh to set GRASS_PAGER to "more" on Windows if other options fail - it should always be there.

Change to G_gets() to handle the carriage return-line feed sequence found on Windows. I hope this change is OK:

        eof = fgets(p,100,stdin);
        /* strip the EOL character */
- p[strlen(p)-1]='\0';
+ if( strlen(p) > 1 && p[strlen(p)-1] == '\n' && p[strlen(p)-2] == '\r' )
+ p[strlen(p)-2]='\0'; /* Handles DOS/Windows "\r\n" */
+ else
+ p[strlen(p)-1]='\0'; /* Handles Unix "\n" or old Mac "\r" */
        /* buf could be any length. Any overflow will occur here. */
        strcpy(buf,p);

In many places in modules we have to change calls to G_getl() to G_getl2() to enable them to handle Windows newline sequences - I wonder why G_getl() was not just changed in CVS and then it would fix everything? Changing G_gets() like this to catch everything seems to me like definitely the easiest solution.

lib/init and g.setproj

lib/init/mke_loc.c, set_data.c, g.setproj: fixes to system() calls etc. to make interactive location set-up work. Replace system("clear") call in Vasklib V_init() function with G_clear_screen(). Fixes problem discussed on list here:
http://grass.itc.it/pipermail/grass5/2006-October/026824.html

r.out.png

Updates to add a .png extension to the output file if it isn't there.

r.average

Fix so calling other modules with system() will work on Windows

Paul Kelly wrote:

One thing that I'm really not too sure about is the code that creates a
copy of the GRASS shared libraries with the GRASS version number (6.3.cvs)
as part of the filename and then creates symlinks to those without the
version number in the filename.
I'm not sure why it does this. It was disabled for Mingw but I re-enabled
it for consistency. Maybe it leads to two copies of the libraries now if
the Windows filesystem doesn't support symlinks. But can anybody say what
it is really needed for?

AFAICT, the version number doesn't have any real purpose.

The GRASS shared libraries aren't versioned in the sense that most
shared libraries are (i.e. with a trailing version number,
incorporated in the library's soname).

The main reason being that there isn't any point unless you increment
the version number whenever the ABI changes, and the GRASS development
process isn't really disciplined enough to do that.

Started to abandon the use of G_system() because it hardcodes the use of
/bin/sh.

G_system() specifically uses command.com on Windows:

  #ifdef __MINGW32__
      signal (SIGINT, SIG_DFL);
      _spawnl ( P_WAIT,
                "command",
                "command",
                "/c",
                command,
                NULL );
  #else

If anything, we should move towards G_system() rather than away from
it. That would allow various portability hacks to be localised in one
place rather than spread across modules.

Better still would be to implement G_spawn[_ex] on Windows and use
that instead. Those functions don't use a shell, which eliminates a
major source of potential problems.

The way it stops Ctrl-C interrupts being passed to the parent
calling program is useful in some situations but I'm not sure how to make
it work on Windows.

Note that system() behaves in the same way; at least, it's supposed
to. The comments for that function suggest that it was implemented as
a workaround for platforms with broken system() functions.

In many places in modules we have to change calls to G_getl() to G_getl2()
to enable them to handle Windows newline sequences - I wonder why G_getl()
was not just changed in CVS and then it would fix everything? Changing
G_gets() like this to catch everything seems to me like definitely the
easiest solution.

Probably because someone thought that there *might* be a situation
where the CR needed to be preserved, and didn't want to scan the
entire source tree to check.

lib/init and g.setproj

lib/init/mke_loc.c, set_data.c, g.setproj: fixes to system() calls etc. to
make interactive location set-up work. Replace system("clear") call in
Vasklib V_init() function with G_clear_screen(). Fixes problem discussed
on list here:

The vask library should just use the curses clear() function. The
"problem" with it not "working" on xterm isn't a problem, but a
feature.

Using system("clear") etc is a hack for programs which want to clear
the screen (and many of these probably *shouldn't* be clearing the
screen) but where using curses would be overkill.

--
Glynn Clements <glynn@gclements.plus.com>

On Fri, 3 Nov 2006, Paul Kelly wrote:

Also removed the fmode.o stuff that was linked against all the Windows binaries. Saw some discussion about this on the list - binary mode? but everything is working fine for me without it so have left it out. If it needs to go back in it should go in some of the variables in the MinGW section in aclocal.m4 I think.

I added that back in as I don't know the extent of the problems it fixes. Creating files in non-binary mode was the problem with lib/fonts/for_grass failing to compile anyway.

Just re-visiting some of these issues:

On Fri, 3 Nov 2006, Glynn Clements wrote:

Paul Kelly wrote:

Started to abandon the use of G_system() because it hardcodes the use of
/bin/sh.

G_system() specifically uses command.com on Windows:

  #ifdef __MINGW32__
      signal (SIGINT, SIG_DFL);
      _spawnl ( P_WAIT,
                "command",
                "/c",
                command,
                NULL );
  #else

If anything, we should move towards G_system() rather than away from
it. That would allow various portability hacks to be localised in one
place rather than spread across modules.

OK that actually didn't work. I changed two things:
- Use cmd.exe (Windows command shell) instead of command.com (old DOS shell, the last time I looked in detail seemed to be permanently frozen in a similar state to whatever the current version of DOS was when Windows NT was first released)
- Use _spawnlp instead of _spawnl. _spawnl requires the full path to the command being executed (cmd.exe) but this wasn't being given. _spawnlp looks in the PATH.

After those two changes, G_system() actually seems to work on Windows so I'll commit them in a while if nobody objects.

In many places in modules we have to change calls to G_getl() to G_getl2()
to enable them to handle Windows newline sequences - I wonder why G_getl()
was not just changed in CVS and then it would fix everything? Changing
G_gets() like this to catch everything seems to me like definitely the
easiest solution.

Probably because someone thought that there *might* be a situation
where the CR needed to be preserved, and didn't want to scan the
entire source tree to check.

Yes, although I keep coming across more situations. I'm almost tempted to replace the functionality G_getl() with a call to G_getl2(); I keep finding it causing bugs in obscure places where text files get written with DOS/Windows line endings and then can't be read. Feel it might be better to just globally replace all occurences and deal with any bugs resulting from that rather than changing over on a case-by-case basis.