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


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

Mechanism to generate annotated "error codes"

Started byDon Y <this@isnotme.com>
First post2012-03-01 12:48 -0700
Last post2012-03-06 11:21 -0700
Articles 7 on this page of 87 — 17 participants

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


Contents

  Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-01 12:48 -0700
    Re: Mechanism to generate annotated "error codes" Willem <willem@toad.stack.nl> - 2012-03-01 21:29 +0000
      Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-01 16:53 -0700
    Re: Mechanism to generate annotated "error codes" William Ahern <william@wilbur.25thandClement.com> - 2012-03-01 14:13 -0800
      Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-01 22:07 -0700
    Re: Mechanism to generate annotated "error codes" Shao Miller <sha0.miller@gmail.com> - 2012-03-01 17:53 -0500
      Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-01 23:05 -0700
        Re: Mechanism to generate annotated "error codes" Shao Miller <sha0.miller@gmail.com> - 2012-03-02 01:50 -0500
          Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-02 00:43 -0700
            Re: Mechanism to generate annotated "error codes" Shao Miller <sha0.miller@gmail.com> - 2012-03-03 17:58 -0500
              Re: Mechanism to generate annotated "error codes" Shao Miller <sha0.miller@gmail.com> - 2012-03-04 03:16 -0500
                Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-04 13:47 -0700
              Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-04 13:45 -0700
                Re: Mechanism to generate annotated "error codes" Shao Miller <sha0.miller@gmail.com> - 2012-03-04 18:37 -0500
                  Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-04 22:12 -0700
                    Re: Mechanism to generate annotated "error codes" Shao Miller <sha0.miller@gmail.com> - 2012-03-08 01:41 -0500
                      Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-09 14:34 -0700
    Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-02 00:30 -0700
      Re: Mechanism to generate annotated "error codes" Keith Thompson <kst-u@mib.org> - 2012-03-02 02:05 -0800
        Re: Mechanism to generate annotated "error codes" Kaz Kylheku <kaz@kylheku.com> - 2012-03-02 10:47 +0000
        Re: Mechanism to generate annotated "error codes" gazelle@shell.xmission.com (Kenny McCormack) - 2012-03-02 14:18 +0000
        Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-02 10:46 -0700
          Re: Mechanism to generate annotated "error codes" James Kuyper <jameskuyper@verizon.net> - 2012-03-02 14:08 -0500
            Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-02 12:38 -0700
          Re: Mechanism to generate annotated "error codes" Kaz Kylheku <kaz@kylheku.com> - 2012-03-02 22:57 +0000
            Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-02 17:14 -0700
              Re: Mechanism to generate annotated "error codes" Kaz Kylheku <kaz@kylheku.com> - 2012-03-03 02:25 +0000
              Re: Mechanism to generate annotated "error codes" James Kuyper <jameskuyper@verizon.net> - 2012-03-03 06:10 -0500
                Re: Mechanism to generate annotated "error codes" Shao Miller <sha0.miller@gmail.com> - 2012-03-03 16:12 -0500
          Re: Mechanism to generate annotated "error codes" Keith Thompson <kst-u@mib.org> - 2012-03-03 04:04 -0800
            Re: Mechanism to generate annotated "error codes" Kaz Kylheku <kaz@kylheku.com> - 2012-03-03 15:05 +0000
              Re: Mechanism to generate annotated "error codes" Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-03-03 16:25 +0000
            Re: Mechanism to generate annotated "error codes" Shao Miller <sha0.miller@gmail.com> - 2012-03-03 16:26 -0500
              Re: Mechanism to generate annotated "error codes" Keith Thompson <kst-u@mib.org> - 2012-03-03 13:40 -0800
        Re: Mechanism to generate annotated "error codes" Ian Collins <ian-news@hotmail.com> - 2012-03-03 12:03 +1300
          Re: Mechanism to generate annotated "error codes" Keith Thompson <kst-u@mib.org> - 2012-03-02 15:45 -0800
          Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-02 17:18 -0700
        Re: Mechanism to generate annotated "error codes" blp@cs.stanford.edu (Ben Pfaff) - 2012-03-02 15:08 -0800
        Re: Mechanism to generate annotated "error codes" "BartC" <bc@freeuk.com> - 2012-03-03 10:30 +0000
          Re: Mechanism to generate annotated "error codes" James Kuyper <jameskuyper@verizon.net> - 2012-03-03 06:19 -0500
          Re: Mechanism to generate annotated "error codes" Phil Carmody <thefatphil_demunged@yahoo.co.uk> - 2012-03-03 15:15 +0200
          Re: Mechanism to generate annotated "error codes" Kaz Kylheku <kaz@kylheku.com> - 2012-03-03 14:52 +0000
            Re: Mechanism to generate annotated "error codes" Malcolm McLean <malcolm.mclean5@btinternet.com> - 2012-03-03 07:39 -0800
              Re: Mechanism to generate annotated "error codes" Jonathan Leffler <jleffler@earthlink.net> - 2012-03-03 23:56 -0800
                Re: Mechanism to generate annotated "error codes" Ian Collins <ian-news@hotmail.com> - 2012-03-05 09:20 +1300
                  Re: Mechanism to generate annotated "error codes" Malcolm McLean <malcolm.mclean5@btinternet.com> - 2012-03-04 13:28 -0800
                    Re: Mechanism to generate annotated "error codes" Ian Collins <ian-news@hotmail.com> - 2012-03-05 10:56 +1300
            Re: Mechanism to generate annotated "error codes" "BartC" <bc@freeuk.com> - 2012-03-03 17:02 +0000
          Re: Mechanism to generate annotated "error codes" Keith Thompson <kst-u@mib.org> - 2012-03-03 12:30 -0800
      Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-03 19:15 -0700
        Re: Mechanism to generate annotated "error codes" Kaz Kylheku <kaz@kylheku.com> - 2012-03-04 03:20 +0000
          Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-04 11:03 -0700
        Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-04 16:31 -0700
          Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-04 23:04 -0700
    Re: Mechanism to generate annotated "error codes" Malcolm McLean <malcolm.mclean5@btinternet.com> - 2012-03-02 22:13 -0800
      Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-03 00:49 -0700
        Re: Mechanism to generate annotated "error codes" Malcolm McLean <malcolm.mclean5@btinternet.com> - 2012-03-03 03:32 -0800
          Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-03 12:04 -0700
            Re: Mechanism to generate annotated "error codes" Lowell Gilbert <lgusenet@be-well.ilk.org> - 2012-03-03 15:06 -0500
              Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-03 14:38 -0700
            Re: Mechanism to generate annotated "error codes" Malcolm McLean <malcolm.mclean5@btinternet.com> - 2012-03-03 12:15 -0800
              Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-03 16:51 -0700
                Re: Mechanism to generate annotated "error codes" Malcolm McLean <malcolm.mclean5@btinternet.com> - 2012-03-04 14:08 -0800
                  Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-04 15:56 -0700
        Re: Mechanism to generate annotated "error codes" Malcolm McLean <malcolm.mclean5@btinternet.com> - 2012-03-03 03:45 -0800
          Re: Mechanism to generate annotated "error codes" Lowell Gilbert <lgusenet@be-well.ilk.org> - 2012-03-03 14:11 -0500
            Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-03 13:03 -0700
          Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-03 12:32 -0700
        Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-03 15:04 -0700
          Re: Mechanism to generate annotated "error codes" Ian Collins <ian-news@hotmail.com> - 2012-03-04 11:09 +1300
            Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-03 16:55 -0700
              Re: Mechanism to generate annotated "error codes" Ian Collins <ian-news@hotmail.com> - 2012-03-04 13:04 +1300
                Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-03 18:24 -0700
          Re: Mechanism to generate annotated "error codes" Malcolm McLean <malcolm.mclean5@btinternet.com> - 2012-03-03 14:30 -0800
            Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-03 17:06 -0700
    Re: Mechanism to generate annotated "error codes" Ian Collins <ian-news@hotmail.com> - 2012-03-05 10:09 +1300
      Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-04 16:03 -0700
        Re: Mechanism to generate annotated "error codes" Ian Collins <ian-news@hotmail.com> - 2012-03-05 13:26 +1300
          Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-04 22:21 -0700
            Re: Mechanism to generate annotated "error codes" Ian Collins <ian-news@hotmail.com> - 2012-03-05 20:46 +1300
              Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-05 10:54 -0700
                Re: Mechanism to generate annotated "error codes" Ian Collins <ian-news@hotmail.com> - 2012-03-06 10:02 +1300
                  Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-05 16:09 -0700
              Re: Mechanism to generate annotated "error codes" "BartC" <bc@freeuk.com> - 2012-03-06 10:54 +0000
                Re: Mechanism to generate annotated "error codes" Ian Collins <ian-news@hotmail.com> - 2012-03-07 07:22 +1300
    Re: Mechanism to generate annotated "error codes" gordonb.8sa24@burditt.org (Gordon Burditt) - 2012-03-06 08:51 -0600
      Re: Mechanism to generate annotated "error codes" Don Y <this@isnotme.com> - 2012-03-06 11:21 -0700

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


