Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #145998 > unrolled thread

error_t proposal

Started byThiago Adams <thiago.adams@gmail.com>
First post2019-09-04 14:14 -0700
Last post2019-09-05 08:43 -0700
Articles 15 on this page of 55 — 14 participants

Back to article view | Back to comp.lang.c


Contents

  error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-04 14:14 -0700
    Re: error_t proposal Keith Thompson <kst-u@mib.org> - 2019-09-04 15:20 -0700
      Re: error_t proposal Mateusz Viste <mateusz@wont.tell> - 2019-09-05 08:02 +0000
        Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-05 04:04 -0700
          Re: error_t proposal Bruce S <bruces42@hotmail.com> - 2019-09-05 08:18 -0600
            Re: error_t proposal Keith Thompson <kst-u@mib.org> - 2019-09-05 14:31 -0700
              Re: error_t proposal James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-09-05 17:49 -0400
                Re: error_t proposal Keith Thompson <kst-u@mib.org> - 2019-09-05 15:14 -0700
              Re: error_t proposal Bruce S <bruces42@hotmail.com> - 2019-09-06 14:03 -0600
    Re: error_t proposal Clifford Heath <no.spam@please.net> - 2019-09-05 09:30 +1000
      Re: error_t proposal Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2019-09-05 02:38 -0700
      Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-05 04:57 -0700
        Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-05 05:16 -0700
          Re: error_t proposal Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2019-09-05 05:35 -0700
            Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-05 06:08 -0700
              Re: error_t proposal Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2019-09-05 06:16 -0700
                Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-05 06:37 -0700
                  Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-05 07:04 -0700
                    Re: error_t proposal Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-09-05 20:51 +0100
                      Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-05 13:52 -0700
                        Re: error_t proposal Keith Thompson <kst-u@mib.org> - 2019-09-05 14:56 -0700
                Re: error_t proposal William Ahern <william@25thandClement.com> - 2019-09-05 13:18 -0700
                Re: error_t proposal Clifford Heath <no.spam@please.net> - 2019-09-06 07:25 +1000
        Re: error_t proposal Clifford Heath <no.spam@please.net> - 2019-09-06 07:35 +1000
          Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-06 04:22 -0700
      Re: error_t proposal scott@slp53.sl.home (Scott Lurndal) - 2019-09-05 13:59 +0000
        Re: error_t proposal Clifford Heath <no.spam@please.net> - 2019-09-06 07:10 +1000
    Re: error_t proposal Jorgen Grahn <grahn+nntp@snipabacken.se> - 2019-09-05 10:01 +0000
      Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-05 04:36 -0700
        Re: error_t proposal Keith Thompson <kst-u@mib.org> - 2019-09-05 14:43 -0700
          Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-06 05:01 -0700
            Re: error_t proposal Keith Thompson <kst-u@mib.org> - 2019-09-06 11:18 -0700
              Re: error_t proposal scott@slp53.sl.home (Scott Lurndal) - 2019-09-06 19:34 +0000
              Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-06 12:37 -0700
                Re: error_t proposal Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-09-06 20:54 +0100
                  Re: error_t proposal Keith Thompson <kst-u@mib.org> - 2019-09-06 13:20 -0700
                    Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-06 13:43 -0700
                      Re: error_t proposal Keith Thompson <kst-u@mib.org> - 2019-09-06 14:25 -0700
                        Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-06 15:14 -0700
                          Re: error_t proposal Keith Thompson <kst-u@mib.org> - 2019-09-06 15:49 -0700
                            Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-06 18:44 -0700
                              Re: error_t proposal Clifford Heath <no.spam@please.net> - 2019-09-07 12:35 +1000
                                Re: error_t proposal Ike Naar <ike@sdf.lonestar.org> - 2019-09-08 20:15 +0000
                                  Re: error_t proposal Clifford Heath <no.spam@please.net> - 2019-09-09 09:30 +1000
                                    Re: error_t proposal Ike Naar <ike@iceland.freeshell.org> - 2019-09-09 07:35 +0000
                                      Re: error_t proposal Clifford Heath <no.spam@please.net> - 2019-09-09 19:44 +1000
                                    Re: error_t proposal scott@slp53.sl.home (Scott Lurndal) - 2019-09-09 13:58 +0000
                                    Re: error_t proposal Jorgen Grahn <grahn+nntp@snipabacken.se> - 2019-09-10 14:24 +0000
                                      Re: error_t proposal Clifford Heath <no.spam@please.net> - 2019-09-11 09:22 +1000
                                        Re: error_t proposal Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2019-09-10 16:48 -0700
                                          Re: error_t proposal Clifford Heath <no.spam@please.net> - 2019-09-11 10:45 +1000
                    Re: error_t proposal Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-09-06 21:47 +0100
    Re: error_t proposal jadill33@gmail.com - 2019-09-05 07:04 -0700
      Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-05 07:36 -0700
        Re: error_t proposal jadill33@gmail.com - 2019-09-05 08:43 -0700

Page 3 of 3 — ← Prev page 1 2 [3]


#146086

FromThiago Adams <thiago.adams@gmail.com>
Date2019-09-06 18:44 -0700
Message-ID<32ae196a-b38b-43e4-a09d-561a5d2e5aa6@googlegroups.com>
In reply to#146085
On Friday, September 6, 2019 at 7:49:26 PM UTC-3, Keith Thompson wrote:
> Thiago Adams writes:
> > On Friday, September 6, 2019 at 6:25:27 PM UTC-3, Keith Thompson wrote:
> [...]
> >> If you want to define your own error type, I suggest *not* calling it
> >> "errno_t" as C11 Annex K does.  Support for Annex K is not widespread,
> >> and it's been proposed for removal in the next edition.
> >> 
> >> <http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1969.htm#adi>
> >
> > I think they should do a fix. In the worst case just ignore the 
> > extra arguments and leave it for static analysis.
> 
> I don't think that will happen.
> 
> >> I like the idea of a consistent error reporting convention for library
> >> functions, but existing and widely used libraries are *not* consistent,
> >> and that's not going to change any time soon.  What is the intended
> >> scope of your proposal?
> > Sorry, I didn't understand you question.
> 
> For example, are you pushing for POSIX and other standards/libraries to
> be updated to adopt your proposal?  Or just newly designed libraries?
> Or just your own?

I think it is not possible to change the existing POSIX interfaces
because the function contract would be broken.
The current contract is 
"
 On success, zero is returned.  On error, -1 is returned, and errno is
 set appropriately.
"

So it would not be possible to return errno .

For our own libraries the advantage is not having to
create/define/maintain/remember/document/explain a header
file with a exclusive error type.

For a C community the advantage is the similar. As soon as you read
errno_t from a thirty party lib you will understand.
And conversion between MyLibError and YourLibError and StardandLib
error would not be necessary.
One situation where I think this idea should have been used is here
int thrd_create( thrd_t *thr, thrd_start_t func, void *arg );

If you look at C++ they are using POSIX as the abstraction layer.
I think this is correct. The thing I think is bad in C++ is the
over-engineering, for instance, in the error type.
https://en.cppreference.com/w/cpp/error/error_code
or chrono
https://en.cppreference.com/w/cpp/chrono/time_point
iostream and more.

What I would like to see is a simple typedef errno_t not depending
on Annex K and POSIX constants added into C. Note that they already
included in C++.

As a bonus, I would like to see more POSIX functions added into C
especially file system.
In this case the contract could be new and returning errno_t .
For instance: (this is C++)

https://en.cppreference.com/w/cpp/filesystem/remove


The notes says everthing:

"Notes
On POSIX systems, this function typically calls unlink and rmdir as needed, on Windows RemoveDirectoryW and DeleteFileW."

I would like to see in C

errno_t remove(const char* path);

[toc] | [prev] | [next] | [standalone]


#146087

FromClifford Heath <no.spam@please.net>
Date2019-09-07 12:35 +1000
Message-ID<VHEcF.199857$9i3.11349@fx42.iad>
In reply to#146086
On 7/9/19 11:44 am, Thiago Adams wrote:
> On Friday, September 6, 2019 at 7:49:26 PM UTC-3, Keith Thompson wrote:
>> Thiago Adams writes:
>>> On Friday, September 6, 2019 at 6:25:27 PM UTC-3, Keith Thompson wrote:
>> [...]
>>>> If you want to define your own error type, I suggest *not* calling it
>>>> "errno_t" as C11 Annex K does.  Support for Annex K is not widespread,
>>>> and it's been proposed for removal in the next edition.
>>>>
>>>> <http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1969.htm#adi>
>>>
>>> I think they should do a fix. In the worst case just ignore the
>>> extra arguments and leave it for static analysis.
>>
>> I don't think that will happen.
>>
>>>> I like the idea of a consistent error reporting convention for library
>>>> functions, but existing and widely used libraries are *not* consistent,
>>>> and that's not going to change any time soon.  What is the intended
>>>> scope of your proposal?
>>> Sorry, I didn't understand you question.
>>
>> For example, are you pushing for POSIX and other standards/libraries to
>> be updated to adopt your proposal?  Or just newly designed libraries?
>> Or just your own?
> 
> I think it is not possible to change the existing POSIX interfaces
> because the function contract would be broken.
> The current contract is
> "
>   On success, zero is returned.  On error, -1 is returned, and errno is
>   set appropriately.
> "
> 
> So it would not be possible to return errno .
> 
> For our own libraries the advantage is not having to
> create/define/maintain/remember/document/explain a header
> file with a exclusive error type.

