defenestration 
Author Message
 defenestration

I'm trying to read the source code for a C program that is intended to
compile either under Microsoft Windows or under Unix. Therefore, it is
full of preprocessor commands of the form #ifdef WINDOWS <a> #else <b> #endif
and #ifndef WINDOWS <c> #else <d> #endif. I find these very distracting,
as it is already hard enough to read source code even under the best
conditions. The source consists of several .c files and .h files. I've been
going through them by hand and trying to edit them to replace every
#ifdef WINDOWS <a> #else <b> #endif by <b> and every
#ifndef WINDOWS <c> #else <d> #endif by <c>. This is somewhat labor
intensive but not more than I can do in an hour or so. It is also error
prone, but so far the resulting files still yield a properly running
program. However, it occurred to me that it might not be that difficult
to accomplish this automatically with a suitable program. Leaving aside
the fact that I am not very good at programming, it seems that such a
program would basically duplicate some of the functions that are already
in the C preprocessor of gcc.

I would be surprised if there is an option for cpp which will simply
modify source code in this way but if it is not hard to scavenge the
source code for cpp to do this, it would be nice to know how to do it.
Does anyone know exactly what to do?

As I explained above, I can manage without it in this case, but it would
be nice to be able to avoid having to do so in the future.

Ignorantly,
Allan Adler

****************************************************************************
*                                                                          *
*  Disclaimer: I am a guest and *not* a member of the MIT Artificial       *
*              Intelligence Lab. My actions and comments do not reflect    *
*              in any way on MIT. Moreover, I am nowhere near the Boston   *
*              metropolitan area.                                          *
*                                                                          *
****************************************************************************
--



Sun, 04 Sep 2005 12:32:29 GMT  
 defenestration


Quote:
>As I explained above, I can manage without it in this case, but it would
>be nice to be able to avoid having to do so in the future.

I think you are suffering from a badly designed program. The way I have
always been taught to deal with OS issues is to extract all OS dependant
code into its own files(s). With a reasonable version control system you
then can just have a Windows version and a Unix version.

I know this does not solve your problem but perhaps thinking about the
idea might let you see how investing some extra time up front could
greatly ease future maintenance.

--
ACCU Spring Conference 2003 April 2-5
The Conference you cannot afford to miss
Check the details: http://www.accuconference.co.uk/
Francis Glassborow      ACCU
--



Mon, 05 Sep 2005 01:17:49 GMT  
 defenestration

Quote:
> I'm trying to read the source code for a C program that is intended to
> compile either under Microsoft Windows or under Unix. Therefore, it is
> full of preprocessor commands of the form #ifdef WINDOWS <a> #else <b>
#endif
> and #ifndef WINDOWS <c> #else <d> #endif. I find these very distracting,
> as it is already hard enough to read source code even under the best
> conditions. The source consists of several .c files and .h files. I've
been
> going through them by hand and trying to edit them to replace every
> #ifdef WINDOWS <a> #else <b> #endif by <b> and every
> #ifndef WINDOWS <c> #else <d> #endif by <c>. This is somewhat labor
> intensive but not more than I can do in an hour or so. It is also error
> prone, but so far the resulting files still yield a properly running
> program. However, it occurred to me that it might not be that difficult
> to accomplish this automatically with a suitable program. Leaving aside
> the fact that I am not very good at programming, it seems that such a
> program would basically duplicate some of the functions that are already
> in the C preprocessor of gcc.

> I would be surprised if there is an option for cpp which will simply
> modify source code in this way but if it is not hard to scavenge the
> source code for cpp to do this, it would be nice to know how to do it.
> Does anyone know exactly what to do?

With gcc, you can run the preprocessor with

    gcc -E  <other options and filenames>

IIRC, it squirts preprocessed output to stdout, but I may stand corrected
on that.   The code output will have all #include's and macro expansions
expanded, and will not necessarily be particularly readable as a result.
Keep in mind that the output text will be C (or C++, depending on the
compiler) that will almost certainly be compiler specific.

Other compilers usually have an option (or a separate executable available)
that allows running the preprocessor only.  Check the compiler
documentation.

I would suggest a better way would be to write a macro with a good text
editor (eg emacs) so you only selectively expand what you want to (rather
than expand *everything* like a preprocessor does).
--



Mon, 05 Sep 2005 01:18:05 GMT  
 defenestration
Depends on the compiler you are using.  On most a -E option with
the -DWINDOWS would generate the file.

You could do something like
for file in *.c *.h
do
        gcc -E -DWINDOWS $file > $file.windows
        gcc -E $file > $file.unix
done

assuming you are on unix with some kind of a sh...

i.

<snip>
--



Mon, 05 Sep 2005 01:18:13 GMT  
 defenestration
Do you really need to eliminate the iddef'ed code from the source
files, or is the problem just that it makes the code hard to read on a
screen?

If it's the latter, perhaps all you need is an intelligent editor
which understands C code.  Using the rule that "if programmers want
it, emacs has it", I found an emacs mode called "hideif".  Here's the
brief description:

;; Hide-ifdef suppresses the display of code that the preprocessor wouldn't
;; pass through.  The support of constant expressions in #if lines is
;; limited to identifiers, parens, and the operators: &&, ||, !, and
;; "defined".  Please extend this.

Quote:

> I'm trying to read the source code for a C program that is intended to
> compile either under Microsoft Windows or under Unix. Therefore, it is
> full of preprocessor commands of the form #ifdef WINDOWS <a> #else <b> #endif
> and #ifndef WINDOWS <c> #else <d> #endif. I find these very distracting,
> as it is already hard enough to read source code even under the best
> conditions. The source consists of several .c files and .h files. I've been
> going through them by hand and trying to edit them to replace every
> #ifdef WINDOWS <a> #else <b> #endif by <b> and every
> #ifndef WINDOWS <c> #else <d> #endif by <c>. This is somewhat labor
> intensive but not more than I can do in an hour or so. It is also error
> prone, but so far the resulting files still yield a properly running
> program. However, it occurred to me that it might not be that difficult
> to accomplish this automatically with a suitable program. Leaving aside
> the fact that I am not very good at programming, it seems that such a
> program would basically duplicate some of the functions that are already
> in the C preprocessor of gcc.

> I would be surprised if there is an option for cpp which will simply
> modify source code in this way but if it is not hard to scavenge the
> source code for cpp to do this, it would be nice to know how to do it.
> Does anyone know exactly what to do?

> As I explained above, I can manage without it in this case, but it would
> be nice to be able to avoid having to do so in the future.

--
--

--



Mon, 05 Sep 2005 01:18:24 GMT  
 defenestration
On 19 Mar 2003 17:17:49 GMT, Francis Glassborow

Quote:



>>As I explained above, I can manage without it in this case, but it would
>>be nice to be able to avoid having to do so in the future.

>I think you are suffering from a badly designed program. The way I have
>always been taught to deal with OS issues is to extract all OS dependant
>code into its own files(s). With a reasonable version control system you
>then can just have a Windows version and a Unix version.

This really doesn't work very well for header files, where this
technique is most often seen. Even with a good version control system,
I wouldn't want multiple files with the same name and differing
contents.

For an obvious example, think about how many combinations of source
and header files would be required to support the many POSIX
compile-time options.

Quote:

>I know this does not solve your problem but perhaps thinking about the
>idea might let you see how investing some extra time up front could
>greatly ease future maintenance.

>--
>ACCU Spring Conference 2003 April 2-5
>The Conference you cannot afford to miss
>Check the details: http://www.accuconference.co.uk/
>Francis Glassborow      ACCU

--
Al Balmer
Balmer Consulting

--



Tue, 06 Sep 2005 04:47:00 GMT  
 defenestration
[about removing #ifdef's from a program]

Check your system for the "unifdef" command.  If you don't have it, you
can get the source from any of the *BSDs and probably Linux as well.
Just Google for unifdef.c.

-Larry Jones

Why can't I ever build character in a Miami condo or a {*filter*} somewhere?
-- Calvin
--



Tue, 06 Sep 2005 04:47:04 GMT  
 defenestration

Quote:



>>As I explained above, I can manage without it in this case, but it would
>>be nice to be able to avoid having to do so in the future.

> I think you are suffering from a badly designed program. The way I have
> always been taught to deal with OS issues is to extract all OS dependant
> code into its own files(s). With a reasonable version control system you
> then can just have a Windows version and a Unix version.

> I know this does not solve your problem but perhaps thinking about the
> idea might let you see how investing some extra time up front could
> greatly ease future maintenance.

Search for unifdef
I needed something like you and it did the job for me.
If you can't find it I can mail it to you.
Regards
ulf
--



Tue, 06 Sep 2005 04:47:06 GMT  
 defenestration

Quote:

> I'm trying to read the source code for a C program that is intended
> to compile either under Microsoft Windows or under Unix. Therefore,
> it is full of preprocessor commands of the form #ifdef WINDOWS <a>
> #else <b> #endif and #ifndef WINDOWS <c> #else <d> #endif. I find
> these very distracting, as it is already hard enough to read source
> code even under the best conditions.

This is a sign of two problems, actually:

1) Badly written source code.  There's hardly any valid excuse for
having #ifdef PLATFORM stuff to be scattered all ascross the sources.

2) Insufficient tools.  As another answer already pointed out,
powerful editors have ways to hide such ugly details from your view.

Quote:
> I would be surprised if there is an option for cpp which will simply
> modify source code in this way but if it is not hard to scavenge the
> source code for cpp to do this, it would be nice to know how to do it.

Sending the files through the preprocessor will remove those #ifdef, but
also make them quite unreadable in lots of other ways.  You may as
well forget about that option.

What you really need is a tool called "unifdef".  Google hints that
its origin is in BSD Unix, but I'm quite certain I have seen versions
of it for Linux, too.  The tool is so simple it should be extremely
easy to port it to other platforms.
--