#18236

FromDon Y <this@isnotme.com>
Date2012-03-05 10:54 -0700
Message-ID<jj2uld$b6d$1@speranza.aioe.org>
In reply to#18219
Hi Ian,

On 3/5/2012 12:46 AM, Ian Collins wrote:

>>> First the user or log messages have to be documented somewhere, for user
>>> documentation and testing.
>>
>> Yes. I document them IN THE CODE.
>>
>>> Scattering them throughout the code isn't a
>>> great way to do that.
>>
>> Why?
>
> Because it is easier to generate code than it is to parse code and
> extract information from an entire code base. It is also easier to
> maintain a single document in a form that can be translated in to things
> other than code (especially if you have a need to get some of the
> messages translated).

So, you have a "single document" for <stdio>, another for <math>,
another for <string>, another for <motor>, another for... (i.e.,
you *don't* have a single document *or* that single document
is the concatenation of all of these OTHER single documents).

What happens when some *aspect* of <math> never is used in your
final link?  Do you modify *that* "single document" and put it under
configuration management/version control for this project/product?

>> It ensures EVERY error code is documented. And, it keeps that
>> proximate to the actual code itself. *This* is what the code is
>> testing for... not something else that you THINK it is enforcing!
>
> Quite. The table of error codes/messages/whatever is all generated from
> one place. If a new error code is required , it has to be added to the
> master file.

And you have to manually verify that the two documents are in sync.
That the "explanation" of the error/condition/exception is in agreement
with the actual tests being performed that detect it.

>>> Second, the document is the *source* for the messages and error codes,
>>> so it will always be up to date.
>>
>> What happens when an error code is never referenced? How does
>> your document ELIDE that error code and its documentation?
>
> Nothing. How many of the error codes in a typical system header (such as
> <errno.h> on a Unix system) does any one application actually use?

But they aren't *exposed* to the end user/etc.

You put a description for EDOMAIN in your "single document" (whether
that is the <math> single document or the composite single document
formed from all-of-the-above).

The product goes to final test.

   "OK, we've verified the motor subsystem responds as required to
    all possible operating conditions.  Let's move on.  Now, how do
    I cause the EDOMAIN error to manifest?"
   "Um, let's see...  No, it doesn't appear that any of the
    functions that COULD signal that error are actually present
    in the executable.  So, to answer your question, EDOMAIN is
    something that /* CAN'T HAPPEN */"
   "<frown>  And how am *I*, charged with ensuring that your product
    meets its stated/documented specifications, supposed to know
    which of these errors can and can't occur?  How do I know that
    your code isn't buggy and FAILING to accurately detect them?"