On the other hand one could augment the existing contract.

For example, an ENOSPC error while writing a file can still be set in 
errno, but a support library could also set an additional variable 
(error parameter) to the name of the device that is out of space. Even 
just an fstat() to get the inode details from the fd would be a damn 
good start.

By providing the context that *should have been returned by the OS* you 
reduce the impedance that a developer has to chasing the details of a 
rare error on every possible time that they might need to report it.

The fact that there is so rarely value in such a lot of effort is the 
problem here - but when the problem does occur, the end user often needs 
more help. Developers just shrug and say "you should learn how to use 
your computer" - i.e. the problem is with the user, not with themselves.

This is the fundamental disrespect that is enshrined in Posix and errno.

--
Clifford Heath.

> For a C community the advantage is the similar. As soon as you read
> errno_t from a thirty party lib you will understand.
> And conversion between MyLibError and YourLibError and StardandLib
> error would not be necessary.
> One situation where I think this idea should have been used is here
> int thrd_create( thrd_t *thr, thrd_start_t func, void *arg );
> 
> If you look at C++ they are using POSIX as the abstraction layer.
> I think this is correct. The thing I think is bad in C++ is the
> over-engineering, for instance, in the error type.
> https://en.cppreference.com/w/cpp/error/error_code
> or chrono
> https://en.cppreference.com/w/cpp/chrono/time_point
> iostream and more.
> 
> What I would like to see is a simple typedef errno_t not depending
> on Annex K and POSIX constants added into C. Note that they already
> included in C++.
> 
> As a bonus, I would like to see more POSIX functions added into C
> especially file system.
> In this case the contract could be new and returning errno_t .
> For instance: (this is C++)
> 
> https://en.cppreference.com/w/cpp/filesystem/remove
> 
> 
> The notes says everthing:
> 
> "Notes
> On POSIX systems, this function typically calls unlink and rmdir as needed, on Windows RemoveDirectoryW and DeleteFileW."
> 
> I would like to see in C
> 
> errno_t remove(const char* path);
> 
> 

[toc] | [prev] | [next] | [standalone]


#146096

FromIke Naar <ike@sdf.lonestar.org>
Date2019-09-08 20:15 +0000
Message-ID<slrn3ht8qnaob4.fpt.ike@sdf.lonestar.org>
In reply to#146087
On 2019-09-07, Clifford Heath <no.spam@please.net> wrote:
> On the other hand one could augment the existing contract.
>
> For example, an ENOSPC error while writing a file can still be set in 
> errno, but a support library could also set an additional variable 
> (error parameter) to the name of the device that is out of space. Even 
> just an fstat() to get the inode details from the fd would be a damn 
> good start.

Is this really necessary?
If some function, taking a file argument, returs ENOSPC, the caller
knows the file for which error condition happened, so if the caller
would be interested in the device, the caller could extract this
information via other means.

[toc] | [prev] | [next] | [standalone]


#146097

FromClifford Heath <no.spam@please.net>
Date2019-09-09 09:30 +1000
Message-ID<6agdF.238076$Yo.220135@fx08.iad>
In reply to#146096
On 9/9/19 6:15 am, Ike Naar wrote:
> On 2019-09-07, Clifford Heath <no.spam@please.net> wrote:
>> On the other hand one could augment the existing contract.
>>
>> For example, an ENOSPC error while writing a file can still be set in
>> errno, but a support library could also set an additional variable
>> (error parameter) to the name of the device that is out of space. Even
>> just an fstat() to get the inode details from the fd would be a damn
>> good start.
> 
> Is this really necessary?
> If some function, taking a file argument, returs ENOSPC, the caller
> knows the file for which error condition happened, so if the caller
> would be interested in the device, the caller could extract this
> information via other means.

Yes, it is necessary, both in this case and in other cases, even though 
there may be a round-about way of discovering the cause.

The culture of laziness that engendered this omission is the same 
culture that results in omission of other detail, caricatured eventually 
by "Unknown Error 0x80000000" type reporting. It's too hard to handle 
every error that might follow from a write() call, so coders end up 
simply saying "Can't save your project" or something even less useful, 
and leaving the end user guessing at why.

Every single error has a concrete context and cause, and we need to make 
a radical commitment to actually reporting the details (all the time but 
most particularly at the operating system level) - as well as the final 
consequences. Failure to properly report details that are available is 
the single thing that most infuriates users, and rightly so.

This is why our users hate us.

Clifford Heath.

[toc] | [prev] | [next] | [standalone]


#146098

FromIke Naar <ike@iceland.freeshell.org>
Date2019-09-09 07:35 +0000
Message-ID<slrn3km4qnc062.f0h.ike@iceland.freeshell.org>
In reply to#146097
On 2019-09-08, Clifford Heath <no.spam@please.net> wrote:
> On 9/9/19 6:15 am, Ike Naar wrote:
>> On 2019-09-07, Clifford Heath <no.spam@please.net> wrote:
>>> On the other hand one could augment the existing contract.
>>>
>>> For example, an ENOSPC error while writing a file can still be set in
>>> errno, but a support library could also set an additional variable
>>> (error parameter) to the name of the device that is out of space. Even
>>> just an fstat() to get the inode details from the fd would be a damn
>>> good start.
>> 
>> Is this really necessary?
>> If some function, taking a file argument, returs ENOSPC, the caller
>> knows the file for which error condition happened, so if the caller
>> would be interested in the device, the caller could extract this
>> information via other means.
>
> Yes, it is necessary, both in this case and in other cases, even though 
> there may be a round-about way of discovering the cause.
>
> The culture of laziness that engendered this omission is the same 
> culture that results in omission of other detail, caricatured eventually 
> by "Unknown Error 0x80000000" type reporting. It's too hard to handle 
> every error that might follow from a write() call, so coders end up 
> simply saying "Can't save your project" or something even less useful, 
> and leaving the end user guessing at why.
>
> Every single error has a concrete context and cause, and we need to make 
> a radical commitment to actually reporting the details (all the time but 
> most particularly at the operating system level) - as well as the final 
> consequences. Failure to properly report details that are available is 
> the single thing that most infuriates users, and rightly so.
>
> This is why our users hate us.

If the caller of write() is not willing to report the details when
write() returns an error, then what would be the benefit if write()
would provide those details in some alternative fashion?

[toc] | [prev] | [next] | [standalone]


#146101

FromClifford Heath <no.spam@please.net>
Date2019-09-09 19:44 +1000
Message-ID<vapdF.206347$9i3.183161@fx42.iad>
In reply to#146098
On 9/9/19 5:35 pm, Ike Naar wrote:
> On 2019-09-08, Clifford Heath <no.spam@please.net> wrote:
>> On 9/9/19 6:15 am, Ike Naar wrote:
>>> On 2019-09-07, Clifford Heath <no.spam@please.net> wrote:
>>>> On the other hand one could augment the existing contract.
>>>>
>>>> For example, an ENOSPC error while writing a file can still be set in
>>>> errno, but a support library could also set an additional variable
>>>> (error parameter) to the name of the device that is out of space. Even
>>>> just an fstat() to get the inode details from the fd would be a damn
>>>> good start.
>>>
>>> Is this really necessary?
>>> If some function, taking a file argument, returs ENOSPC, the caller
>>> knows the file for which error condition happened, so if the caller
>>> would be interested in the device, the caller could extract this
>>> information via other means.
>>
>> Yes, it is necessary, both in this case and in other cases, even though
>> there may be a round-about way of discovering the cause.
>>
>> The culture of laziness that engendered this omission is the same
>> culture that results in omission of other detail, caricatured eventually
>> by "Unknown Error 0x80000000" type reporting. It's too hard to handle
>> every error that might follow from a write() call, so coders end up
>> simply saying "Can't save your project" or something even less useful,
>> and leaving the end user guessing at why.
>>
>> Every single error has a concrete context and cause, and we need to make
>> a radical commitment to actually reporting the details (all the time but
>> most particularly at the operating system level) - as well as the final
>> consequences. Failure to properly report details that are available is
>> the single thing that most infuriates users, and rightly so.
>>
>> This is why our users hate us.
> 
> If the caller of write() is not willing to report the details when
> write() returns an error, then what would be the benefit if write()
> would provide those details in some alternative fashion?
> 

