Upon doing some inspection of apache 2.x, it seems that me making a SysV
Windows .DLL for PostgreSQL, while a cool project, would be unnecessary.

The APR (Apache Portable Runtime) seems to have all the necessary support. The
problem is that it has its own API.

We should find a way to extract the APR out of apache and make it a library
within PostgreSQL. A quick look at the license seems to indicate this is OK.
Should we notify the Apache guys just to be polite?

It looks like the APR is pretty analogous to SysV with a few changes, so it
should not be too hard to code it into PostgrsSQL.

Sat, 04 May 2002 09:46:05 -0400
mlw <markw@mohawksoft.com>
Native Windows, Apache Portable Runtime
mlw wrote:
> 
> Upon doing some inspection of apache 2.x, it seems that me making a SysV
> Windows .DLL for PostgreSQL, while a cool project, would be unnecessary.
> 
> The APR (Apache Portable Runtime) seems to have all the necessary support. The
> problem is that it has its own API.
> 
> We should find a way to extract the APR out of apache and make it a library
> within PostgreSQL. A quick look at the license seems to indicate this is OK.
> Should we notify the Apache guys just to be polite?

Definitely.  They make also be able to offer some tips and guidance
(i.e. there may already be a way of splitting it off easy, etc), but
we'll never know if we don't say hello.  (Hey, that rhymes!)

:-)

Regards and best wishes,

Justin Clift

 
> It looks like the APR is pretty analogous to SysV with a few changes, so it
> should not be too hard to code it into PostgrsSQL.
> 
> ---------------------------(end of broadcast)---------------------------
> TIP 6: Have you searched our list archives?
> 
> http://archives.postgresql.org

-- 
"My grandfather once told me that there are two kinds of people: those
who work and those who take the credit. He told me to try to be in the
first group; there was less competition there."
   - Indira Gandhi

Sun, 05 May 2002 00:21:41 +1000
Justin Clift <justin@postgresql.org>
Re: Native Windows, Apache Portable Runtime
Justin Clift wrote:
> 
> mlw wrote:
> >
> > Upon doing some inspection of apache 2.x, it seems that me making a SysV
> > Windows .DLL for PostgreSQL, while a cool project, would be unnecessary.
> >
> > The APR (Apache Portable Runtime) seems to have all the necessary support. The
> > problem is that it has its own API.
> >
> > We should find a way to extract the APR out of apache and make it a library
> > within PostgreSQL. A quick look at the license seems to indicate this is OK.
> > Should we notify the Apache guys just to be polite?
> 
> Definitely.  They make also be able to offer some tips and guidance
> (i.e. there may already be a way of splitting it off easy, etc), but
> we'll never know if we don't say hello.  (Hey, that rhymes!)

It is so easy to extract he APR it is silly. They even describe how in the
README.dev. Except for NIH, I can't see any reason not to use t.

Sat, 04 May 2002 10:22:42 -0400
mlw <markw@mohawksoft.com>
Re: Native Windows, Apache Portable Runtime
mlw <markw@mohawksoft.com> writes:
> Upon doing some inspection of apache 2.x, it seems that me making a SysV
> Windows .DLL for PostgreSQL, while a cool project, would be unnecessary.

> The APR (Apache Portable Runtime) seems to have all the necessary support.

Does it?  AFAICT they intend to provide mutexes not counting semaphores.
Their implementation atop SysV semaphores would work the way we need
(ie, remember multiple unlocks arriving before a lock operation), but
I'm unclear on whether any of the other ones would.

			regards, tom lane

Sat, 04 May 2002 12:18:24 -0400
Tom Lane <tgl@sss.pgh.pa.us>
Re: Native Windows, Apache Portable Runtime 
Tom Lane wrote:
> 
> mlw <markw@mohawksoft.com> writes:
> > Upon doing some inspection of apache 2.x, it seems that me making a SysV
> > Windows .DLL for PostgreSQL, while a cool project, would be unnecessary.
> 
> > The APR (Apache Portable Runtime) seems to have all the necessary support.
> 
> Does it?  AFAICT they intend to provide mutexes not counting semaphores.
> Their implementation atop SysV semaphores would work the way we need
> (ie, remember multiple unlocks arriving before a lock operation), but
> I'm unclear on whether any of the other ones would.

