How to select and read #define lines from a code file

Hi,

I would like to read a .m file
and select the lines which begins with '#define PL-KEY', like

{quote}
#define PL-KEYTAG TAG_values
#define PL-KEYGROUP GROUP_value
#define PL-KEYINFO "INFO_ValueTxtMax120Char" // could be max 120 char
..... more PL-KEY keys
{quote}

and put the rest of that line until a '//' or '/*' , like

{quote}
TAG TAG_values
GROUP GROUP_value
INFO "INFO_ValueTxtMax120Char"
{quote}

into something like a list where my code above will loop through.

I thought using something like


cat "path/to/code.h" | while read line
do
#... what do I have to with "$line" ...
if [[ "$line" == #define PL-KEY* ]] ; then
# yes then... then what????
done


any suggestions?? I noticed today, I am still no shell expert 😟

Thanks again

Posted on Feb 8, 2010 5:53 AM

Reply
24 replies

Feb 8, 2010 7:31 AM in response to Obj-D

I cam up with this,


#!/usr/bin/env bash

declare -x PlistBuddy=/usr/libexec/PlistBuddy
plistFile="/Volumes/Repository/_Development/Plugin-Info.plist"
sourceFile="/Volumes/Repository/_Development/PluginMainClass.h"
findLine=*#define kPL_KEY*

#result=$(
cat ${sourceFile} | while read line
do
if [[ "$line" == ${findLine} ]] ; then
echo $line
echo $line | cut -f2 -d" " | cut -c 8-
echo $line | cut -f3 -d" "
key=$(echo $line | cut -f2 -d" " | cut -c 8-)
newValue=$(echo $line | cut -f3 -d" " )
echo "key : " ${key}
echo "newValue : " ${newValue}
myCurrentKey=$($PlistBuddy -c 'Print :'${key} ${plistFile} 2>&1)
echo "myCurrentKey : " ${myCurrentKey}
if [[ "$myCurrentKey" == *Does Not Exist ]] ; then
echo "make key"
$PlistBuddy -c 'Add :'${key}' string '${newValue} ${plistFile}
else
if [[ "${myCurrentKey}" == "${newValue}" ]]; then
echo "key values are equal!"
#...
else
echo "set key"
$PlistBuddy -c 'Set :'$key ${newValue} ${plistFile}
# $PlistBuddy -c 'Set :TAG '${newValue} ${plistFile}
fi
fi
fi
done #)
echo "result :" ${result}
exit



Still this
"$PlistBuddy -c 'Set :'$key ${newValue} ${plistFile}"
line gives me some problems. Why?

If someone knows a better way please tell me. This is my first trial with this.

Thanks.

Feb 8, 2010 7:42 AM in response to J D McIninch

{quote:title=J D McIninch wrote:}
PERL lives for this sort of thing.

perl -ne 'chomp; if (/^#define PL-KEY(.*)/) { $x=$1; $x=~s{/[/\ ].}{}; print "$x\n"; }' < path/to/code.h

{quote}

I saw this when I did supply my trial.
Thank you for your code, but I cant get it to work, at least I don't see the result anywhere.
I see no print in the terminal.

I did copy the code into SubEthaEdit perl mode, set the execution bit and run in terminal.
If I do a syntax check it gives errors.

syntax error at - line 1, near "-ne"
- had compilation errors.

Feb 8, 2010 9:06 AM in response to Obj-D

Thanks guys.

My requirements are a little wilder I guess

I would like to do the following
In xcode I will, during building, check the info.plist if there is an element called f.e TAG and do compare it with a #define kPL_TAG myTagTest line in .h file. If it is wrong or not there, it should be replaced/added. From the #define line I have to cut the #define kPL_ part to get the plist-Key name the left over till an existing comment char like // or /*

With the above code it works,.... almost.

However if I have spaces in one of those guy's

#define kPL_KEYTAG TAG_values
#define kPL_KEYGROUP GROUP_value
#define kPL_KEYINFO "INFO_Value Txt Max 120 Char width"

I have a problem with line

newValue=$(echo $line | cut -f3 -d" " )


it cut the string till the next space.

Also, if you look back to my code post, I have a problem with accepting a Key as var for PlistBuddy.
I would like to work arround this, and try to do something like


mySet=$(echo "$PlistBuddy -c 'Set :${key} ${newValue} ' ${plistFile}")
echo "mySet :"${mySet}

eval ${mySet}
# or
echo ${$mySet}


But I mis the clue here.

Feb 8, 2010 2:56 PM in response to Obj-D

I can't help much with PlistBuddy, as I just recently found out about it myself.

But for the code, here are some adjustments based on your comments.

I stuck with shell scripting because you seem to be more comfortable with shell scripting, vs awk or perl.

#!/usr/bin/env bash

while read lb_def rest
do
if [[ "$lb_def" = #define && "$rest" = PL_KEY* ]]; then
rest=${rest#PL_KEY}
echo "${rest%/[/]}"
fi
if [[ "$lb_def" = # && "$rest" = define PL_KEY* ]]; then
rest=${rest#define }
rest=${rest#PL_KEY}
echo "${rest%/[/]}"
fi
done </path/to/code.h

If PL_KEY has stuff in front if it, like one of your posts where it was kPL_KEY, then you could modify the uses of PL_KEY to include the 'k', or you could wildcard it. If a single character, then

if [[ "$lb_def" = #define && "$rest" = ?PL_KEY* ]]; then
...
rest=${rest#?PL_KEY}

If multiple characters could prefix PL_KEY, then you can use the multi-character wildcard

if [[ "$lb_def" = #define && "$rest" = PL_KEY ]]; then
...
rest=${rest#*PL_KEY}

If you are worried, that PL_KEY might exist in the comment, then you could strip the comment before doing the tests

#!/usr/bin/env bash

while read lb_def rest
do
rest=${rest%/[/]} # remove comments.
if [[ "$lb_def" = #define && "$rest" = PL_KEY ]]; then
rest=${rest#*PL_KEY}
echo "${rest}"
fi
if [[ "$lb_def" = # && "$rest" = define PL_KEY ]]; then
rest=${rest#define }
rest=${rest#*PL_KEY}
echo "${rest}"
fi
done </path/to/code.h

Is that better?

Message was edited by: BobHarris

Feb 8, 2010 4:25 PM in response to Obj-D

This might actually be more useful to you. I have added logic that deals with variable amounts of white space, and prefixes attached to PL_KEY.

I also separated the key from the value.

#!/usr/bin/env bash
shopt -s extglob # enable extended globs +(...), *(...), etc...
while read line
do
line="${line%([[:space:]])/[/*]}" # remove comments
if [[ "$line" = #([[:space:]])define*([[:space:]])*([[:alnum:]])PL_KEY ]]; then
line="${line##([[:space:]])define*([[:space:]])([[:alnum:]])PL_KEY}"
echo "$line"
key=${line%%+([[:space:]])*}
echo $key
value=${line##${key}+([[:space:]])}
echo "$value"
fi
done </path/to/code.h

Feb 11, 2010 8:01 PM in response to Obj-D

The

line="${line%([[:space:]])/[/*]}" # remove comments

should have removed any space before comments.

However, if there are no comments, but a trailing space or spaces after the value, that would not have been removed.

I would change your solution slightly, and put the following line following my above line, which should make sure there is no white space of any kind following the value.

line=${line%+([[:space:]])}

Giving:

#!/usr/bin/env bash

shopt -s extglob # enable extended globs +(...), *(...), etc...
while read line
do
line="${line%/[/]}" # remove comments
line="${line%+([[:space:]])}" # remove trailing spaces
if [[ "$line" = #([[:space:]])define*([[:space:]])*([[:alnum:]])PL_KEY ]]; then
line="${line##([[:space:]])define*([[:space:]])([[:alnum:]])PL_KEY}"
echo "$line"
key=${line%%+([[:space:]])*}
echo $key
value=${line##${key}+([[:space:]])}
echo "$value"
fi
done </path/to/code.h

Feb 12, 2010 8:13 AM in response to BobHarris

Thanks Bob,

Before you posted your solution I did change my code to

line="${line%+([[:space:]])/[/\ ]}"

However this works for when there are spaces between the last value character.
It doesn't work when I have f.e.

#define kPL_KEYORDER 14// dfd

But, as always, your code is better 🙂

Any way, now the question raised, what is the difference between yes or no comments at the end? A bug?

Feb 12, 2010 8:48 AM in response to Obj-D

Any way, now the question raised, what is the difference between yes or no comments at the end? A bug?

I'm a little confused by the question.

The code I provided, in theory, should first remove a // or /* comment, if and only if a comment is present, otherwise that statement does nothing.

The next line should look for a trailing spaces and if and only if there is one or more spaces following the line after any comments have been removed. If not trailing spaces, that statement does nothing.

I'm taking advantage of the POSIX shell variable substitution operators (man bash):

${var%patterm} # delete shortest end matching pattern
${var%%patterm} # delete longest end matching pattern
${var#patterm} # delete shortest begin matching pattern
${var##patterm} # delete longest begin matching pattern
${var/patterm/replace} # substitute 1st matching pattern
${var//patterm/replace} # substitute all matching patterns

where pattern can be any wildcard string, and can also include variables substituted in the pattern (such as ${key})

This thread has been closed by the system or the community team. You may vote for any posts you find helpful, or search the Community for additional answers.

How to select and read #define lines from a code file

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple Account.