> If new errors are added to the master file as required, this will not
> really be a problem.
>
>>>> E.g., the approach I am taking here is analagous to how Literate
>>>> Programming couples documentation with source code (except I am
>>>> only tackling the "error reporting" aspect of the task).
>>>
>>> In my case, the documentation *is* part of the source code.
>>
>> Fair enough. You should look at Literate Programming for a
>> different take on this (see URL later)
>
> We did, however code editors tend to be piss poor word processors and
> word processors tend to be piss poor text editors! It's quite easy to
> write code in Open Office and extract the code sections for compilation,
> but it's a process not well suited to contemporary tools (IDEs).
>
> On the project I mentioned, the master XML was used to generate many
> different components, including database tables and their equivalent C
> structures and enumerations. So this file had a lot more value than it
> would had it simply been used for error codes and messages. Elsewhere in
> this thread someone mentioned a function to check input values, well the
> types and range of common data types were also specified in this file,
> so all the range checking and error reporting was centralised.

Our first "experience" with integrating separate tools for
"documentation" and "coding" followed this same rationale.
We reasoned that the sorts of things we wanted to do in the
documentation (ended up in HTML) just weren't effectively
handled in a "text/programmer's editor".  And, of course, as
is always the case, no one wanted to give up the tools that
*they* had grown fond of!

We figured that we could just "dress up" our formal specifications
in a more colloquial tone and reorganize them in a way more suitable
to an "on-line manual" (of sorts).  Perfect!  since it also allowed
folks to start working on that aspect of the documentation in
parallel with the coding.

We ended up with gorgeous documentation.  The overhead for accessing
particular parts of the documentation was trivial -- effectively a
URL that was passed between the actual code and the "help system".

Things like EDOMAIN are easy to describe -- and forget -- once.
Things like MOTOR_OVERHEAT tend to get a bit more involved.  And,
remain unsettled a lot longer: "Oh, Bob, we stumbled on another
example of a common situation that, with prolonged use, will
cause the motor to overheat.  You should probably add it to the
documentation..."

It was always a game of cat and mouse -- keeping the documentation
in sync with the actual code base (these are fairly sized projects;
~40MB for the documentation) took constant diligence.  We only
used two levels of "messaging" -- a simple, short phrase (which
was enough for an experienced user to recognize The Problem)
and a link to the portion of the manual describing the issue
in detail (e.g., "Section 23.1.5:  Specifying Numeric Values").

We naively thought this was *ideal* -- have the manual at the
user's fingertips without requiring him to keep it nearby!

But, the manual presented too much information and, so, ended
up being largely ignored (!).  Calls coming in to Tech Support
were *always* answered just by the support person consulting
that very same portion of the manual as had been offered to the
user at run time.  I.e., if the user had bothered to READ it,
it would have admirably served its purpose!

Talking to users showed us that we had straddled the "sweet spot"
with our error messages -- too little or too much.  This led to
the current approach of gradually increasing detail.  At the
extreme end, the user finds himself "in" the "Manual", again,
where we can take our time/space explaining things in detail
along with examples illustrating usage, problems and potential
remedies (including interactive troubleshooting).

This increases the number of "references" between code and
"documentation" almost by an order of magnitude (e.g., in the
examples presented here, I show just two levels of "user
information"; in practice, it's more like 5 or 6 for each
"error").  More things to potentially get out of sync.

In this approach, we already acknowledge that programmers don't
always make good "teachers" ("explainers").  So, we don't expect
messages to be particularly "user friendly".  Watching the
sorts of messages that people come up with shows big differences
in style, presentation, etc.

But, programmers can be expected to ACCURATELY describe what their
code is actually doing (or *supposedly* doing).  And, can explain
to someone better equipped with "language" how errors "nest".
This other person can then clean up the actual language for each
message and (another) handle translations to other languages, etc.

Putting these in separate "master documents" just leads to more
"conflicts" as the two developers (linguist and coder) drift out of
sync:
     "Here are the texts of the error messages you need, Bob"
     "Huh?  No, I no longer have to worry about decimal points
      AT ALL!  I chose to pass data in units of 1/10 so I can
      eliminate the need for decimal points -- and the testing
      for MULTIPLE decimal points -- in those interactions.
      Clever, eh?  Oh, and, by the way, you need to reflect
      this in the 'out of range' messages since those values
      can now be 10 times higher..."
If you decouple these even *more* (i.e., linguist updates the
"master file" and Bob never has to worry about consulting it
since the build mechanism does that FOR him) then you end up
with an unreferenced error message (Err_TooManyDecimalPoints)
or an *incorrect* error message (Err_OutOfRange)

>>> Our approaches appear to be opposite. You extract messages from the
>>> code, I inject them into the code (and the tests and user
>>> documentation).
>>
>> Fair enough. My approach is "inspired" by Literate Programming
>> (http://en.wikipedia.org/wiki/Literate_programming). In either
>> approach, you need to have a tool/utility massage a file (or
>> files) to generate the actual "source" and supporting files.
>
> I believe the the tools required to generate code from XML are much
> simpler than those required to extract documentation form code (other
> than from code comments).

That was why I opted for a syntactically simple implementation:
"MakeErrorCode" is just a "tag" that I can locate and excise from
the source file (replacing the line(s) that it occupies with
empty lines).  The tool that does so doesn't need to be aware
of any C syntax.  Nor does it interfere with any C *statements*.

It plays the role of a "#specialcomment" (I had thought of trying
to implement it as a #pragma but figured that tied it to the
language too much)

>> I bundle it in the source because I can just let MakeErrorCode
>> be a macro that doesn't alter the source (Literate Programming
>> requires the source to be "extracted" -- "tangled").
>
> But it doesn't solve the uniqueness problem. With a master file, you
> don't have to worry, or even define the error values. The translator can
> do that for you.

See my response to Shao.  Mechanically, it (well, this newest version)
provides everything I want -- uniqueness, unused errors "disappear"
from the documentation automatically, scales linearly, can be used
independently by multiple developers (only the errors that are
defined in the modules *you* are using need be concerned with), tells
me where it is "defined"/raised in the code, etc.

But, it doesn't "encourage" (force is too strong a word) developers
to "use it the right way".  A "conforming" use might be, for example
(pseudocode):

    function() {
       ...
       // test for "foo" condition
       if () {
           MakeErrorCode(foo1, ...)
           // handle foo condition
           ...
           error = foo1;
       }
       ...
       // test for "bar" condition
       if () {
           MakeErroCode(bar, ...)
           // handle bar condition
           ...
           error = bar;
       }
       ...
       // test for some other variant/instance of "foo" condition
       if () {
           MakeErrorCode(foo2, ...)
           // handle other foo condition
           ...
           error = foo2;
       }
       ...
       // report <whatever> condition
       ...
   }