Ok, you got me, they do not provide a semaphore, only mutexes. We should be
able to use APR in PostgreSQL, I'll implement a semaphore directory for Windows
and UNIX. Someone will have to handle the Netware, beos and OS/2.
 
(I may be able to do the OS/2 stuff, but it has, in fact, been 6 years since I
even looked at OS/2 in any form.)

We could provide a PGSemaphore based on an APR mutex and a counter, but I'm not
sure of the performance impact. We may want to implement a "generic" semaphore
like this and one optimized for platforms which we have development resources.

Sat, 04 May 2002 12:28:43 -0400
mlw <markw@mohawksoft.com>
Re: Native Windows, Apache Portable Runtime
mlw <markw@mohawksoft.com> writes:
> We could provide a PGSemaphore based on an APR mutex and a counter,
> but I'm not sure of the performance impact. We may want to implement a
> "generic" semaphore like this and one optimized for platforms which we
> have development resources.

Once we have the internal API redone, it should be fairly easy to
experiment with alternatives like that.

I'm planning to work on this today (need a break from thinking about
schemas ;-)).  I'll run with the API I sketched yesterday, since no one
objected.  Although I'm not planning on doing anything to the API of the
shared-mem routines, I'll break them out into a replaceable file as
well, just in case anyone wants to try a non-SysV implementation.
What I plan to do is:

1. Replace include/storage/ipc.h with "pg_sema.h" and "pg_shmem.h"
containing the hopefully-platform-independent API definitions, plus
ifdef'd sections along the lines of

	#ifdef USE_SYSV_SEMAPHORES

	typedef struct PGSemaphoreData {
		int id;
		int num;
	} PGSemaphoreData;

	typedef PGSemaphoreData *PGSemaphore;

	#endif

AFAICS at the moment, only this typedef needs to vary across different
implementations as far as the header is concerned.

2. Break out the SysV-dependent code into backend/port/sysv_sema.c
and backend/port/sysv_shmem.c.  storage/ipc/ipc.c will either go away
completely or get lots smaller.

3. Extend configure to define the correct USE_foo_SEMAPHORES symbol
in pg_config.h, and to symlink the correct implementation files to
backend/port/pg_sema.c and backend/port/pg_shmem.c.  These two "files"
will be the ones compiled and linked into the backend.

I'm expecting that configure will default to use SysV semas and shared
memory unless told differently by the "template" script selected for
the platform.  For instance src/template/darwin might contain something
like
	USE_DARWIN_SEMAPHORES=1
	SEMA_IMPLEMENTATION=src/backend/port/darwin/sem.c
to override the default semaphore implementation.  Later we might want
some more-dynamic way of configuring the sema type, but this seems like
enough to get started.

Comments, better ideas?

			regards, tom lane

Sat, 04 May 2002 12:56:49 -0400
Tom Lane <tgl@sss.pgh.pa.us>
Re: Native Windows, Apache Portable Runtime 
    Hi Tom,

    I'll do the necessary change for the BeOS port. On a first look, this
will greatly simplify the semaphore layer as the new API map quite well with
the BeOS one.

    I find the semaphore API quite clean but have some question on the
Shared memory one. The Id's passed to PGSharedMemoryIsInUse aren't clear to
me. How id1 and id1 are related to the port parameter of
PGSharedMemoryCreate ?
    Also why not do the header fillup outside of PGSharedMemoryCreate ?


    What about using an API similar to the sema one :
        PGShmemHeader * PGSharedMemoryCreate(PGShmem shmem,uint32 size, bool
makePrivate, int memKey);
        bool PGSharedMemoryIsInUse(PGShmem shmem);

        where PGShmem is an implementation definded struct (including header
datas).


    On a side note, after these API change, Beos will still need an Hack for
shared memory, because all shared memory segments are in copy on write mode
in the forked process. One solution could be to have an explicit attach call
in the forked process :
        PGSharedMemoryAttach(PGShmem shmem);

    This could be a no op for SYSV shmem.

     This will allow the following calls for each fork to removed :

    beos_before_backend_startup
    beos_backend_startup_failed
    beos_backend_startup

                    cyril


----- Original Message -----
From: "Tom Lane" <tgl@sss.pgh.pa.us>
To: "mlw" <markw@mohawksoft.com>
Cc: "PostgreSQL-development" <pgsql-hackers@postgresql.org>
Sent: Saturday, May 04, 2002 6:56 PM
Subject: Re: [HACKERS] Native Windows, Apache Portable Runtime


