0

Below is a typo for a C++ include guard. Both should read _MYFILE_H_.

#ifndef _MYFILE_H_
#define _MYFLIE_H_

How would you suggest searching a bunch of header files for a typo like this using GNU coreutils (e.g. grep, awk)?

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
Shaun Lebron
  • 2,501
  • 28
  • 29
  • Save time and #define _MYFLIE_H_ _MYFILE_H_ – QuentinUK Feb 21 '13 at 20:51
  • I just learned a simpled egrep search won't do: http://stackoverflow.com/q/3717772/ – Kijewski Feb 21 '13 at 20:56
  • 2
    Neither should read `_MYFILE_H_`. `` Names that begin with an underscore followed by a capital letter and names that contain two consecutive underscores are reserved to the implementation. Don't use them. – Pete Becker Feb 21 '13 at 21:01
  • I know some awk,grep, due to the lack of my C++ knowledge. I didn't understand what do you want to do...:( – Kent Feb 21 '13 at 21:06
  • @PeteBecker I'm not sure that those rules appliy to macros, as they specifically mention that these are restrictions on *names*. Essentially, the difference between a name and an identifier is that a name is an identifier which denotes some item. This is why the identifier used to identify a user-defined literal does not count towards this rule. A macro should be the same, as it does not actually exist in the language as an item, it is just a string which gets replaced dumbly in the preprocessor. – Agentlien Feb 21 '13 at 21:07
  • @Agentlien I think it the restriction applies for macros, too. Keep normative constructs like _Bool and _Complex in mind. – Kijewski Feb 21 '13 at 21:08
  • 1
    @Agentlien - see 17.6.4.3 [reserved.names] /1: "The C++ standard library reserves the following kinds of names: **macros** ...". Whew, that's a relief! – Pete Becker Feb 21 '13 at 21:10
  • @Kay Still, those are keywords ore typedefs. Macros are essentially directives to perform search-and-replace and are performed already in the preprocessor, before names really gain a maeaning. – Agentlien Feb 21 '13 at 21:10
  • @PeteBecker Thank you for the reference. That is something I've been wondering about, since I've seen a lot of macros with these type of names. – Agentlien Feb 21 '13 at 21:12

3 Answers3

2

You could use awk:

{
  if ($1 == "#ifndef") { was_ifdef = 1; def = $2 }
  else if ($1 == "#define" && was_ifdef) 
    { 
      if ($2 != def)   printf("Mismatch in %s: expected %s found %s\n", FILENAME, def, $2);
    }
  else was_ifdef = 0;
}

There may be more clever ways to do this, but this is (to me) quite clear and easy.

Note: This will show "false positives" if the file contains something like

#ifndef FOO_DEFINED
typedef int foo;
#define FOO_DEFINED 
#endif
Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
1

grep by itself will not work here because regular expressions are not powerful enough to match the set of strings you're describing.

Specifically, the language of all strings of the form

#ifndef X
#define Y

Where XY is not a regular language. You can prove this by using the Myhill-Nerode theorem (since any two strings of the form #ifndef X for different choices of X fall into different equivalence classes of the distinguishability relation). As a result, there is no way to write a regular expression that can match strings of this form, and since grep uses pure mathematical regular expressions, there is no way to use grep to solve this problem.

Sorry for the negative result, but I hope this helps!

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
1

Multiple sed commands could do the trick.

for FILENAME in ./*.h; do
     [[ $(sed -n '1p' "$FILENAME" | sed -e 's/#ifndef //') != $(sed -n '2p' "$FILENAME" | sed -e 's/#define //') ]] && echo "$FILENAME"
end

Problem with that implementation is, that there may be no copyright header above the guard.

And I'm quite sure that this could be written more concise.

Kijewski
  • 25,517
  • 12
  • 101
  • 143