It's all about impedance. If errno was augmented with (thread-safe) 
parameter variables, and if strerror() contained printf substitutions or 
made use of the returned error parameters to format a customised 
message, I think every developer would be happy to use it. But when 
every system call has to be followed by custom code in many cases of a 
switch(errno) statement, it's just not going to happen (and hasn't 
happened).

Clifford Heath.

[toc] | [prev] | [next] | [standalone]


#146107

Fromscott@slp53.sl.home (Scott Lurndal)
Date2019-09-09 13:58 +0000
Message-ID<zUsdF.69191$7O3.2290@fx10.iad>
In reply to#146097
Clifford Heath <no.spam@please.net> writes:
>On 9/9/19 6:15 am, Ike Naar wrote:
>> On 2019-09-07, Clifford Heath <no.spam@please.net> wrote:
>>> On the other hand one could augment the existing contract.
>>>
>>> For example, an ENOSPC error while writing a file can still be set in
>>> errno, but a support library could also set an additional variable
>>> (error parameter) to the name of the device that is out of space. Even
>>> just an fstat() to get the inode details from the fd would be a damn
>>> good start.
>> 
>> Is this really necessary?
>> If some function, taking a file argument, returs ENOSPC, the caller
>> knows the file for which error condition happened, so if the caller
>> would be interested in the device, the caller could extract this
>> information via other means.
>
>Yes, it is necessary, both in this case and in other cases, even though 
>there may be a round-about way of discovering the cause.
>
>The culture of laziness that engendered this omission is the same 

Culture of laziness?   Guess there's no point in reading further.

[toc] | [prev] | [next] | [standalone]


#146120

FromJorgen Grahn <grahn+nntp@snipabacken.se>
Date2019-09-10 14:24 +0000
Message-ID<slrnqnfch1.cdo.grahn+nntp@frailea.sa.invalid>
In reply to#146097
On Sun, 2019-09-08, Clifford Heath wrote:
> On 9/9/19 6:15 am, Ike Naar wrote:
>> On 2019-09-07, Clifford Heath <no.spam@please.net> wrote:
>>> On the other hand one could augment the existing contract.
>>>
>>> For example, an ENOSPC error while writing a file can still be set in
>>> errno, but a support library could also set an additional variable
>>> (error parameter) to the name of the device that is out of space. Even
>>> just an fstat() to get the inode details from the fd would be a damn
>>> good start.
>> 
>> Is this really necessary?
>> If some function, taking a file argument, returs ENOSPC, the caller
>> knows the file for which error condition happened, so if the caller
>> would be interested in the device, the caller could extract this
>> information via other means.
>
> Yes, it is necessary, both in this case and in other cases, even though 
> there may be a round-about way of discovering the cause.
>
> The culture of laziness that engendered this omission is the same 
> culture that results in omission of other detail, caricatured eventually 
> by "Unknown Error 0x80000000" type reporting. It's too hard to handle 
> every error that might follow from a write() call, so coders end up 
> simply saying "Can't save your project" or something even less useful, 
> and leaving the end user guessing at why.
>
> Every single error has a concrete context and cause, and we need to make 
> a radical commitment to actually reporting the details (all the time but 
> most particularly at the operating system level) - as well as the final 
> consequences. Failure to properly report details that are available is 
> the single thing that most infuriates users, and rightly so.
>
> This is why our users hate us.

I'm not sure if he disagrees or agrees with you, but there's this
essay that's worth reading:

    The case for stupid software
    Peter da Silva
    http://scarydevil.com/~peter/io/stupidsoftware.html

/Jorgen

-- 
  // Jorgen Grahn <grahn@  Oo  o.   .     .
\X/     snipabacken.se>   O  o   .

[toc] | [prev] | [next] | [standalone]


#146133

FromClifford Heath <no.spam@please.net>
Date2019-09-11 09:22 +1000
Message-ID<OeWdF.179574$Pr1.166625@fx01.iad>
In reply to#146120
On 11/9/19 12:24 am, Jorgen Grahn wrote:
> On Sun, 2019-09-08, Clifford Heath wrote:
>> On 9/9/19 6:15 am, Ike Naar wrote:
>>> On 2019-09-07, Clifford Heath <no.spam@please.net> wrote:
>>>> On the other hand one could augment the existing contract.
>>>>
>>>> For example, an ENOSPC error while writing a file can still be set in
>>>> errno, but a support library could also set an additional variable
>>>> (error parameter) to the name of the device that is out of space. Even
>>>> just an fstat() to get the inode details from the fd would be a damn
>>>> good start.
>>>
>>> Is this really necessary?
>>> If some function, taking a file argument, returs ENOSPC, the caller
>>> knows the file for which error condition happened, so if the caller
>>> would be interested in the device, the caller could extract this
>>> information via other means.
>>
>> Yes, it is necessary, both in this case and in other cases, even though
>> there may be a round-about way of discovering the cause.
>>
>> The culture of laziness that engendered this omission is the same
>> culture that results in omission of other detail, caricatured eventually
>> by "Unknown Error 0x80000000" type reporting. It's too hard to handle
>> every error that might follow from a write() call, so coders end up
>> simply saying "Can't save your project" or something even less useful,
>> and leaving the end user guessing at why.
>>
>> Every single error has a concrete context and cause, and we need to make
>> a radical commitment to actually reporting the details (all the time but
>> most particularly at the operating system level) - as well as the final
>> consequences. Failure to properly report details that are available is
>> the single thing that most infuriates users, and rightly so.
>>
>> This is why our users hate us.
> 
> I'm not sure if he disagrees or agrees with you, but there's this
> essay that's worth reading:
> 
>      The case for stupid software
>      Peter da Silva
>      http://scarydevil.com/~peter/io/stupidsoftware.html
> 
> /Jorgen
> 

Thanks. He makes some of the same points - you need to report the 
original error even if it seems too technical (not report the most 
likely error instead of the actual error), and you need to point the 
user to where they can make a configuration change to avoid the error 
(for example). As I said, it's necessary to indicate 
Problem/Reason/Solution (in that example, "Login Failed", 
"Authentication method disallowed", and "Reconfigure your authentication 
settings").

He claims that proliferation of configuration wizards is the reason for 
Windows bloat (which I would dispute anyway). In recent Windoze versions 
everything is comprehensively configurable by powershell/commandline 
actions that span the entire API for each feature. Microsoft's adoption 
of this API-oriented system design is admirable and should be followed 
(even though they also bury the API under mountains of GUIs). They 
generate all the APIs, command lines and documentation from the 
single-source design files. This was not the situation in 1999 when the 
article was written.

The reason I chose "ENOSPC" error is that the error occurs on writing a 
file, but it actually pertains to the volume; and it's a pain to 
reliably report the volume name given only the file descriptor. So we 
leave it to the user to guess (with a network drive this can be 
confusing, too).

Clifford Heath.

[toc] | [prev] | [next] | [standalone]


#146134

FromMalcolm McLean <malcolm.arthur.mclean@gmail.com>
Date2019-09-10 16:48 -0700
Message-ID<03bd835f-4d07-4ad6-ac10-28398177cc66@googlegroups.com>
In reply to#146133
On Wednesday, 11 September 2019 00:22:31 UTC+1, Clifford Heath  wrote:

> The reason I chose "ENOSPC" error is that the error occurs on writing a 
> file, but it actually pertains to the volume; and it's a pain to 
> reliably report the volume name given only the file descriptor. So we 
> leave it to the user to guess (with a network drive this can be 
> confusing, too).
> 
But as likely as not the error is that the program is stuck in an
infinite / size_t == -1 loop writing out bytes to the file. So
reporting the volume as full will still be misleading.

[toc] | [prev] | [next] | [standalone]


#146136

FromClifford Heath <no.spam@please.net>
Date2019-09-11 10:45 +1000
Message-ID<usXdF.100047$Ph5.93382@fx27.iad>
In reply to#146134
On 11/9/19 9:48 am, Malcolm McLean wrote:
> On Wednesday, 11 September 2019 00:22:31 UTC+1, Clifford Heath  wrote:
> 
>> The reason I chose "ENOSPC" error is that the error occurs on writing a
>> file, but it actually pertains to the volume; and it's a pain to
>> reliably report the volume name given only the file descriptor. So we
>> leave it to the user to guess (with a network drive this can be
>> confusing, too).
>>
> But as likely as not the error is that the program is stuck in an
> infinite / size_t == -1 loop writing out bytes to the file. So
> reporting the volume as full will still be misleading.

That's one possibility. Another is that *another* process is doing the 
same on the same volume, possibly even to a file which has no directory 
entry (no external name, just an open inode) - I've seen this. The 
operating system can easily know which large files on the full volume 
have been written to/extended recently, and be able to report them and 
the name of the process that's writing them (details subject to 
security, of course). All this stuff is readily available to the O/S, 
but quite difficult to discover even as a knowledgeable user - so the 
O/S should provide sufficient diagnostic clues. So your point only 
reinforces my claim that error context should be gathered and reported 
from where the error is first detected.