> mlw <markw@mohawksoft.com> writes:
> > We could provide a PGSemaphore based on an APR mutex and a counter,
> > but I'm not sure of the performance impact. We may want to implement a
> > "generic" semaphore like this and one optimized for platforms which we
> > have development resources.
>
> Once we have the internal API redone, it should be fairly easy to
> experiment with alternatives like that.
>
> I'm planning to work on this today (need a break from thinking about
> schemas ;-)).  I'll run with the API I sketched yesterday, since no one
> objected.  Although I'm not planning on doing anything to the API of the
> shared-mem routines, I'll break them out into a replaceable file as
> well, just in case anyone wants to try a non-SysV implementation.
> What I plan to do is:
>
> 1. Replace include/storage/ipc.h with "pg_sema.h" and "pg_shmem.h"
> containing the hopefully-platform-independent API definitions, plus
> ifdef'd sections along the lines of
>
> #ifdef USE_SYSV_SEMAPHORES
>
> typedef struct PGSemaphoreData {
> int id;
> int num;
> } PGSemaphoreData;
>
> typedef PGSemaphoreData *PGSemaphore;
>
> #endif
>
> AFAICS at the moment, only this typedef needs to vary across different
> implementations as far as the header is concerned.
>
> 2. Break out the SysV-dependent code into backend/port/sysv_sema.c
> and backend/port/sysv_shmem.c.  storage/ipc/ipc.c will either go away
> completely or get lots smaller.
>
> 3. Extend configure to define the correct USE_foo_SEMAPHORES symbol
> in pg_config.h, and to symlink the correct implementation files to
> backend/port/pg_sema.c and backend/port/pg_shmem.c.  These two "files"
> will be the ones compiled and linked into the backend.
>
> I'm expecting that configure will default to use SysV semas and shared
> memory unless told differently by the "template" script selected for
> the platform.  For instance src/template/darwin might contain something
> like
> USE_DARWIN_SEMAPHORES=1
> SEMA_IMPLEMENTATION=src/backend/port/darwin/sem.c
> to override the default semaphore implementation.  Later we might want
> some more-dynamic way of configuring the sema type, but this seems like
> enough to get started.
>
> Comments, better ideas?
>
> regards, tom lane
>
> ---------------------------(end of broadcast)---------------------------
> TIP 6: Have you searched our list archives?
>
> http://archives.postgresql.org


Sun, 5 May 2002 21:24:44 +0200
"Cyril VELTER" <cyril.velter@libertysurf.fr>
Re: Native Windows, Apache Portable Runtime 
On Sat, 2002-05-04 at 21:56, Tom Lane wrote:
> mlw <markw@mohawksoft.com> writes:
> > We could provide a PGSemaphore based on an APR mutex and a counter,
> > but I'm not sure of the performance impact. We may want to implement a
> > "generic" semaphore like this and one optimized for platforms which we
> > have development resources.
> 
> Once we have the internal API redone, it should be fairly easy to
> experiment with alternatives like that.
> 
> I'm planning to work on this today (need a break from thinking about
> schemas ;-)).  I'll run with the API I sketched yesterday, since no one
> objected.  Although I'm not planning on doing anything to the API of the
> shared-mem routines, I'll break them out into a replaceable file as
> well, just in case anyone wants to try a non-SysV implementation.

Would it be too hard to make them macros, so those which dont need
shared mem at all (embedded single-user systems) could avoid the
performance impact altogether.

----------------
Hannu



06 May 2002 00:31:04 +0500
Hannu Krosing <hannu@krosing.net>
Re: Native Windows, Apache Portable Runtime
"Cyril VELTER" <cyril.velter@libertysurf.fr> writes:
>     I find the semaphore API quite clean but have some question on the
> Shared memory one. The Id's passed to PGSharedMemoryIsInUse aren't clear to
> me. How id1 and id1 are related to the port parameter of
> PGSharedMemoryCreate ?

You can define 'em however you want.  For SysV shmem they are the shmem
key and id.

>     Also why not do the header fillup outside of PGSharedMemoryCreate ?

Well, (a) I wasn't really concerned about defining an all-new API for
shmem, and (b) I think the header is largely dependent on the semantics
of SysV shmem anyway.  A different shmem implementation might need
different fields in there.