This causes each error code to be associated with the actual
test (line number) that detected it and ensures that each
such test is uniquely identified by an error code.

But, there is nothing that prevents the developer from doing:

    MakeErrorCode(foo, ...)
    MakeErrorCode(bar, ...)

    function() {
       ...
       // test for "foo" condition
       if () {
           // handle foo condition
           ...
           error = foo;
       }
       ...
       // test for "bar" condition
       if () {
           // handle bar condition
           ...
           error = bar;
       }
       ...
       // test for some other variant/instance of "foo" condition
       if () {
           // handle other foo condition
           ...
           error = foo;
       }
       ...
       // report <whatever> condition
       ...
   }

Note that two different criteria that enforce "foo" have been
reported using the same error code (foo).  And, that neither foo
nor bar give any clue as to which line -- or *function* -- is
associated with the "error".  (Indeed, the developer could have
placed the MakeErrorCode instances in a *header* file and
things would still have worked!)

So, it ends up much like "goto" -- relying on peer pressure, code
reviews, "policy", etc. to ensure that it is "deployed" properly.
I'm looking for ways to increase the likelihood of "conforming"
behavior from developers...

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


#18246

FromIan Collins <ian-news@hotmail.com>
Date2012-03-06 10:02 +1300
Message-ID<9rknveFg0kU1@mid.individual.net>
In reply to#18236
On 03/ 6/12 06:54 AM, Don Y wrote:
> Hi Ian,
>
> On 3/5/2012 12:46 AM, Ian Collins wrote:
>
>>>> First the user or log messages have to be documented somewhere, for user
>>>> documentation and testing.
>>>
>>> Yes. I document them IN THE CODE.
>>>
>>>> Scattering them throughout the code isn't a
>>>> great way to do that.
>>>
>>> Why?
>>
>> Because it is easier to generate code than it is to parse code and
>> extract information from an entire code base. It is also easier to
>> maintain a single document in a form that can be translated in to things
>> other than code (especially if you have a need to get some of the
>> messages translated).
>
> So, you have a "single document" for<stdio>, another for<math>,
> another for<string>, another for<motor>, another for... (i.e.,
> you *don't* have a single document *or* that single document
> is the concatenation of all of these OTHER single documents).

Only for our own stuff.  Everything else is already documented and tested.

<snip>