Clifford Heath.

[toc] | [prev] | [next] | [standalone]


#146082

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2019-09-06 21:47 +0100
Message-ID<871rwtxibp.fsf@bsb.me.uk>
In reply to#146080
Keith Thompson <kst-u@mib.org> writes:

> Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
>> Thiago Adams <thiago.adams@gmail.com> writes:
>>> On Friday, September 6, 2019 at 3:18:44 PM UTC-3, Keith Thompson wrote:
>>>> Thiago Adams writes:
>>>> [...]
>>>> > I am happy to have found errno_t in the C11 standard.
>>>> > I will not change bool for errno_t in my current programs (because 
>>>> > this creates a inverse logic) but I intend to use errno_t in new 
>>>> > programs.
>>>> 
>>>> Then your new programs won't compile with implementations that don't
>>>> support the optional Annex K (unless you define errno_t yourself).
>>>
>>> When I compiled using VC++ 2019 I didn't have to add any defines
>>> like #define __STDC_WANT_LIB_EXT1__ 1 to use errno_t or other.
>>> I guess it is not following the standard in this case.
>>
>> No, that's permitted.  A C11 implementation should not define these
>> types etc. when __STDC_WANT_LIB_EXT1__ is defined to be 0 (at the
>> appropriate time) and it should when __STDC_WANT_LIB_EXT1__ is defined
>> to be 1, but the default (what happens when there is no explicit define
>> for __STDC_WANT_LIB_EXT1__) is left up to the implementation.
>
> Right.  There are three ways for an implementation to conform to C11
> with respect to Annex K:
>
> 1. Don't support it at all.  The macro __STDC_LIB_EXT1__ is not
>    predefined.  Defining or undefining __STDC_WANT_LIB_EXT1__
>    (probably) has no effect.
>
> 2. Support it, but disable it by default.  __STDC_LIB_EXT1__ is
>    predefined as 201112L.  A program that uses Annex K features
>    must define __STDC_WANT_LIB_EXT1__ as 1.
>
> 3. Support it and enable it by default.  __STDC_LIB_EXT1__ is
>    predefined as 201112L.  A program that uses Annex K features
>    may define __STDC_WANT_LIB_EXT1__ as 1.

That's clearer because it includes a reminder that the whole of Annex K
is optional.

<cut>
>>> I tried online some compilers and they are not recognizing
>>> errno_t even when I  use
>>> #define __STDC_WANT_LIB_EXT1__  1
>>
>> It would be helpful to see where that define is in your test case, along
>> with the compiler's name and the options you used.
>
> If you're using gcc or clang, that's expected; neither supports Annex K.
> (More precisely, the implementations I use, consisting of gcc or clang
> with glibc, do not support it.  I don't know whether gcc with a
> different library implementation might support Annex K.)

Ah.  For some reason I thought that gcc + recent glibc did, but that was
based on zero evidence.  Obviously just a wrong thought that somehow got
stuck in my head.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#146025

Fromjadill33@gmail.com
Date2019-09-05 07:04 -0700
Message-ID<61b543db-2e2d-4b79-9b41-2ff0dab29a14@googlegroups.com>
In reply to#145998
On Wednesday, September 4, 2019 at 5:14:29 PM UTC-4, Thiago Adams wrote:
> In my experience, most of the time I don't need to check
> for specific errors.
> 
> For instance, I rarely need to do this:
> 
> if (error == specific_error) { 
>  /*do something*/
> }
> 
> in general I just check for general errors:
> 
> if (error != error_success) {
>  /*do something*/
> }
> 
> Some libraries uses 0 to say "no error" and others use
> 1 or true do say "no error".
> 
> My suggestion is to add at <errno.h>
> 
> typedef int error_t
> and a enum item  std_success
> 
> 
> If you look at existing code, for instance
> 
> int thrd_create( thrd_t *thr, thrd_start_t func, void *arg );
> "thrd_success if the creation of the new thread was successful."
> 
> 
> int bind(SOCKET s, const sockaddr *addr, int namelen);
> "If no error occurs, bind returns zero. Otherwise, it returns SOCKET_ERROR, and a specific error code can be "
> 
> You will see different approaches.
> 
> But I think it should be more universal and library implementers
> could use the same typedef.
> 
> Let's say
> 
> error_t MyLibFunc();
> 
> then I could use 
> 
> error_t er = MyLibFunc();
> 
> if (er != std_success)
> {
>   printf("%s", MyLibErrorToString(er));
> }
> 
> and then automatically, the programmer that is using that lib
> knows how do check for errors.
> 
> 
> What do you think?
> How do you propagate errors? Do you create your own type?
> Do you use enun or int? 
> How do you integrate errors from thirty party libs in our own
> errors?
> 
> 
> Apart of that some range could be reserved for known errors.
> E.g nomen or io errors.
> 
> then errors like
> 
> thrd_nomem 
> 
> would not need a specific namespaces.

I think one method is to abstract errors with your own error enumeration
and then translate OS or 3rd party errors to your own enum.  Here's a
partial code snippet that demonstrates the strategy.  I didn't spend time
to make a standalone code snippet that compiles out of box, but it should
illustrate the idea.

/* The symbol 'error_errno_t_defined' is temporarily used to
   record whether or not the 'errno_t' type is available. */
#undef error_errno_t_defined

/*
 * If C11 standard support is available, then 'errno_t' is directly
 * available, and the declaration of the errno integer type can be
 * defined directly in terms of 'errno_t'.
 */
#if defined(__STDC__) && defined(__STDC_VERSION__)
#  if (__STDC__ && __STDC_VERSION__ >= 201112L)
     typedef errno_t c_errno;
#    define error_errno_t_defined
#  endif
#endif

/*!
 * \brief Define the error number type.
 *
 * The \c c_errno type represents an integer type meant to store an
 * error code native to the local operating system.  For example,
 * inspecting an error code for an out of memory condition may be
 * \c ENOMEM on POSIX systems or \c ERROR_NOT_ENOUGH_MEMORY on
 * Windows systems.
 */
#if !defined(error_errno_t_defined)
  typedef int c_errno;
#endif

#undef error_errno_t_defined

/*!
 * \brief This errno define represents an unknown or untranslatable
 *        error code.
 *
 * This error code is defined for Windows errors that do not have a
 * corresponding POSIX error code.
 */
#define EOTHER 9999

enum c_error
{
  c_error_force_signed__ = -1,

  c_success = 0,
  c_no_error = 0,

  c_argument_list_too_long,
  c_argument_out_of_domain,
  c_bad_address,
  c_bad_file_descriptor,
  c_broken_pipe,
  c_cross_device_link,
  c_device_or_resource_busy,

  /*
   * 'c_directory_exists' does not have a corresponding POSIX
   * errno or Windows GetLastError error code.  The concept mirrors
   * the same type of error as 'c_file_exists', but is applied
   * specifically to directory errors in the 'fileutils.h' library.
   */
  c_directory_exists,

  c_directory_not_empty,
  c_file_exists,
  c_file_not_found,
  c_file_too_big,
  c_filename_too_long,
  c_function_not_supported,
  c_illegal_seek,
  c_insufficient_range,
  c_interrupted,
  c_invalid_argument,
  c_io_error,
  c_no_child_process,
  c_no_lock_available,
  c_no_space_on_device,
  c_no_such_device,
  c_no_such_file_or_directory,
  c_not_a_directory,
  c_not_an_executable,
  c_not_enough_memory,
  c_operation_not_permitted,
  c_permission_denied,
  c_read_only_file_system,
  c_resource_unavailable_try_again,
  c_too_many_open_files,

  c_other = EOTHER
};

/*! \brief Alias the <tt>enum c_error</tt> type. */
typedef enum c_error c_error;