>     What about using an API similar to the sema one :
>         PGShmemHeader * PGSharedMemoryCreate(PGShmem shmem,uint32 size, bool
> makePrivate, int memKey);
>         bool PGSharedMemoryIsInUse(PGShmem shmem);

How does that solve the problem of determining whether a *previously*
created shmem block is still in use?  The point here is to be able to
trace the connection from a data directory to active backends via their
connections to a shared memory block --- take a look at
RecordSharedMemoryInLockFile, which is the flip side of
SharedMemoryIsInUse.

>     On a side note, after these API change, Beos will still need an Hack for
> shared memory, because all shared memory segments are in copy on write mode
> in the forked process. One solution could be to have an explicit attach call
> in the forked process :
>         PGSharedMemoryAttach(PGShmem shmem);

No strong feelings about this --- it looks like the same BeOS-specific
hack under a different name ;-)

>      This will allow the following calls for each fork to removed :

>     beos_before_backend_startup
>     beos_backend_startup_failed
>     beos_backend_startup

How so?  If those calls were needed before, why won't all three still
be needed?

			regards, tom lane

Sun, 05 May 2002 19:21:31 -0400
Tom Lane <tgl@sss.pgh.pa.us>
Re: Native Windows, Apache Portable Runtime 
On Sat, 4 May 2002, mlw wrote:

> Upon doing some inspection of apache 2.x, it seems that me making a SysV
> Windows .DLL for PostgreSQL, while a cool project, would be unnecessary.
>
> The APR (Apache Portable Runtime) seems to have all the necessary support. The
> problem is that it has its own API.
>
> We should find a way to extract the APR out of apache and make it a library
> within PostgreSQL. A quick look at the license seems to indicate this is OK.
> Should we notify the Apache guys just to be polite?
>
> It looks like the APR is pretty analogous to SysV with a few changes, so it
> should not be too hard to code it into PostgrsSQL.

This is the wrong route to take ... I've already discussed it with the
Apache folk, and, yes, we could include it into our tree, but I would
*really* like to avoid that ... main reason, there is an active group over
there working on this API and I'd rather not have to maintain a second
version of it ...

As is my intention, I'm going to pull out the shared memory stuff that we
are currently using and putting it into a central file, with a pg_*
associated command to match it ... this way, if someone wants to use the
'standard shared memory' that comes with their OS, they can ... if someone
wants to use libapr.*, which I've been informed will be released as a
seperate package from Apache once v1.0 of it is available (and associated
.dll's), then they will have that option too ...





Mon, 6 May 2002 00:41:00 -0300 (ADT)
"Marc G. Fournier" <scrappy@hub.org>
Re: Native Windows, Apache Portable Runtime

Well, I guess that just saved *me* alot of work ... thanks ...

On Sat, 4 May 2002, Tom Lane wrote:

> mlw <markw@mohawksoft.com> writes:
> > We could provide a PGSemaphore based on an APR mutex and a counter,
> > but I'm not sure of the performance impact. We may want to implement a
> > "generic" semaphore like this and one optimized for platforms which we
> > have development resources.
>
> Once we have the internal API redone, it should be fairly easy to
> experiment with alternatives like that.
>
> I'm planning to work on this today (need a break from thinking about
> schemas ;-)).  I'll run with the API I sketched yesterday, since no one
> objected.  Although I'm not planning on doing anything to the API of the
> shared-mem routines, I'll break them out into a replaceable file as
> well, just in case anyone wants to try a non-SysV implementation.
> What I plan to do is:
>
> 1. Replace include/storage/ipc.h with "pg_sema.h" and "pg_shmem.h"
> containing the hopefully-platform-independent API definitions, plus
> ifdef'd sections along the lines of
>
> 	#ifdef USE_SYSV_SEMAPHORES
>
> 	typedef struct PGSemaphoreData {
> 		int id;
> 		int num;
> 	} PGSemaphoreData;
>
> 	typedef PGSemaphoreData *PGSemaphore;
>
> 	#endif
>
> AFAICS at the moment, only this typedef needs to vary across different
> implementations as far as the header is concerned.
>
> 2. Break out the SysV-dependent code into backend/port/sysv_sema.c
> and backend/port/sysv_shmem.c.  storage/ipc/ipc.c will either go away
> completely or get lots smaller.
>
> 3. Extend configure to define the correct USE_foo_SEMAPHORES symbol
> in pg_config.h, and to symlink the correct implementation files to
> backend/port/pg_sema.c and backend/port/pg_shmem.c.  These two "files"
> will be the ones compiled and linked into the backend.
>
> I'm expecting that configure will default to use SysV semas and shared
> memory unless told differently by the "template" script selected for
> the platform.  For instance src/template/darwin might contain something
> like
> 	USE_DARWIN_SEMAPHORES=1
> 	SEMA_IMPLEMENTATION=src/backend/port/darwin/sem.c
> to override the default semaphore implementation.  Later we might want
> some more-dynamic way of configuring the sema type, but this seems like
> enough to get started.
>
> Comments, better ideas?
>
> 			regards, tom lane
>
> ---------------------------(end of broadcast)---------------------------
> TIP 6: Have you searched our list archives?
>
> http://archives.postgresql.org
>