>>>> Our approaches appear to be opposite. You extract messages from the
>>>> code, I inject them into the code (and the tests and user
>>>> documentation).
>>>
>>> Fair enough. My approach is "inspired" by Literate Programming
>>> (http://en.wikipedia.org/wiki/Literate_programming). In either
>>> approach, you need to have a tool/utility massage a file (or
>>> files) to generate the actual "source" and supporting files.
>>
>> I believe the the tools required to generate code from XML are much
>> simpler than those required to extract documentation form code (other
>> than from code comments).
>
> That was why I opted for a syntactically simple implementation:
> "MakeErrorCode" is just a "tag" that I can locate and excise from
> the source file (replacing the line(s) that it occupies with
> empty lines).  The tool that does so doesn't need to be aware
> of any C syntax.  Nor does it interfere with any C *statements*.

I don't think we are disagreeing, merely describing different approaches 
to a similar problem.

In our case, the master files (they were hierarchical for a family of 
products with a common core) where used for a lot more than errors. 
They included definitions of the types, structures and enumerations in 
our database.  They also defined the database and user menu structure. 
A lot of code was generated from them, including range checking and 
serialisation.  So it made sense to do as much as possible in one place.

-- 
Ian Collins

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


#18252

FromDon Y <this@isnotme.com>
Date2012-03-05 16:09 -0700
Message-ID<jj3h2e$r36$1@speranza.aioe.org>
In reply to#18246
Hi Ian,

On 3/5/2012 2:02 PM, Ian Collins wrote:

>> That was why I opted for a syntactically simple implementation:
>> "MakeErrorCode" is just a "tag" that I can locate and excise from
>> the source file (replacing the line(s) that it occupies with
>> empty lines). The tool that does so doesn't need to be aware
>> of any C syntax. Nor does it interfere with any C *statements*.
>
> I don't think we are disagreeing, merely describing different approaches
> to a similar problem.

Agreed.  I'm trying to point out the issues that we've encountered
that "strongly encourage" less "human involvement" in the process.

E.g., trying to "force" MakeErrorCode to be placed at the right
spot in the file will, I *know*, lead to arguments over exactly
where that spot should be in each instance (IMO, "wherever it
becomes clear that this *is* an instance of the particular 'error'")

*You* have to come up with a solution that fits the size, personnel,
skill and discipline of your application/team.  If it works, great!
If it doesn't, tweak it (which is how *we* ended up going down this
road).

> In our case, the master files (they were hierarchical for a family of
> products with a common core) where used for a lot more than errors. They
> included definitions of the types, structures and enumerations in our
> database. They also defined the database and user menu structure. A lot
> of code was generated from them, including range checking and
> serialisation. So it made sense to do as much as possible in one place.

You would find our current approach, here, interesting.  Damn near
*every* "table" has been removed from the code and instantiated in
the database.  Couple this with lots of table driven code and
you magically expose (for modification) much of the software
without necessitating actually modifying the executables.

(the jury is still out on what the actual performance hit will be)

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


#18259

From"BartC" <bc@freeuk.com>
Date2012-03-06 10:54 +0000
Message-ID<jj4qe2$ael$1@dont-email.me>
In reply to#18219
"Ian Collins" <ian-news@hotmail.com> wrote in message
news:9rj9aoFi9oU1@mid.individual.net...
> On 03/ 5/12 06:21 PM, Don Y wrote:

> On the project I mentioned, the master XML was used to generate many
> different components, including database tables and their equivalent C
> structures and enumerations.  So this file had a lot more value than it
> would had it simply been used for error codes and messages.

Sounds like you weren't writing in C at all. Especially if the source is
supposed to look like XML.

Or do your tools allow you to write actual C code (for the executable 
stuff), but store it in this high-level format, and only produce properly 
formatted C for the purposes of compilation? (Or to allow perusal by anybody 
else?)

What would a heavily documented, commented and error-checked version of
Hello World look like in this scheme?

-- 
Bartc 

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


#18270

FromIan Collins <ian-news@hotmail.com>
Date2012-03-07 07:22 +1300
Message-ID<9rn2vdFg0kU5@mid.individual.net>
In reply to#18259
On 03/ 6/12 11:54 PM, BartC wrote:
> "Ian Collins"<ian-news@hotmail.com>  wrote in message
> news:9rj9aoFi9oU1@mid.individual.net...
>> On 03/ 5/12 06:21 PM, Don Y wrote:
>
>> On the project I mentioned, the master XML was used to generate many
>> different components, including database tables and their equivalent C
>> structures and enumerations.  So this file had a lot more value than it
>> would had it simply been used for error codes and messages.
>
> Sounds like you weren't writing in C at all. Especially if the source is
> supposed to look like XML.
>
> Or do your tools allow you to write actual C code (for the executable
> stuff), but store it in this high-level format, and only produce properly
> formatted C for the purposes of compilation? (Or to allow perusal by anybody
> else?)

We generated types, and some boilerplate, not the application logic. 
The exception was the menu structure, which was another XML file read by 
the application at run time.

-- 
Ian Collins

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


#18266

Fromgordonb.8sa24@burditt.org (Gordon Burditt)
Date2012-03-06 08:51 -0600
Message-ID<17KdnUKUw7zqucvSnZ2dnUVZ_uSdnZ2d@posted.internetamerica>
In reply to#18090
> I have a suite of projects that utilize a common approach to
> error reporting.  Instead of a PASS/FAIL result, most functions
> return information regarding the nature of the "failure" (which
> can also include "partial failures"... "warnings").  These
> reports allow upper levels of the application to convey those
> details to the user without exposing all of the *mechanism*
> involved to those upper levels.

One approach I've seen used in BSD's libcom_err is to have different
library modules that can each register their own blocks of error
codes.  Any module can take one of the error codes (which it doesn't
necessarily recognize) and call the equivalent of strerror() to
come up with a text message to describe the problem to the user.
There isn't really a concept of "severity" of an error code but you
could add that.  You don't need a centralized location with a full
list of all the error codes.  Along with this comes the need to
vary the error message depending on the language of the user.  You
probably do need to assign a (unique) name for a block of error
codes, which might be the name of the library or subdivision of it.

There's a problem with this approach alone.  A *good* description of
the error needs variable parts dependent on the situation.

Poor:  Cannot open input file.
Almost as bad:  Cannot open input file:  File does not exist.
A bit better:  Cannot open input file '/hme/ralph/foo.txt'.
Good:  Cannot open input file '/hme/ralph/foo.txt': File does not exist.

It's very important to get the file name into the message, especially
if the name came from a command-line argument or other form of user
input.  (In this case, it is likely that the user mis-spelled the
"home" part of the filename.)

I might come up with a small set of parameters the error report can return,
and try to fit the messages into that:
	1 error code (mandatory) that can be translated into error text.
	2-4 strings
	1-2 integers
	1-2 floating point numbers

You should be able to tell which of these values were returned along
with the error (*NOT* the first integer is 0 indicating a minimum
value of 0, or 0 indicating the value was not supplied, and I'm not
going to tell you which).

The error message and the returned values go together.  A common
routine (*NOT* specific to a particular module) can create a
situation-specific message by substituting values into the message
text at appropriate places.

> E.g., the application may need a numeric value from the user
> with a particular set of constraints (must be positive, less
> than 293, no more than two decimals, etc.).  Of course, it would
> be silly for the upper levels of the application to process
> individual characters to assemble such a "value" and enforce
> those constraints.

The prompt should probably indicate the range of acceptable values
(which doesn't excuse you from range-checking what the user types).
What constitutes a valid number shouldn't have to be repeated
endlessly.

One issue to remember is that the lack of an error from a lower-level
routine may be an error to a higher-level routine.  For example,
success in checking for the existence of a file may trigger a
higher-level routine to ask "File '/home/you/calendar' already
exists - overwrite?"


> [Note that "from the user" could just as easily be "from a
> file"... i.e., how the error is ultimately reported/handled
> is something that the upper level routines should decide,
> not this lower level function]

It may be a good idea to *show the user* what the bad input was,
especially if it might be coming from a file the user can't see.


> For example, the lower level routine might report:
> - invalid character encountered
> - value below minimum allowed
> - value exceeds maximum allowed
> - too many significant digits
> 
> The "invalid character" report might be embelished:
> - only one decimal point allowed
> - only one *sign* allowed
> - non-digit encountered

"Only one decimal point allowed" might be more correctly reported
as "multiple numbers should be separated by commas" in a situation
where multiple numbers are a legitimate possibility.

At some point, diagnosing the input in excruciating detail makes
you look silly (and often wrong).  And it might be better to say
*which field* on *which line* is wrong, rather than making the user
look through a 5 meg input file for a single decimal point that
should have been a comma.

> Etc.  The information conveyed by each of these allows the
> application to inform the user of the exact nature of the
> "problem" -- instead of just resorting to a "bad value"
> report.

Make sure that the user can get out of the error situation in a
reasonable manner.  For example, if the user has been repeatedly
entering an out-of-range age for a child he wishes to enroll, perhaps
it would be appropriate to back up and let him change his previous
answer to "Do you wish to enroll another child?" which he read as
"Do you have another child?" from YES to NO.  (He said YES, tried
to enter the age for his baby, then realized they were only asking
for children old enough to enroll in this school, so the correct
age of his baby is an error.)  A CANCEL button on a popup asking
for a set of information can be useful here.
 
> Each possible "report" needs a mechanism through which the
> caller can ascertain the nature of the error.  You *could*
> impose a convention that causes reports to be more easily
> summarized:  e.g., 0 for SUCCESS, <0 for errors, >0 for
> warnings (so, if you don't care about warnings the caller
> would test for any "not negative" result codes as being
> "acceptable" -- as in the case of SUCCESS or "too many
> significant digits").

The direct caller of a routine such as "input an integer" routine
probably has to know the range of acceptable values (which it has
to pass to the input function) and may need to know about a few of
the specific error codes it can return.

> Of course, there's nothing difficult or magical about this.
> Create an enumeration or a set of manifest constants to
> symbolically represent each of the "results", package them
> in a header file and you're all set!

Along with this, you might have rules that say that all of the
"input an integer" error codes set string#1 to the user input and
integer#1 to the length of that input, for use in the error
message and perhaps for handling by the caller.

> That approach is fine for "small" functions with a limited
> number of potential "results".  But, consider how you would
> scale it to more comprehensive functions.  E.g., the complete
> UI.  Managing these "enumerations" gets to be tedious and
> error prone.  "Which *values* have been assigned?  What is
> a good value to pick for this new 'condition'?  etc."

This is the reason for suggesting that each routine have its own
block of error codes, without worrying too much about "wasting"
them.  For example, libcom_err gives a block of 256 error codes
to each routine.  If it needs more, it can use two blocks.
Since there are 2^23 blocks, running out should not be a problem.

> One approach to ensuring unique "values" for each of these
> "results" is to synthesize them from the function/file name
> and line number where they are detected (instantiating a
> macro at that particular point).  This ensures that values
> are unique while hiding the *actual* value from the developer
> (*I* surely don't care if TOO_MANY_DECIMAL_POINTS resolves
> to 0x27 or 0x7732!).
 
> The problem then becomes one of making that information available
> to other *consumers*!  I.e., wrapping it in a header file that
> others can reference.

Each module provides its own header file, which would include:
	- prototypes for functions in the module you can call.
	- data types used by those functions
	- A list of possible error codes generated by those functions.

You'd have to include that header file anyway for the function
prototypes if you use that module whether there are error codes
included or not.

> [Note this opens the door for a bootstrap problem but I am
> willing to live with that -- "I'll deal with it later..."]

libcom_err also manages to include the set of error codes returned
in errno from system calls, using a bit of system-dependent knowledge
of which codes are used.

> A "solution" also needs to address the problem of *explaining*
> the "result" (to the ultimate user).  The point at which the
> result is "signaled" contains the most information about the
> nature of the "problem" being reported though it is in a
> very narrowly defined context:  i.e., you can tell the user
> "Multiple decimal points encountered" -- though you can't
> indicate the role that the value being entered plays in the
> application (is this a person's wages?  the weight of a
> newborn child?  the average lifespan of a male tortoise?).

"Multiple decimal points encountered" is equally an error regardless
of what that value represents.

The prompt for the value should indicate the data being requested,
and the units of it.  That weight of a newborn child is in *grams*,
not ounces, which might explain the complaint about the number being
too small, and the average lifespan of a male tortoise is in
*years*.

> So, the developer should be able to tie the explanation/commentary
> *to* the (symbolic) result code where the result code is defined
> instead of having to do so "somewhere else" -- hoping to keep the
> explanations in sync with the symbolic names, etc.
> 
> A code fragment with such a system might look like:
> 
>    if (*ptr == '.') {
>       if (decimalPointEncountered == TRUE) {
> 
> MakeErrorCode(Err_TooManyDecimalPoints,
>               "Multiple decimal points encountered.",
>               "Only a single decimal point is allowed in numeric
>                  values."
>               )

You forgot here to include the string that had too many decimal points,
and, perhaps, which file and which line it was on.

>           result = Err_TooManyDecimalPoints;
>       } else {
>           decimalPointEncountered = TRUE;
>       }
>    }
>    ...
>    return (result);
 
> Obviously, a macro could #define Err_TooManyDecimalPoints to a unique
> value, here (e.g., __FILE__ ## __LINE__).   A script could parse the
> output of the preprocessor extracting all lines of the form
> "#define Err_" to build a suitable header file.  And, another
> script could extract the short and long textual explanations of
> the error itself.
> 
> I currently do this with a mix of ad hoc measures.  As such,
> it is very fragile (and an annoying drain on my time!).  I'm
> hoping for suggestions that might lead me to a better/different
> approach (WITH THE SAME GOALS).  Pointers to tools better suited
> to this.  *Or*, examples of similar approaches!!

GNU gettext also deals with extracting messages from source
code with the intent of having them translated for multiple
languages.  You might take ideas from this, or decide you need
to use it for internationalization.

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


#18269

FromDon Y <this@isnotme.com>
Date2012-03-06 11:21 -0700
Message-ID<jj5kif$ld0$1@speranza.aioe.org>
In reply to#18266
Hi Gordon,

On 3/6/2012 7:51 AM, Gordon Burditt wrote:
>> I have a suite of projects that utilize a common approach to
>> error reporting.  Instead of a PASS/FAIL result, most functions
>> return information regarding the nature of the "failure" (which
>> can also include "partial failures"... "warnings").  These
>> reports allow upper levels of the application to convey those
>> details to the user without exposing all of the *mechanism*
>> involved to those upper levels.
>
> One approach I've seen used in BSD's libcom_err is to have different
> library modules that can each register their own blocks of error

Different environment.  That tries to accommodate an open-ended
error space that is dynamically reconfigurable.

Imagine if you didn't know what ERANGE was until run time?

> codes.  Any module can take one of the error codes (which it doesn't
> necessarily recognize) and call the equivalent of strerror() to
> come up with a text message to describe the problem to the user.
> There isn't really a concept of "severity" of an error code but you
> could add that.  You don't need a centralized location with a full
> list of all the error codes.

To clarify (in case you haven't read the rest of the thread):
I don't want a DEVELOPERS MAINTAINED "centralize location with a
full list of all the error codes".  I.e., I don't want developers
having to coordinate which "code" is assigned to which symbolic
error name.

But, *I* (which might not be a requirement for others employing
such a system) want to be able to CENTRALIZE the messages associated
with those individual error codes so that, e.g., they need not be
part of the executable images.  And, so that they can be embellished
without constraint (if I want to write a 5 page description of a
particular error code -- including examples and remedies -- I should
be free to do so *if* I have a way of storing that <somewhere>)

> Along with this comes the need to
> vary the error message depending on the language of the user.

Yes.  Note that the actual *nature* of the user can be addressed
with this, as well.  E.g., you might have a "locale" called "devel"
which provides messages specifically designed for the development
environment containing details that a "real user" would neither
be interested in nor capable of comprehending.

Likewise, your "user" might be another process on the other end
of a network connection.  Reporting "Relay denied" puts a significant
decoding burden on the (remote) "caller" whereas "550" requires very
little overhead and conveys the exact nature of the problem!

> You
> probably do need to assign a (unique) name for a block of error
> codes, which might be the name of the library or subdivision of it.
>
> There's a problem with this approach alone.  A *good* description of
> the error needs variable parts dependent on the situation.

Yes.  As I have stated, I have chosen to ignore this in this discussion
as it just adds another level of detail that doesn't substantially alter
the problem.

[I'm eliding most of that related discussion, here]

>> E.g., the application may need a numeric value from the user
>> with a particular set of constraints (must be positive, less
>> than 293, no more than two decimals, etc.).  Of course, it would
>> be silly for the upper levels of the application to process
>> individual characters to assemble such a "value" and enforce
>> those constraints.
>
> The prompt should probably indicate the range of acceptable values
> (which doesn't excuse you from range-checking what the user types).
> What constitutes a valid number shouldn't have to be repeated
> endlessly.

This is something that the application decides -- not related to
"error reporting".

>> For example, the lower level routine might report:
>> - invalid character encountered
>> - value below minimum allowed
>> - value exceeds maximum allowed
>> - too many significant digits
>>
>> The "invalid character" report might be embelished:
>> - only one decimal point allowed
>> - only one *sign* allowed
>> - non-digit encountered
>
> "Only one decimal point allowed" might be more correctly reported
> as "multiple numbers should be separated by commas" in a situation
> where multiple numbers are a legitimate possibility.

The whole point of this is to illustrate how context influences
how an error is reported.  An "upper layer" -- one that might be
expecting two values separated by a delimiter -- invokes get_value(),
twice.  *It* sees "Err_TooManyDecimalPoints" returned from the
first invocation.  It's possible that the user has entered two
values with no intervening whitespace *and* no delimiter.  Or,
just typed "123..456".  OTOH, if the same error is returned on
the second invocation, the expecation is that this was SUPPOSED
to be a single value -- we've already seen the "first" of the
two values!

How that upper layer interprets this error AND WHAT *it* REPORTS
is up to the code in that layer.  Each layer interprets errors
reported to it IN ITS OWN CONTEXT and decides how to report
that "situation".  The easy way out is just to relay the
error message handed to you.  That's how things were done in the
1970's  :>

But, that error message was created by something (the "underling")
that had no knowledge of the context in which the report is being
conveyed to the user!  I.e., get_value doesn't know that there are
*two* values expected!  So, anything that get_value could conceivably
report can't account for that possibility (without being foolish!)

    // get first value
    result = get_value(... &msg);
    if (result == Err_TooManyDecimalPoints) {
        printf("Have you forgotten a delimiter between values?")
        break;
    }
    // verify and skip over delimiter
    ...
    // get second value
    result = get_value(... &msg);
    if (result == Err_TooManyDecimalPoints) {
        printf("A value can only have one decimal point.")
        break;
    }

> At some point, diagnosing the input in excruciating detail makes
> you look silly (and often wrong).

The problem is that you don't want to have to embed all of the
knowledge of every possible condition in the upper layer.  E.g.,
it could reparse the input string (Gee, didn't get_value do that
already?) and notice "###..###" vs. "###.###.###" and *guess*
that the latter is more likely a missing delimiter case while
the former is probably a keybounce.  But, that defeats the
purpose of hiding detail in the get_value layer.

>> Etc.  The information conveyed by each of these allows the
>> application to inform the user of the exact nature of the
>> "problem" -- instead of just resorting to a "bad value"
>> report.
>
> Make sure that the user can get out of the error situation in a
> reasonable manner.  For example, if the user has been repeatedly
> entering an out-of-range age for a child he wishes to enroll, perhaps
> it would be appropriate to back up and let him change his previous
> answer to "Do you wish to enroll another child?" which he read as
> "Do you have another child?" from YES to NO.  (He said YES, tried
> to enter the age for his baby, then realized they were only asking
> for children old enough to enroll in this school, so the correct
> age of his baby is an error.)  A CANCEL button on a popup asking
> for a set of information can be useful here.

Different issue entirely.

>> Each possible "report" needs a mechanism through which the
>> caller can ascertain the nature of the error.  You *could*
>> impose a convention that causes reports to be more easily
>> summarized:  e.g., 0 for SUCCESS,<0 for errors,>0 for
>> warnings (so, if you don't care about warnings the caller
>> would test for any "not negative" result codes as being
>> "acceptable" -- as in the case of SUCCESS or "too many
>> significant digits").
>
> The direct caller of a routine such as "input an integer" routine
> probably has to know the range of acceptable values (which it has
> to pass to the input function) and may need to know about a few of
> the specific error codes it can return.

But, you could craft the "get_integer" routine to be parameterized
with min_value and max_value -- so that *it* does the range checking
and just reports the result of those checks to the caller.  This
cleans up the calling code and ensures values are consistently
checked.

>> That approach is fine for "small" functions with a limited
>> number of potential "results".  But, consider how you would
>> scale it to more comprehensive functions.  E.g., the complete
>> UI.  Managing these "enumerations" gets to be tedious and
>> error prone.  "Which *values* have been assigned?  What is
>> a good value to pick for this new 'condition'?  etc."
>
> This is the reason for suggesting that each routine have its own
> block of error codes, without worrying too much about "wasting"
> them.  For example, libcom_err gives a block of 256 error codes
> to each routine.  If it needs more, it can use two blocks.
> Since there are 2^23 blocks, running out should not be a problem.

"Famous last words"  :>

Why do you need error codes to be contiguous?  What happens when you
can't assign all of the error codes in a contiguous range?  (a library
grows and needs a 257th error condition).

You don't want error codes (CONDITIONS!) to be considered a scarce
resource.  That puts pressure on you to conserve error codes.
(when you've used up 240 codes in your block, don't you think
the developer starts hedging his use of NEW codes -- just so he
doesn't have to get another block?)

You see this sort of thinking every day.  People want to "pre_allocate"
a block of part numbers for the various subassemblies in the product
they are designing.  Or, want to assign employee numbers based on
what department they are working in.  Or...

Have <something> assign a number (i.e., "representation") that hasn't
been used, yet.  Record that choice (this is what liberr does -- except
it does that at run-time).  When you need another "number", take
whatever that <something> gives you -- which might bear no resemblance
to the thing you were given for your previous request!

Let machines deal with the tedium of tracking which department
employee 00004 works in or where subassembly 234887 is used.

Or, what "Err_TooManyDecimalPoints" means!

>> One approach to ensuring unique "values" for each of these
>> "results" is to synthesize them from the function/file name
>> and line number where they are detected (instantiating a
>> macro at that particular point).  This ensures that values
>> are unique while hiding the *actual* value from the developer
>> (*I* surely don't care if TOO_MANY_DECIMAL_POINTS resolves
>> to 0x27 or 0x7732!).
>
>> The problem then becomes one of making that information available
>> to other *consumers*!  I.e., wrapping it in a header file that
>> others can reference.
>
> Each module provides its own header file, which would include:
> 	- prototypes for functions in the module you can call.
> 	- data types used by those functions
> 	- A list of possible error codes generated by those functions.
>
> You'd have to include that header file anyway for the function
> prototypes if you use that module whether there are error codes
> included or not.

This requires the error codes to be known at compile time.
Forces them to be "constants" (since the header file is
a string of "constant characters").  *And* requires every
processing unit to have its own header file!  I.e., if
get_value throws Err_GetFoo and put_value throws Err_PutFoo,
it is possible that get_value might be included in a link
while put_value is not!  (you've used up an error code
that could have been used by something else!)

>> A "solution" also needs to address the problem of *explaining*
>> the "result" (to the ultimate user).  The point at which the
>> result is "signaled" contains the most information about the
>> nature of the "problem" being reported though it is in a
>> very narrowly defined context:  i.e., you can tell the user
>> "Multiple decimal points encountered" -- though you can't
>> indicate the role that the value being entered plays in the
>> application (is this a person's wages?  the weight of a
>> newborn child?  the average lifespan of a male tortoise?).
>
> "Multiple decimal points encountered" is equally an error regardless
> of what that value represents.

But in one case, the application knows the user is specifying
an infant's weight.  Instead of an impersonal, generic "too many
decimal points" message (which is what get_value would report),
the application can say "The infant's weight can contain at most one
decimal point".

This acts as an interlock with the user reassuring him that
the application is in lock step with his actions.

Or, alerting the user to the fact that he is NOT where he
thinks he was!  "Whaddya mean, 'infant's weight'?  I thought I
was typing in my password!!"

> The prompt for the value should indicate the data being requested,
> and the units of it.  That weight of a newborn child is in *grams*,
> not ounces, which might explain the complaint about the number being
> too small, and the average lifespan of a male tortoise is in
> *years*.

Again, that is an application specific issue.  If the input is
coming from a file, the application isn't "prompting" the filesystem
"OK, now I need the tortoise's age, in years please.  Great!  Now
the infant's weight -- in grams..."

>> So, the developer should be able to tie the explanation/commentary
>> *to* the (symbolic) result code where the result code is defined
>> instead of having to do so "somewhere else" -- hoping to keep the
>> explanations in sync with the symbolic names, etc.
>>
>> A code fragment with such a system might look like:
>>
>>     if (*ptr == '.') {
>>        if (decimalPointEncountered == TRUE) {
>>
>> MakeErrorCode(Err_TooManyDecimalPoints,
>>                "Multiple decimal points encountered.",
>>                "Only a single decimal point is allowed in numeric
>>                   values."
>>                )
>
> You forgot here to include the string that had too many decimal points,
> and, perhaps, which file and which line it was on.

As I said at the start, I am not returning "data" to the user in
this discussion.

FILE/LINE/func are handled by MakeErrorCode -- so the developer doesn't
need to deal with that "detail".  Note that all of the information
provided to and generated by MakeErrorCode is passed "out of band".
All the caller needs is a *handle* that:
- tells him that this was an error (not a warning, etc.)
- tells him *which* error it was (if he wants to take remedial action)
- tells him how to find more information about the error

The mechanism is lightweight, from the developer's standpoint.
He doesn't have to "do" much to use it or take advantage of the
features that it provides.

>>            result = Err_TooManyDecimalPoints;
>>        } else {
>>            decimalPointEncountered = TRUE;
>>        }
>>     }
>>     ...
>>     return (result);
>
>> Obviously, a macro could #define Err_TooManyDecimalPoints to a unique
>> value, here (e.g., __FILE__ ## __LINE__).   A script could parse the
>> output of the preprocessor extracting all lines of the form
>> "#define Err_" to build a suitable header file.  And, another
>> script could extract the short and long textual explanations of
>> the error itself.
>>
>> I currently do this with a mix of ad hoc measures.  As such,
>> it is very fragile (and an annoying drain on my time!).  I'm
>> hoping for suggestions that might lead me to a better/different
>> approach (WITH THE SAME GOALS).  Pointers to tools better suited
>> to this.  *Or*, examples of similar approaches!!
>
> GNU gettext also deals with extracting messages from source
> code with the intent of having them translated for multiple
> languages.  You might take ideas from this, or decide you need
> to use it for internationalization.

[toc] | [prev] | [standalone]


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

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


csiph-web