#if defined(_WIN32) || defined(__WIN32__)
/*!
 * \brief Translate a native Windows API error code into the common
 *        enumeration defined by \c c_error.
 * \param wapi_error The Windows API error code.
 * \return The corresponding \c c_error value if an error translation
 *         exists, otherwise \c c_other.
 */
c_error gc_translate_windows_getlasterror( c_errno wapi_error );
#endif

/*!
 * \brief Translate a native POSIX API error code into the common
 *        enumeration defined by \c c_error.
 * \param posix_errno The POSIX error code.
 * \return The corresponding \c c_error value if an error translation
 *         exists, otherwise \c c_other.
 */
c_error c_translate_posix_errno( c_errno posix_errno );

static inline c_error c_translate_errno( c_errno e )
{
#if defined(_WIN32) || defined(__WIN32__)
  return gc_translate_windows_getlasterror( e );
#else
  return c_translate_posix_errno( e );
#endif
}

#if defined(_WIN32) || defined(__WIN32__)
enum c_error gc_translate_windows_getlasterror( c_errno wapi_error )
{
  /* Common errors are placed first in the switch to speed up error
     code translation. */
  switch ( wapi_error )
  {
  case ERROR_SUCCESS:                 return c_success;
  case ERROR_INVALID_PARAMETER:       return c_invalid_argument;
  case ERROR_FILE_NOT_FOUND:          return c_file_not_found;
  case ERROR_PATH_NOT_FOUND:          return c_no_such_file_or_directory;

  case ERROR_ACCESS_DENIED:           return c_permission_denied;
  case ERROR_ACCOUNT_DISABLED:        return c_permission_denied;
  case ERROR_ALREADY_ASSIGNED:        return c_device_or_resource_busy;
  case ERROR_ALREADY_EXISTS:          return c_file_exists;
  case ERROR_ARITHMETIC_OVERFLOW:     return c_insufficient_range;
  case ERROR_BAD_DEVICE:              return c_no_such_device;
  case ERROR_BAD_EXE_FORMAT:          return c_not_an_executable;
  case ERROR_BAD_FORMAT:              return c_not_an_executable;
  case ERROR_BAD_LENGTH:              return c_invalid_argument;
  case ERROR_BAD_PATHNAME:            return c_no_such_file_or_directory;
  case ERROR_BAD_PIPE:                return c_broken_pipe;
  case ERROR_BAD_UNIT:                return c_no_such_device;
  case ERROR_BROKEN_PIPE:             return c_broken_pipe;
  case ERROR_BUFFER_OVERFLOW:         return c_filename_too_long;
  case ERROR_BUSY:                    return c_device_or_resource_busy;
  case ERROR_BUSY_DRIVE:              return c_device_or_resource_busy;
  case ERROR_CALL_NOT_IMPLEMENTED:    return c_function_not_supported;
  case ERROR_CANNOT_MAKE:             return c_permission_denied;
  case ERROR_CANTOPEN:                return c_io_error;
  case ERROR_CANTREAD:                return c_io_error;
  case ERROR_CANTWRITE:               return c_io_error;
  case ERROR_CHILD_NOT_COMPLETE:      return c_no_child_process;
  case ERROR_CRC:                     return c_io_error;
  case ERROR_CURRENT_DIRECTORY:       return c_permission_denied;
  case ERROR_DEV_NOT_EXIST:           return c_no_such_device;
  case ERROR_DEVICE_IN_USE:           return c_device_or_resource_busy;
  case ERROR_DIR_NOT_EMPTY:           return c_directory_not_empty;
  case ERROR_DIRECT_ACCESS_HANDLE:    return c_bad_file_descriptor;
  case ERROR_DIRECTORY:               return c_not_a_directory;
  case ERROR_DISK_CHANGE:             return c_io_error;
  case ERROR_DISK_FULL:               return c_no_space_on_device;
  case ERROR_DRIVE_LOCKED:            return c_device_or_resource_busy;
  case ERROR_ENVVAR_NOT_FOUND:        return c_invalid_argument;
  case ERROR_EXE_MARKED_INVALID:      return c_not_an_executable;
  case ERROR_FILE_EXISTS:             return c_file_exists;
  case ERROR_FILE_INVALID:            return c_no_such_device;
  case ERROR_FILENAME_EXCED_RANGE:    return c_filename_too_long;
  case ERROR_GEN_FAILURE:             return c_io_error;
  case ERROR_HANDLE_DISK_FULL:        return c_no_space_on_device;
  case ERROR_INSUFFICIENT_BUFFER:     return c_not_enough_memory;
  case ERROR_INVALID_ACCESS:          return c_permission_denied;
  case ERROR_INVALID_ADDRESS:         return c_bad_address;
  case ERROR_INVALID_DATA:            return c_invalid_argument;
  case ERROR_INVALID_DRIVE:           return c_no_such_device;
  case ERROR_INVALID_EXE_SIGNATURE:   return c_not_an_executable;
  case ERROR_INVALID_FUNCTION:        return c_function_not_supported;
  case ERROR_INVALID_HANDLE:          return c_bad_file_descriptor;
  case ERROR_INVALID_NAME:            return c_no_such_file_or_directory;
  case ERROR_INVALID_TARGET_HANDLE:   return c_bad_file_descriptor;
  case ERROR_IO_DEVICE:               return c_io_error;
  case ERROR_LOCK_FAILED:             return c_permission_denied;
  case ERROR_LOCK_VIOLATION:          return c_permission_denied;
  case ERROR_LOCKED:                  return c_device_or_resource_busy;
  case ERROR_LOGON_FAILURE:           return c_permission_denied;
  case ERROR_MAPPED_ALIGNMENT:        return c_invalid_argument;
  case ERROR_MAX_THRDS_REACHED:       return c_resource_unavailable_try_again;
  case ERROR_META_EXPANSION_TOO_LONG: return c_argument_list_too_long;
  case ERROR_NEGATIVE_SEEK:           return c_invalid_argument;
  case ERROR_NO_DATA:                 return c_broken_pipe;
  case ERROR_NO_MORE_FILES:           return c_no_such_file_or_directory;
  case ERROR_NO_MORE_SEARCH_HANDLES:  return c_too_many_open_files;
  case ERROR_NO_PROC_SLOTS:           return c_resource_unavailable_try_again;
  case ERROR_NO_SUCH_PRIVILEGE:       return c_permission_denied;
  case ERROR_NOACCESS:                return c_bad_address;
  case ERROR_NOT_ENOUGH_MEMORY:       return c_not_enough_memory;
  case ERROR_NOT_ENOUGH_QUOTA:        return c_not_enough_memory;
  case ERROR_NOT_READY:               return c_resource_unavailable_try_again;
  case ERROR_NOT_SAME_DEVICE:         return c_cross_device_link;
  case ERROR_OPEN_FAILED:             return c_io_error;
  case ERROR_OPEN_FILES:              return c_device_or_resource_busy;
  case ERROR_OPERATION_ABORTED:       return c_interrupted;
  case ERROR_OUTOFMEMORY:             return c_not_enough_memory;
  case ERROR_PIPE_BUSY:               return c_device_or_resource_busy;
  case ERROR_PIPE_CONNECTED:          return c_device_or_resource_busy;
  case ERROR_PIPE_LISTENING:          return c_broken_pipe;
  case ERROR_PIPE_NOT_CONNECTED:      return c_broken_pipe;
  case ERROR_READ_FAULT:              return c_io_error;
  case ERROR_SEEK:                    return c_io_error;
  case ERROR_SEEK_ON_DEVICE:          return c_illegal_seek;
  case ERROR_SHARING_BUFFER_EXCEEDED: return c_too_many_open_files;
  case ERROR_SHARING_VIOLATION:       return c_permission_denied;
  case ERROR_SIGNAL_PENDING:          return c_device_or_resource_busy;
  case ERROR_STACK_OVERFLOW:          return c_not_enough_memory;
  case ERROR_TOO_MANY_MODULES:        return c_too_many_open_files;
  case ERROR_TOO_MANY_OPEN_FILES:     return c_too_many_open_files;
  case ERROR_UNRECOGNIZED_VOLUME:     return c_no_such_device;
  case ERROR_WAIT_NO_CHILDREN:        return c_no_child_process;
  case ERROR_WRITE_FAULT:             return c_io_error;
  case ERROR_WRITE_PROTECT:           return c_read_only_file_system;

  default:
    c_unexpected( "unhandled windows api error code" );
    break;
  }

  return c_other;
}
#endif