Mon, 6 May 2002 00:43:02 -0300 (ADT)
"Marc G. Fournier" <scrappy@hub.org>
Re: Native Windows, Apache Portable Runtime 
"Marc G. Fournier" <scrappy@hub.org> writes:
> Well, I guess that just saved *me* alot of work ... thanks ...

Uh, not yet.  Don't you still need a semaphore implementation that
works on Windows?

			regards, tom lane

Mon, 06 May 2002 00:00:46 -0400
Tom Lane <tgl@sss.pgh.pa.us>
Re: Native Windows, Apache Portable Runtime 
Tom Lane wrote:
> 
> "Marc G. Fournier" <scrappy@hub.org> writes:
> > Well, I guess that just saved *me* alot of work ... thanks ...
> 
> Uh, not yet.  Don't you still need a semaphore implementation that
> works on Windows?
> 

I have a LOT of experience with Windows development. You tell me what you want
and I'll write it. This is not an issue.

Mon, 06 May 2002 00:08:24 -0400
mlw <markw@mohawksoft.com>
Re: Native Windows, Apache Portable Runtime
> "Cyril VELTER" <cyril.velter@libertysurf.fr> writes:
> >     Also why not do the header fillup outside of PGSharedMemoryCreate ?
>
> Well, (a) I wasn't really concerned about defining an all-new API for
> shmem, and (b) I think the header is largely dependent on the semantics
> of SysV shmem anyway.  A different shmem implementation might need
> different fields in there.

    Are the PGShmemHeader fields only used by PGSharedMemoryCreate ?

>
> >     What about using an API similar to the sema one :
> >         PGShmemHeader * PGSharedMemoryCreate(PGShmem shmem,uint32 size,
bool
> > makePrivate, int memKey);
> >         bool PGSharedMemoryIsInUse(PGShmem shmem);
>
> How does that solve the problem of determining whether a *previously*
> created shmem block is still in use?  The point here is to be able to
> trace the connection from a data directory to active backends via their
> connections to a shared memory block --- take a look at
> RecordSharedMemoryInLockFile, which is the flip side of
> SharedMemoryIsInUse.
>

    Ok, I overlooked that, my proposal for PGSharedMemoryIsInUse doesn't
make sense (and it doesn't matter on Beos because shared mem segments are
automaticaly reaped at the end of the process).


> >     On a side note, after these API change, Beos will still need an Hack
for
> > shared memory, because all shared memory segments are in copy on write
mode
> > in the forked process. One solution could be to have an explicit attach
call
> > in the forked process :
> >         PGSharedMemoryAttach(PGShmem shmem);
>
> No strong feelings about this --- it looks like the same BeOS-specific
> hack under a different name ;-)
>
> >      This will allow the following calls for each fork to removed :
>
> >     beos_before_backend_startup
> >     beos_backend_startup_failed
> >     beos_backend_startup
>
> How so?  If those calls were needed before, why won't all three still
> be needed?


    In the current hack, I've to iterate over all sharedmem segments (system
wide) to find the original one by name. There is a race condition here if
several backend are starting at the same time. beos_before_backend_startup
beos_backend_startup_failed acquire / release a semaphore which prevent
several fork at the same time.


    With the proposed API, I would be able to store some specific info about
the shared mem segment (the beos handle of the original one created by
postmaster) which will be accessible to the backend after the fork. This
will remove the race condition and the need of the three calls. This will
also improve mutliple backend startup time cause now forks are serialized.

    This was just a though, current implementation works fine.


            cyril