Even if all the snow were burnt, ashes would remain.
--



Tue, 06 Sep 2005 04:47:09 GMT  
 defenestration

Quote:
> On 19 Mar 2003 17:17:49 GMT, Francis Glassborow



> >>As I explained above, I can manage without it in this case, but it would
> >>be nice to be able to avoid having to do so in the future.

> >I think you are suffering from a badly designed program. The way I have
> >always been taught to deal with OS issues is to extract all OS dependant
> >code into its own files(s). With a reasonable version control system you
> >then can just have a Windows version and a Unix version.

> This really doesn't work very well for header files, where this
> technique is most often seen. Even with a good version control system,
> I wouldn't want multiple files with the same name and differing
> contents.

Hmmmm....   I agree with Francis on this one.   A technique that I've
seen (and used) for multi-platform work involves;

1)    Define an interface (eg a set of functions and structures) that
         provides a set of functions in a consistent (i.e. not compiler
         specific) way.   Put the appropriate declarations and function
         prototypes into a header file.

2)   For each interface
      a)  Have a single source file that implements behaviour known
            to be common between operating systems.
      b)  Have a single source file per operating system that implements
             required functions whose implementation is known to
             depend on operating system.

3)    Set up a set of build scripts that compiles and links the appropriate
          set of files.

This approach basically avoids having system dependent header files.

One variation is to have a single source file that works for all supported
operating systems, and is structured like

#if defined (WIN32)
#include "win32.imp"              /* win32 specific implementations */
#elif defined (__GNUG__)
#include "gnu.imp"                 /*  gnu compiler specific implementations
*/
#endif

This variation offers the advantage of not needing to mess around with
build scripts as much.

Quote:

> For an obvious example, think about how many combinations of source
> and header files would be required to support the many POSIX
> compile-time options.

Fair call that this sort of approach results in more individual files to be
maintained.   But that is a trade-off with multi-platform code:  either have
a significant number of files that have to be individually maintained, or
have
one that is more difficult to maintain.   With a good source control system,
the difficulties with having multiple files are pretty light, but there is
no
sure way to make a single hard-to-maintain file more easily maintainable.

However, if the system is designed right, the operating system and compiler
dependencies will rarely be found in header files.  Using the above
approach,
the only exceptions to that statement have been the occasional #pragma
and the odd work-around for compiler bugs.
--



Fri, 09 Sep 2005 04:38:41 GMT  
 defenestration

Quote:

> I'm trying to read the source code for a C program that is intended
> to compile either under Microsoft Windows or under Unix. Therefore,
> it is full of preprocessor commands of the form #ifdef WINDOWS <a>
> #else <b> #endif and #ifndef WINDOWS <c> #else <d> #endif.

The abundance of those preprocessor statements does not follow
logically from the portability requirement. Without seeing the code
I'd say that most likely someone wrote spaghetti without any
good reason, and used the UNIX/Windows argument as an excuse.

The right way to approach your problem would be finding the programmer
who wrote the code, giving him a good kick, and making him clean it
up. Assuming he is no longer available though...

Quote:
> I would be surprised if there is an option for cpp which will simply
> modify source code in this way but if it is not hard to scavenge the
> source code for cpp to do this, it would be nice to know how to do it.
> Does anyone know exactly what to do?

The problem of utilizing cpp here is that you only want to get rid of
the WINDOWS branch, but you do not want cpp to do any of the rest of
its normal tasks. Rather than scavenging code from cpp (which is
hardly a trivial program, as you undoubtedly realize), the proper way
to do it would be to write an awk or perl or python script that would
do just what you want. It should be easy enough, and folks at
comp.lang.awk or some perl or python group may have one lying around
or write one in under 30 minutes. Asking there usually leads to better
results if you first try yourself though.

Note that writing such a script is not trivial. For instance, I can
write this UNTESTED script

#!/bin/awk -f
/^[ \t]*\#ifdef[ \t]+WINDOWS/ { windows_branch = 1; next }
/^[ \t]*\#ifndef[ \t]+WINDOWS/ { windows_branch = 0; next }
/^[ \t]*\#else/ { windows_branch = !windows_branch; next }
/^[ \t]*\#endif/ { windows_branch = 0; next }
!windows_branch { print }

in much less than 30 minutes, but this won't work on the variety of
possible cpp directives involving WINDOWS or on nested cpp
conditionals. If you only have the primitive cases you mentioned,
without nesting, this just might work. No guarantees, mind you.

Save it into an executable file (say, rmwin), do

$ chmod 755 rmwin
$ ./rmwin foo.c | less

see if it does what you expect. Including nested conditionals is left
as an exercise... Including other forms of conditionals is left as a
harder exercise... ;-)

--

--



Fri, 09 Sep 2005 04:38:51 GMT  
 
 [ 11 post ] 

 Relevant Pages 
 

 
Powered by phpBB® Forum Software