enum c_error c_translate_posix_errno( c_errno posix_errno )
{
  /* Common errors are placed first in the switch to speed up error
     code translation. */
  switch ( posix_errno )
  {
  case 0:               return c_no_error;
  case EINVAL:          return c_invalid_argument;
  case ENOENT:          return c_no_such_file_or_directory;  /* ENOFILE */

  case EPERM:           return c_operation_not_permitted;
  case EINTR:           return c_interrupted;
  case EIO:             return c_io_error;
  case ENXIO:           return c_no_such_device;
  case E2BIG:           return c_argument_list_too_long;
  case ENOEXEC:         return c_not_an_executable;
  case EBADF:           return c_bad_file_descriptor;
  case ECHILD:          return c_no_child_process;
  case EAGAIN:          return c_resource_unavailable_try_again;
  case ENOMEM:          return c_not_enough_memory;
  case EACCES:          return c_permission_denied;
  case EFAULT:          return c_bad_address;
  case EBUSY:           return c_device_or_resource_busy;
  case EEXIST:          return c_file_exists;
  case EXDEV:           return c_cross_device_link;
  case ENODEV:          return c_no_such_device;
  case ENOTDIR:         return c_not_a_directory;
  case EISDIR:          return c_io_error;
  case ENFILE:          return c_too_many_open_files;
  case EMFILE:          return c_too_many_open_files;
  case EFBIG:           return c_file_too_big;
  case ENOSPC:          return c_no_space_on_device;
  case ESPIPE:          return c_illegal_seek;
  case EROFS:           return c_read_only_file_system;
  case EDOM:            return c_argument_out_of_domain;
  case ERANGE:          return c_insufficient_range;
  case ENAMETOOLONG:    return c_filename_too_long;
  case ENOLCK:          return c_no_lock_available;
  case ENOSYS:          return c_function_not_supported;
  case ENOTEMPTY:       return c_directory_not_empty;

  default:
    c_unexpected( "unhandled posix error code" );
    break;
  }

  return c_other;
}

c_errno c_get_native_error( void )
{
#if defined(_WIN32) || defined(__WIN32__)
  return GetLastError();
#else
  return errno;
#endif
}

enum c_error c_get_error( void )
{
#if defined(_WIN32) || defined(__WIN32__)
  return gc_translate_windows_getlasterror( GetLastError() );
#else
  return c_translate_posix_errno( errno )
#endif
}

You can also provide a lookup table of error strings and you can normalize
the error messages of OS specific errors to your liking.

Third party libraries are just an extension of this.  You usually have
one function to get the native error code, and define one function that
translates API errors into your common error code.  You have to provide
the mapping yourself.  A simple example would be OpenGL error codes and
the glGetError command.

I crafted this because of my desire to support an abstraction of specific
POSIX and Windows features in a cross platform library.  A word of caution
though, making a common list of all errors from an arbitrary list of 3rd
party libraries can be problematic and a maintenance hassle if you need
to support multiple versions of the same API.  YMMV.

Best regards,
John D.

[toc] | [prev] | [next] | [standalone]


#146030

