help-libidn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: unistd.h include in stringprep.h


From: Simon Josefsson
Subject: Re: unistd.h include in stringprep.h
Date: Wed, 30 Nov 2011 15:56:40 +0100
User-agent: Gnus/5.110018 (No Gnus v0.18) Emacs/24.0.91 (gnu/linux)

Bruno Haible <address@hidden> writes:

>> The #include happens in an installed header file, so the gnulib module
>> wouldn't help here.
>
> Oh, I see. A file that contains public API of libidn.

Right.

>> However, the only reason we include unistd.h is in order to get ssize_t.
>
> ssize_t on MSVC 9 was handled in
> <http://lists.gnu.org/archive/html/bug-gnulib/2011-09/msg00200.html>.
>
> In summary, to get ssize_t defined, you need the 'ssize_t' module or
> - equivalent - an invocation of gt_TYPE_SSIZE_T.

I don't see how this resolves anything?  It resolves the problem inside
the project, but for any external code that #include's my header file,
they will need to define an ssize_t themselves which is sub-optimal.

Is there really no ssize_t anywhere in MSVC9?  There appears to be a
type SSIZE_T though:

http://msdn.microsoft.com/en-us/library/aa383751%28v=VS.85%29.aspx#SSIZE_T

I can find people using ssize_t in their MSVC++ code though:

http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/e712a103-03af-4f62-b456-f550ecb9bf07

>
>> GnuTLS generates its header files that contains this:
>> 
>> /* Get ssize_t. */
>> #ifndef HAVE_SSIZE_T
>> #define HAVE_SSIZE_T
>> /* *INDENT-OFF* */
>> @DEFINE_SSIZE_T@
>> /* *INDENT-ON* */
>> #endif
>> 
>> and then have a configure.ac check looking like this:
>> 
>> AC_CHECK_TYPE(ssize_t,
>>   [
>>     DEFINE_SSIZE_T="#include <sys/types.h>"
>>     AC_SUBST(DEFINE_SSIZE_T)
>>   ], [
>>     AC_DEFINE([NO_SSIZE_T], 1, [no ssize_t type was found])
>>     DEFINE_SSIZE_T="typedef int ssize_t;"
>>     AC_SUBST(DEFINE_SSIZE_T)
>>   ], [
>>     #include <sys/types.h>
>>   ])
>
> It is not safe to define a type like 'ssize_t' in a public header file
> of your library, because it will conflict with packages that want to
> define ssize_t for their internal purpose.

Hopefully those definitions will be compatible, otherwise there will
likely be breakage anyway.

But still, arguable I agree, this should probably be gnutls_ssize_t or
something, but that makes the code quite ugly.

I'm inclined to leave this alone until someone reports a real problem
with it, having conflicting ssize_t definitions seems so problematic
that I doubt it will be a problem in practice.

> The public API that uses ssize_t is:
>
>   extern IDNAPI uint32_t *stringprep_utf8_to_ucs4 (const char *str,
>                                                    ssize_t len,
>                                                    size_t * items_written);
>   extern IDNAPI char *stringprep_ucs4_to_utf8 (const uint32_t * str,
>                                                ssize_t len,
>                                                size_t * items_read,
>                                                size_t * items_written);
>   extern IDNAPI char *stringprep_utf8_nfkc_normalize (const char *str,
>                                                       ssize_t len);
>   extern IDNAPI uint32_t *stringprep_ucs4_nfkc_normalize (uint32_t * str,
>                                                           ssize_t len);
>
> Note that ssize_t values are only passed by value, not through pointers.
> Therefore it's easy. I see two possible solutions:
>
>   1) Use size_t instead of ssize_t. This is backward compatible at the
>      source code level, except for uses of the 4 functions via function
>      pointers, and is also backward compatible at the ABI level.

The functions accept negative lengths -1 to indicate zero terminated
strings.  Using a non-signed type for storing -1 feels wrong to me.

>   2) Use 'long' instead of ssize_t. This is backward compatible at the
>      source code level, except for uses of the 4 functions via function
>      pointers. For ABI level backward compatibility you need to use
>      versioning (such as
>        #define stringprep_utf8_to_ucs4 stringprep_utf8_to_ucs4_v2
>      and a .c file that provides a definition of
>        stringprep_utf8_to_ucs4
>      followed by
>        #undef stringprep_utf8_to_ucs4
>      and a definition of stringprep_utf8_to_ucs4; similarly for the other
>      functions).

There is also the third alternative:

3) Define a libidn_ssize_t with what libidn believes to be the
appropriate ssize_t type, and use that.

and of course the fourth

4) Define ssize_t with what libidn believes to be the appropriate
ssize_t type, and use that, which will collide if something else defines
a type conflicting ssize_t type.

All things considered, I tend to prefer 4) as it leads to the cleanest
code for sane architectures that has a ssize_t (which are the most
important ones to me) and introduces minimal code to deal with platforms
that lacks a ssize_t.

/Simon



reply via email to

[Prev in Thread] Current Thread [Next in Thread]