Mon, 6 May 2002 10:21:37 +0200
"Cyril VELTER" <cyril.velter@libertysurf.fr>
Re: Native Windows, Apache Portable Runtime 
On Mon, 6 May 2002, Tom Lane wrote:

> "Marc G. Fournier" <scrappy@hub.org> writes:
> > Well, I guess that just saved *me* alot of work ... thanks ...
>
> Uh, not yet.  Don't you still need a semaphore implementation that
> works on Windows?

Yup ... next steps, but I believe that is what Mark is working on ...




Mon, 6 May 2002 08:59:17 -0300 (ADT)
"Marc G. Fournier" <scrappy@hub.org>
Re: Native Windows, Apache Portable Runtime 
"Cyril VELTER" <cyril.velter@libertysurf.fr> writes:
>     Are the PGShmemHeader fields only used by PGSharedMemoryCreate ?

Other than totalsize and freeoffset, I believe so.  I see no reason
that a particular port couldn't stick different fields in there if it
had a mind to.

>> How does that solve the problem of determining whether a *previously*
>> created shmem block is still in use?

>     Ok, I overlooked that, my proposal for PGSharedMemoryIsInUse doesn't
> make sense (and it doesn't matter on Beos because shared mem segments are
> automaticaly reaped at the end of the process).

Well, SharedMemoryIsInUse is *not* just about ensuring that the shared
memory gets reaped.  The point is to ensure that you can't start a new
postmaster until the last old backend is gone.  (Consider situations
where the parent postmaster process crashes, or perhaps is kill -9'd
by a careless DBA, but there are still active backends.  We want to
detect that situation and ensure that a new postmaster will refuse to
start.)

>> How so?  If those calls were needed before, why won't all three still
>> be needed?

>     In the current hack, I've to iterate over all sharedmem segments (system
> wide) to find the original one by name. There is a race condition here if
> several backend are starting at the same time. beos_before_backend_startup
> beos_backend_startup_failed acquire / release a semaphore which prevent
> several fork at the same time.

Does keeping the shmem segment name around solve that?  Seems like you
don't need a PGShmemHeader field for that; just store it in a static
variable.

			regards, tom lane

Mon, 06 May 2002 09:36:02 -0400
Tom Lane <tgl@sss.pgh.pa.us>
Re: Native Windows, Apache Portable Runtime 
> Well, SharedMemoryIsInUse is *not* just about ensuring that the shared
> memory gets reaped.  The point is to ensure that you can't start a new
> postmaster until the last old backend is gone.  (Consider situations
> where the parent postmaster process crashes, or perhaps is kill -9'd
> by a careless DBA, but there are still active backends.  We want to
> detect that situation and ensure that a new postmaster will refuse to
> start.)

    Yes I remember that now (the current code do that correctly).

>
> >> How so?  If those calls were needed before, why won't all three still
> >> be needed?
>
> >     In the current hack, I've to iterate over all sharedmem segments
(system
> > wide) to find the original one by name. There is a race condition here
if
> > several backend are starting at the same time.
beos_before_backend_startup
> > beos_backend_startup_failed acquire / release a semaphore which prevent
> > several fork at the same time.
>
> Does keeping the shmem segment name around solve that?  Seems like you
> don't need a PGShmemHeader field for that; just store it in a static
> variable.

No the name is not enough, I need the beos handle for each shared mem
segment. I'll try to find a cleaner solution using existing API.


            cyril


Mon, 6 May 2002 19:51:58 +0200
"Cyril VELTER" <cyril.velter@libertysurf.fr>
Re: Native Windows, Apache Portable Runtime 
On Mon, 6 May 2002, mlw wrote:

> Tom Lane wrote:
> >
> > "Marc G. Fournier" <scrappy@hub.org> writes:
> > > Well, I guess that just saved *me* alot of work ... thanks ...
> >
> > Uh, not yet.  Don't you still need a semaphore implementation that
> > works on Windows?
> >
>
> I have a LOT of experience with Windows development. You tell me what you want
> and I'll write it. This is not an issue.

appropriate sem* replacements in Windows?



Mon, 6 May 2002 20:20:09 -0300 (ADT)
"Marc G. Fournier" <scrappy@hub.org>
Re: Native Windows, Apache Portable Runtime