FromThiago Adams <thiago.adams@gmail.com>
Date2019-09-05 07:36 -0700
Message-ID<3936f028-3dca-47c5-a424-e6218a435068@googlegroups.com>
In reply to#146025
On Thursday, September 5, 2019 at 11:04:40 AM UTC-3, jadi...@gmail.com wrote:
> On Wednesday, September 4, 2019 at 5:14:29 PM UTC-4, Thiago Adams wrote:
> > In my experience, most of the time I don't need to check
> > for specific errors.
> > 
> > For instance, I rarely need to do this:
> > 
> > if (error == specific_error) { 
> >  /*do something*/
> > }
> > 
> > in general I just check for general errors:
> > 
> > if (error != error_success) {
> >  /*do something*/
> > }
> > 
> > Some libraries uses 0 to say "no error" and others use
> > 1 or true do say "no error".
> > 
> > My suggestion is to add at <errno.h>
> > 
> > typedef int error_t
> > and a enum item  std_success
> > 
> > 
> > If you look at existing code, for instance
> > 
> > int thrd_create( thrd_t *thr, thrd_start_t func, void *arg );
> > "thrd_success if the creation of the new thread was successful."
> > 
> > 
> > int bind(SOCKET s, const sockaddr *addr, int namelen);
> > "If no error occurs, bind returns zero. Otherwise, it returns SOCKET_ERROR, and a specific error code can be "
> > 
> > You will see different approaches.
> > 
> > But I think it should be more universal and library implementers
> > could use the same typedef.
> > 
> > Let's say
> > 
> > error_t MyLibFunc();
> > 
> > then I could use 
> > 
> > error_t er = MyLibFunc();
> > 
> > if (er != std_success)
> > {
> >   printf("%s", MyLibErrorToString(er));
> > }
> > 
> > and then automatically, the programmer that is using that lib
> > knows how do check for errors.
> > 
> > 
> > What do you think?
> > How do you propagate errors? Do you create your own type?
> > Do you use enun or int? 
> > How do you integrate errors from thirty party libs in our own
> > errors?
> > 
> > 
> > Apart of that some range could be reserved for known errors.
> > E.g nomen or io errors.
> > 
> > then errors like
> > 
> > thrd_nomem 
> > 
> > would not need a specific namespaces.
> 
> I think one method is to abstract errors with your own error enumeration
> and then translate OS or 3rd party errors to your own enum.  Here's a
> partial code snippet that demonstrates the strategy.  I didn't spend time
> to make a standalone code snippet that compiles out of box, but it should
> illustrate the idea.
> 
> /* The symbol 'error_errno_t_defined' is temporarily used to
>    record whether or not the 'errno_t' type is available. */
> #undef error_errno_t_defined
> 
> /*
>  * If C11 standard support is available, then 'errno_t' is directly
>  * available, and the declaration of the errno integer type can be
>  * defined directly in terms of 'errno_t'.
>  */
> #if defined(__STDC__) && defined(__STDC_VERSION__)
> #  if (__STDC__ && __STDC_VERSION__ >= 201112L)
>      typedef errno_t c_errno;
> #    define error_errno_t_defined
> #  endif
> #endif
> 
> /*!
>  * \brief Define the error number type.
>  *
>  * The \c c_errno type represents an integer type meant to store an
>  * error code native to the local operating system.  For example,
>  * inspecting an error code for an out of memory condition may be
>  * \c ENOMEM on POSIX systems or \c ERROR_NOT_ENOUGH_MEMORY on
>  * Windows systems.
>  */
> #if !defined(error_errno_t_defined)
>   typedef int c_errno;
> #endif
> 
> #undef error_errno_t_defined
> 
> /*!
>  * \brief This errno define represents an unknown or untranslatable
>  *        error code.
>  *
>  * This error code is defined for Windows errors that do not have a
>  * corresponding POSIX error code.
>  */
> #define EOTHER 9999
> 
> enum c_error
> {
>   c_error_force_signed__ = -1,
> 
>   c_success = 0,
>   c_no_error = 0,
> 
>   c_argument_list_too_long,
>   c_argument_out_of_domain,
>   c_bad_address,
>   c_bad_file_descriptor,
>   c_broken_pipe,
>   c_cross_device_link,
>   c_device_or_resource_busy,
> 
>   /*
>    * 'c_directory_exists' does not have a corresponding POSIX
>    * errno or Windows GetLastError error code.  The concept mirrors
>    * the same type of error as 'c_file_exists', but is applied
>    * specifically to directory errors in the 'fileutils.h' library.
>    */
>   c_directory_exists,
> 
>   c_directory_not_empty,
>   c_file_exists,
>   c_file_not_found,
>   c_file_too_big,
>   c_filename_too_long,
>   c_function_not_supported,
>   c_illegal_seek,
>   c_insufficient_range,
>   c_interrupted,
>   c_invalid_argument,
>   c_io_error,
>   c_no_child_process,
>   c_no_lock_available,
>   c_no_space_on_device,
>   c_no_such_device,
>   c_no_such_file_or_directory,
>   c_not_a_directory,
>   c_not_an_executable,
>   c_not_enough_memory,
>   c_operation_not_permitted,
>   c_permission_denied,
>   c_read_only_file_system,
>   c_resource_unavailable_try_again,
>   c_too_many_open_files,
> 
>   c_other = EOTHER
> };
> 
> /*! \brief Alias the <tt>enum c_error</tt> type. */
> typedef enum c_error c_error;
> 
> #if defined(_WIN32) || defined(__WIN32__)
> /*!
>  * \brief Translate a native Windows API error code into the common
>  *        enumeration defined by \c c_error.
>  * \param wapi_error The Windows API error code.
>  * \return The corresponding \c c_error value if an error translation
>  *         exists, otherwise \c c_other.
>  */
> c_error gc_translate_windows_getlasterror( c_errno wapi_error );
> #endif
> 
> /*!
>  * \brief Translate a native POSIX API error code into the common
>  *        enumeration defined by \c c_error.
>  * \param posix_errno The POSIX error code.
>  * \return The corresponding \c c_error value if an error translation
>  *         exists, otherwise \c c_other.
>  */
> c_error c_translate_posix_errno( c_errno posix_errno );
> 
> static inline c_error c_translate_errno( c_errno e )
> {
> #if defined(_WIN32) || defined(__WIN32__)
>   return gc_translate_windows_getlasterror( e );
> #else
>   return c_translate_posix_errno( e );
> #endif
> }
> 
> #if defined(_WIN32) || defined(__WIN32__)
> enum c_error gc_translate_windows_getlasterror( c_errno wapi_error )
> {
>   /* Common errors are placed first in the switch to speed up error
>      code translation. */
>   switch ( wapi_error )
>   {
>   case ERROR_SUCCESS:                 return c_success;
>   case ERROR_INVALID_PARAMETER:       return c_invalid_argument;
>   case ERROR_FILE_NOT_FOUND:          return c_file_not_found;
>   case ERROR_PATH_NOT_FOUND:          return c_no_such_file_or_directory;
> 
>   case ERROR_ACCESS_DENIED:           return c_permission_denied;
>   case ERROR_ACCOUNT_DISABLED:        return c_permission_denied;
>   case ERROR_ALREADY_ASSIGNED:        return c_device_or_resource_busy;
>   case ERROR_ALREADY_EXISTS:          return c_file_exists;
>   case ERROR_ARITHMETIC_OVERFLOW:     return c_insufficient_range;
>   case ERROR_BAD_DEVICE:              return c_no_such_device;
>   case ERROR_BAD_EXE_FORMAT:          return c_not_an_executable;
>   case ERROR_BAD_FORMAT:              return c_not_an_executable;
>   case ERROR_BAD_LENGTH:              return c_invalid_argument;
>   case ERROR_BAD_PATHNAME:            return c_no_such_file_or_directory;
>   case ERROR_BAD_PIPE:                return c_broken_pipe;
>   case ERROR_BAD_UNIT:                return c_no_such_device;
>   case ERROR_BROKEN_PIPE:             return c_broken_pipe;
>   case ERROR_BUFFER_OVERFLOW:         return c_filename_too_long;
>   case ERROR_BUSY:                    return c_device_or_resource_busy;
>   case ERROR_BUSY_DRIVE:              return c_device_or_resource_busy;
>   case ERROR_CALL_NOT_IMPLEMENTED:    return c_function_not_supported;
>   case ERROR_CANNOT_MAKE:             return c_permission_denied;
>   case ERROR_CANTOPEN:                return c_io_error;
>   case ERROR_CANTREAD:                return c_io_error;
>   case ERROR_CANTWRITE:               return c_io_error;
>   case ERROR_CHILD_NOT_COMPLETE:      return c_no_child_process;
>   case ERROR_CRC:                     return c_io_error;
>   case ERROR_CURRENT_DIRECTORY:       return c_permission_denied;
>   case ERROR_DEV_NOT_EXIST:           return c_no_such_device;
>   case ERROR_DEVICE_IN_USE:           return c_device_or_resource_busy;
>   case ERROR_DIR_NOT_EMPTY:           return c_directory_not_empty;
>   case ERROR_DIRECT_ACCESS_HANDLE:    return c_bad_file_descriptor;
>   case ERROR_DIRECTORY:               return c_not_a_directory;
>   case ERROR_DISK_CHANGE:             return c_io_error;
>   case ERROR_DISK_FULL:               return c_no_space_on_device;
>   case ERROR_DRIVE_LOCKED:            return c_device_or_resource_busy;
>   case ERROR_ENVVAR_NOT_FOUND:        return c_invalid_argument;
>   case ERROR_EXE_MARKED_INVALID:      return c_not_an_executable;
>   case ERROR_FILE_EXISTS:             return c_file_exists;
>   case ERROR_FILE_INVALID:            return c_no_such_device;
>   case ERROR_FILENAME_EXCED_RANGE:    return c_filename_too_long;
>   case ERROR_GEN_FAILURE:             return c_io_error;
>   case ERROR_HANDLE_DISK_FULL:        return c_no_space_on_device;
>   case ERROR_INSUFFICIENT_BUFFER:     return c_not_enough_memory;
>   case ERROR_INVALID_ACCESS:          return c_permission_denied;
>   case ERROR_INVALID_ADDRESS:         return c_bad_address;
>   case ERROR_INVALID_DATA:            return c_invalid_argument;
>   case ERROR_INVALID_DRIVE:           return c_no_such_device;
>   case ERROR_INVALID_EXE_SIGNATURE:   return c_not_an_executable;
>   case ERROR_INVALID_FUNCTION:        return c_function_not_supported;
>   case ERROR_INVALID_HANDLE:          return c_bad_file_descriptor;
>   case ERROR_INVALID_NAME:            return c_no_such_file_or_directory;
>   case ERROR_INVALID_TARGET_HANDLE:   return c_bad_file_descriptor;
>   case ERROR_IO_DEVICE:               return c_io_error;
>   case ERROR_LOCK_FAILED:             return c_permission_denied;
>   case ERROR_LOCK_VIOLATION:          return c_permission_denied;
>   case ERROR_LOCKED:                  return c_device_or_resource_busy;
>   case ERROR_LOGON_FAILURE:           return c_permission_denied;
>   case ERROR_MAPPED_ALIGNMENT:        return c_invalid_argument;
>   case ERROR_MAX_THRDS_REACHED:       return c_resource_unavailable_try_again;
>   case ERROR_META_EXPANSION_TOO_LONG: return c_argument_list_too_long;
>   case ERROR_NEGATIVE_SEEK:           return c_invalid_argument;
>   case ERROR_NO_DATA:                 return c_broken_pipe;
>   case ERROR_NO_MORE_FILES:           return c_no_such_file_or_directory;
>   case ERROR_NO_MORE_SEARCH_HANDLES:  return c_too_many_open_files;
>   case ERROR_NO_PROC_SLOTS:           return c_resource_unavailable_try_again;
>   case ERROR_NO_SUCH_PRIVILEGE:       return c_permission_denied;
>   case ERROR_NOACCESS:                return c_bad_address;
>   case ERROR_NOT_ENOUGH_MEMORY:       return c_not_enough_memory;
>   case ERROR_NOT_ENOUGH_QUOTA:        return c_not_enough_memory;
>   case ERROR_NOT_READY:               return c_resource_unavailable_try_again;
>   case ERROR_NOT_SAME_DEVICE:         return c_cross_device_link;
>   case ERROR_OPEN_FAILED:             return c_io_error;
>   case ERROR_OPEN_FILES:              return c_device_or_resource_busy;
>   case ERROR_OPERATION_ABORTED:       return c_interrupted;
>   case ERROR_OUTOFMEMORY:             return c_not_enough_memory;
>   case ERROR_PIPE_BUSY:               return c_device_or_resource_busy;
>   case ERROR_PIPE_CONNECTED:          return c_device_or_resource_busy;
>   case ERROR_PIPE_LISTENING:          return c_broken_pipe;
>   case ERROR_PIPE_NOT_CONNECTED:      return c_broken_pipe;
>   case ERROR_READ_FAULT:              return c_io_error;
>   case ERROR_SEEK:                    return c_io_error;
>   case ERROR_SEEK_ON_DEVICE:          return c_illegal_seek;
>   case ERROR_SHARING_BUFFER_EXCEEDED: return c_too_many_open_files;
>   case ERROR_SHARING_VIOLATION:       return c_permission_denied;
>   case ERROR_SIGNAL_PENDING:          return c_device_or_resource_busy;
>   case ERROR_STACK_OVERFLOW:          return c_not_enough_memory;
>   case ERROR_TOO_MANY_MODULES:        return c_too_many_open_files;
>   case ERROR_TOO_MANY_OPEN_FILES:     return c_too_many_open_files;
>   case ERROR_UNRECOGNIZED_VOLUME:     return c_no_such_device;
>   case ERROR_WAIT_NO_CHILDREN:        return c_no_child_process;
>   case ERROR_WRITE_FAULT:             return c_io_error;
>   case ERROR_WRITE_PROTECT:           return c_read_only_file_system;
> 
>   default:
>     c_unexpected( "unhandled windows api error code" );
>     break;
>   }
> 
>   return c_other;
> }
> #endif
> 
> enum c_error c_translate_posix_errno( c_errno posix_errno )
> {
>   /* Common errors are placed first in the switch to speed up error
>      code translation. */
>   switch ( posix_errno )
>   {
>   case 0:               return c_no_error;
>   case EINVAL:          return c_invalid_argument;
>   case ENOENT:          return c_no_such_file_or_directory;  /* ENOFILE */
> 
>   case EPERM:           return c_operation_not_permitted;
>   case EINTR:           return c_interrupted;
>   case EIO:             return c_io_error;
>   case ENXIO:           return c_no_such_device;
>   case E2BIG:           return c_argument_list_too_long;
>   case ENOEXEC:         return c_not_an_executable;
>   case EBADF:           return c_bad_file_descriptor;
>   case ECHILD:          return c_no_child_process;
>   case EAGAIN:          return c_resource_unavailable_try_again;
>   case ENOMEM:          return c_not_enough_memory;
>   case EACCES:          return c_permission_denied;
>   case EFAULT:          return c_bad_address;
>   case EBUSY:           return c_device_or_resource_busy;
>   case EEXIST:          return c_file_exists;
>   case EXDEV:           return c_cross_device_link;
>   case ENODEV:          return c_no_such_device;
>   case ENOTDIR:         return c_not_a_directory;
>   case EISDIR:          return c_io_error;
>   case ENFILE:          return c_too_many_open_files;
>   case EMFILE:          return c_too_many_open_files;
>   case EFBIG:           return c_file_too_big;
>   case ENOSPC:          return c_no_space_on_device;
>   case ESPIPE:          return c_illegal_seek;
>   case EROFS:           return c_read_only_file_system;
>   case EDOM:            return c_argument_out_of_domain;
>   case ERANGE:          return c_insufficient_range;
>   case ENAMETOOLONG:    return c_filename_too_long;
>   case ENOLCK:          return c_no_lock_available;
>   case ENOSYS:          return c_function_not_supported;
>   case ENOTEMPTY:       return c_directory_not_empty;
> 
>   default:
>     c_unexpected( "unhandled posix error code" );
>     break;
>   }
> 
>   return c_other;
> }
> 
> c_errno c_get_native_error( void )
> {
> #if defined(_WIN32) || defined(__WIN32__)
>   return GetLastError();
> #else
>   return errno;
> #endif
> }
> 
> enum c_error c_get_error( void )
> {
> #if defined(_WIN32) || defined(__WIN32__)
>   return gc_translate_windows_getlasterror( GetLastError() );
> #else
>   return c_translate_posix_errno( errno )
> #endif
> }
> 
> You can also provide a lookup table of error strings and you can normalize
> the error messages of OS specific errors to your liking.
> 
> Third party libraries are just an extension of this.  You usually have
> one function to get the native error code, and define one function that
> translates API errors into your common error code.  You have to provide
> the mapping yourself.  A simple example would be OpenGL error codes and
> the glGetError command.
> 
> I crafted this because of my desire to support an abstraction of specific
> POSIX and Windows features in a cross platform library.  A word of caution
> though, making a common list of all errors from an arbitrary list of 3rd
> party libraries can be problematic and a maintenance hassle if you need
> to support multiple versions of the same API.  YMMV.
> 
> Best regards,
> John D.

Very interesting.
But considering Windows is already mapping some erros to POSIX
what do you think is just convert windows errors to POSIX instead a 
new value?

I would like to have a lib for sockets that is the same for windows
and linux. I think windows sockets errors  already have POSIX values
but the have their own defines. 100+POSIX 

For instance EACCES  = 13
and 
WSAEACCES = 10013

The disadvantage in to use the windows -> posix conversion is when
you have some error that is not present. Creating a new type you can
add the union set .

[toc] | [prev] | [next] | [standalone]


#146033

Fromjadill33@gmail.com
Date2019-09-05 08:43 -0700
Message-ID<a55d6642-8162-4301-83db-706099134f88@googlegroups.com>
In reply to#146030
On Thursday, September 5, 2019 at 10:36:47 AM UTC-4, Thiago Adams wrote:
> On Thursday, September 5, 2019 at 11:04:40 AM UTC-3, jadi...@gmail.com wrote:
> > On Wednesday, September 4, 2019 at 5:14:29 PM UTC-4, Thiago Adams wrote:
> > > In my experience, most of the time I don't need to check
> > > for specific errors.
> > > 
> > > For instance, I rarely need to do this:
> > > 
> > > if (error == specific_error) { 
> > >  /*do something*/
> > > }
> > > 
> > > in general I just check for general errors:
> > > 
> > > if (error != error_success) {
> > >  /*do something*/
> > > }
> > > 
> > > Some libraries uses 0 to say "no error" and others use
> > > 1 or true do say "no error".
> > > 
> > > My suggestion is to add at <errno.h>
> > > 
> > > typedef int error_t
> > > and a enum item  std_success
> > > 
> > > 
> > > If you look at existing code, for instance
> > > 
> > > int thrd_create( thrd_t *thr, thrd_start_t func, void *arg );
> > > "thrd_success if the creation of the new thread was successful."
> > > 
> > > 
> > > int bind(SOCKET s, const sockaddr *addr, int namelen);
> > > "If no error occurs, bind returns zero. Otherwise, it returns SOCKET_ERROR, and a specific error code can be "
> > > 
> > > You will see different approaches.
> > > 
> > > But I think it should be more universal and library implementers
> > > could use the same typedef.
> > > 
> > > Let's say
> > > 
> > > error_t MyLibFunc();
> > > 
> > > then I could use 
> > > 
> > > error_t er = MyLibFunc();
> > > 
> > > if (er != std_success)
> > > {
> > >   printf("%s", MyLibErrorToString(er));
> > > }
> > > 
> > > and then automatically, the programmer that is using that lib
> > > knows how do check for errors.
> > > 
> > > 
> > > What do you think?
> > > How do you propagate errors? Do you create your own type?
> > > Do you use enun or int? 
> > > How do you integrate errors from thirty party libs in our own
> > > errors?
> > > 
> > > 
> > > Apart of that some range could be reserved for known errors.
> > > E.g nomen or io errors.
> > > 
> > > then errors like
> > > 
> > > thrd_nomem 
> > > 
> > > would not need a specific namespaces.
> > 
> > I think one method is to abstract errors with your own error enumeration
> > and then translate OS or 3rd party errors to your own enum.  Here's a
> > partial code snippet that demonstrates the strategy.  I didn't spend time
> > to make a standalone code snippet that compiles out of box, but it should
> > illustrate the idea.
> > 

<snip>

> > 
> > You can also provide a lookup table of error strings and you can normalize
> > the error messages of OS specific errors to your liking.
> > 
> > Third party libraries are just an extension of this.  You usually have
> > one function to get the native error code, and define one function that
> > translates API errors into your common error code.  You have to provide
> > the mapping yourself.  A simple example would be OpenGL error codes and
> > the glGetError command.
> > 
> > I crafted this because of my desire to support an abstraction of specific
> > POSIX and Windows features in a cross platform library.  A word of caution
> > though, making a common list of all errors from an arbitrary list of 3rd
> > party libraries can be problematic and a maintenance hassle if you need
> > to support multiple versions of the same API.  YMMV.
> > 
> 
> Very interesting.
> But considering Windows is already mapping some erros to POSIX
> what do you think is just convert windows errors to POSIX instead a 
> new value?
> 
> I would like to have a lib for sockets that is the same for windows
> and linux. I think windows sockets errors  already have POSIX values
> but the have their own defines. 100+POSIX 
> 
> For instance EACCES  = 13
> and 
> WSAEACCES = 10013
> 
> The disadvantage in to use the windows -> posix conversion is when
> you have some error that is not present. Creating a new type you can
> add the union set.

Yes, the advantage of your own enumeration type is you can combine unique
error codes from each API into a single list, if you need that level of
granularity.  You can still use c_translate_posix_errno on Windows (I use
the 'gc' as a kind of internal namespace for my library), and it will provide
whatever Windows deems its subset of POSIX error codes.

In the library, I made a decision to use the Windows API when detected to
get "as close to the source" as possible.  There are several POSIX errors
that Windows ignores or fails to translate to.  For example, an action using
the Windows API would cause an errno that would translate to one vague
POSIX value that didn't make a whole lot of sense, but GetLastError would
reveal something that made more sense.  So I made my own mapping based on
reading the descriptions of all the errors from GetLastError.

I'm sure experts could find issues with how I mapped error codes, but it's
simplified my error handling within my library wrapper of API features.

Best regards,
John D.

[toc] | [prev] | [standalone]


Page 3 of 3 — ← Prev page 1 2 [3]

Back to top | Article view | comp.lang.c


csiph-web