LinuxQuestions.org
Review your favorite Linux distribution.
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Distributions > Slackware
User Name
Password
Slackware This Forum is for the discussion of Slackware Linux.

Notices

Reply
 
Search this Thread
Old 09-10-2011, 02:16 AM   #1
mudflap
Member
 
Registered: Jul 2008
Location: Coffin Point
Distribution: Slackware - ttylinux - CPO
Posts: 53

Rep: Reputation: 15
Determine the PATCHLEVEL for Bash


I have never been happy with the acrobatics to determine the patchlevel in many of the Slackware build scripts (even when it worked), and hope this might be an acceptable improvement for this and other packages.

Code:
grep "#define PATCHLEVEL " patchlevel.h | sed s%"#define PATCHLEVEL "%% > ${TMP}/patchlevel.tmp
PATCHLEVEL=`cat ${TMP}/patchlevel.tmp`

Last edited by mudflap; 09-10-2011 at 02:24 AM.
 
Old 09-10-2011, 06:01 AM   #2
GazL
Senior Member
 
Registered: May 2008
Posts: 3,312

Rep: Reputation: Disabled
While pulling the PATCHLEVEL out of the header rather than relying on the last patch-file name in a directory does make a lot of sense, the way you suggest is vulnerable to changes in the header file.
For example, what if the patchlevel.h format changed and for whatever reason they started using #ifdefs or doing something like:
Code:
/*  Old Patchlevels:
#define PATCHLEVEL 0
#define PATCHLEVEL 1
#define PATCHLEVEL 2
*/

#define PATCHLEVEL 3

If you're going to try and parse the header, then it might be worth doing it properly using the pre-processor.:
Code:
PATCHLEVEL=" $(echo "PATCHLEVEL" | cpp -P -include "/tmp/wherever/patchlevel.h" )"
But even this approach is susceptible to picking up junk from a badly abused header, so not completely reliable either.

IMO, this is all getting a little bit over-involved though and as the patch files have to be managed manually anyway, I think I'd be inclined to just stick with the way Pat has done it with a simple "ls | tail | cut" pipe-line approach.


Interesting thought exercise though. So thanks for sharing.

Last edited by GazL; 09-10-2011 at 06:10 AM.
 
Old 09-10-2011, 10:22 AM   #3
mudflap
Member
 
Registered: Jul 2008
Location: Coffin Point
Distribution: Slackware - ttylinux - CPO
Posts: 53

Original Poster
Rep: Reputation: 15
It had not occurred to me that the header format might change, but that I suppose is the nature of developers.

I spend entirely too much time and attention to ensure a new version is still behaving with the old build script. The task of getting the patchlevel by any means is really a trivial matter, but I thought it better to use what the program was telling itself.

Mpfr seems to issue their patches in a single cumulative lump: "allpatches". In this case the patchlevel must be extracted from the file: "VERSION". Althogh the patchlevel seems to be "p4" it may simply be the number of patches successfully applied. (a project for later)

All in all it is a matter of preference. I just thought I would put it out there.
 
Old 09-10-2011, 04:21 PM   #4
Ian John Locke II
Member
 
Registered: Mar 2008
Location: /dev/null
Distribution: Slackware, Android, Slackware64
Posts: 130

Rep: Reputation: 17
A better grep pattern might be "^#.* PATCHLEVEL \d+$" so you're certain that the #(ifdef|ifndef|define) is at the start of the line, and that you have digits at the end of the line.

Also if you're doing this in a bash script, you can quite simply do
Code:
PATCHLEVEL=$(grep "^#.* PATCHLEVEL \d+$" | tail -1 | sed -r 's/#.* PATCHLEVEL //')
So if the line is
Code:
/*  Old Patchlevels:
#define PATCHLEVEL 0
#define PATCHLEVEL 1
#define PATCHLEVEL 2
*/

#define PATCHLEVEL 3
or even
Code:
#define PATCHLEVEL
#ifndef PATCHLEVEL 0
#ifdef PATCHLEVEL 1
#define PATCHLEVEL 2
#ifdef PATCHLEVEL 3
it will only grab the last one (thanks to tail -1) and it will ignore the first line. And the modified regexp for sed will not screw the pooch if per chance #define doesn't start off the line.

The above command also removes the need for a ${TMP}/file.tmp that needs to be written to and read from immediately after.

I hope this helps.
 
Old 09-11-2011, 05:44 AM   #5
GazL
Senior Member
 
Registered: May 2008
Posts: 3,312

Rep: Reputation: Disabled
In the example I gave above, there is no guarantee that the last value would be the correct one to use. The commented out #defines could have just as easily come after the active definition. However, the example I gave was contrived solely to illustrate that trying to reliably pull the value out of a C headerfile is fraught with difficulties due to the nature of the file involved and to suggest that the way Pat currently does this: by acting on the filenames of the patch files, is possibly more reliable (YMMV). I doubt we'd actually ever see a patchlevel.h as contorted as the example I gave as it really wouldn't make much sense to do so.


BTW, as another alternative way of coding this, you can parse the file without needing to make any calls to external commands entirely from within the shell script, with something like.

Code:
while read statement symbol value junk
do
   if [ "$statement" = '#define' -a "$symbol" = 'PATCHLEVEL' ]; then
      PATCHLEVEL="$value"
  fi
done < /tmp/patchlevel.h
Like Ian's code, this will rely on the assumption that the #define for PATCHLEVEL is the last or only one contained within the header file..


I still believe that Pat's current approach is the safest, but as mudflap rightly pointed out, it's very much a matter of one's personal viewpoint and preference.

Last edited by GazL; 09-11-2011 at 05:47 AM.
 
Old 09-11-2011, 07:28 AM   #6
mRgOBLIN
Slackware Contributor
 
Registered: Jun 2002
Location: New Zealand
Distribution: Slackware
Posts: 999

Rep: Reputation: 226Reputation: 226Reputation: 226
Something like this?

Code:
awk 'BEGIN {lvl = 0}
/^#.*[[:blank:]]+PATCHLEVEL[[:blank:]]+[[:digit:]]+/ { if ($NF > lvl) {lvl = $NF} }
END { print lvl }' /tmp/patchlevel.h
 
Old 09-11-2011, 09:08 AM   #7
GazL
Senior Member
 
Registered: May 2008
Posts: 3,312

Rep: Reputation: Disabled
That would find the highest patchlevel, but still wouldn't cope if it were in a comment block.
Code:
gazl@slack:/tmp$ cat patchlevel.h 

#define wibble froop     /*

#define PATCHLEVEL 13

*/


// Some other random stuff 

char * var1;

#define PATCHLEVEL 12

/*

#define PATCHLEVEL 2

*/


gazl@slack:/tmp$ awk 'BEGIN {lvl = 0}
/^#.*[[:blank:]]+PATCHLEVEL[[:blank:]]+[[:digit:]]+/ { if ($NF > lvl) {lvl = $NF} }
END { print lvl }' /tmp/patchlevel.h
13
gazl@slack:/tmp$
The best I can come up with for a robust solution is adding a unique placeholder that won't exist in the header file to my previous attempt with cpp to help weed out the crud, like this:
Code:
gazl@slack:/tmp$ PATCHLEVEL="$(echo "placeholder PATCHLEVEL" | cpp -P -include "/tmp/patchlevel.h" | grep '^placeholder ' | cut -f 2 -d ' ' )"
gazl@slack:/tmp$ echo $PATCHLEVEL
12
Obviously "placeholder" isn't a good placeholder string and you want something a little more unique than that, but it's ok for the example.


I suppose you could also try and remove comment blocks using some additional awk script, but as they don't necessarily always start/end on a line beginning, I guess it's not going to be that straight forward. But I don't have much skill in awk so perhaps it's not as bad as I think.

Last edited by GazL; 09-11-2011 at 09:20 AM.
 
Old 09-11-2011, 11:37 AM   #8
Ian John Locke II
Member
 
Registered: Mar 2008
Location: /dev/null
Distribution: Slackware, Android, Slackware64
Posts: 130

Rep: Reputation: 17
Hijacking this thread, does it matter to no one that Kerningham hates awk? After all he co-created it :P
 
Old 09-11-2011, 11:39 AM   #9
Nylex
LQ Addict
 
Registered: Jul 2003
Location: London, UK
Distribution: Slackware
Posts: 7,464

Rep: Reputation: Disabled
Quote:
Originally Posted by Ian John Locke II View Post
Hijacking this thread, does it matter to no one that Kerningham hates awk? After all he co-created it :P
Is the misspelling intentional? If not, it's "Kernighan".
 
Old 09-11-2011, 07:18 PM   #10
mRgOBLIN
Slackware Contributor
 
Registered: Jun 2002
Location: New Zealand
Distribution: Slackware
Posts: 999

Rep: Reputation: 226Reputation: 226Reputation: 226
Quote:
Originally Posted by GazL View Post
That would find the highest patchlevel, but still wouldn't cope if it were in a comment block.
Yeah I was working on the logic that commented out sections were lower patchlevels but that is a valid point.

Quote:
Originally Posted by GazL View Post
I suppose you could also try and remove comment blocks using some additional awk script, but as they don't necessarily always start/end on a line beginning, I guess it's not going to be that straight forward. But I don't have much skill in awk so perhaps it's not as bad as I think.
Yeah it's certainly harder than it looks on first impressions... you are kind of relying on people to use a "sane" comment structure.
I borrowed a section of code from my "Effective Awk Programming" Book.

Code:
#!/usr/bin/awk -f

BEGIN {lvl = 0}


{
     if ((t = index($0, "/*")) != 0) {
          # value will be "" if t is 1
          tmp = substr($0, 1, t - 1)
          u = index(substr($0, t + 2), "*/")
          while (u == 0) {
               if (getline <= 0) {
                    m = "unexpected EOF or error"
                    m = (m ": " ERRNO)
                    print m > "/dev/stderr"
                    exit
               }
               t = -1
               u = index($0, "*/")
          }
          # substr expression will be "" if */
          # occurred at end of line
          $0 = tmp substr($0, t + u + 3)
  }
  if ($0 ~ /^#.*[[:blank:]]+PATCHLEVEL[[:blank:]]+[[:digit:]]+/)
       {
               if ($NF > lvl)
               {
                       lvl = $NF
               }
       }

}

END { print lvl }
Seems to work for me.
Code:
./patchlvl.awk patch.h
12
 
1 members found this post helpful.
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
BASH: Determine what package manager to use worm5252 Programming 4 06-30-2010 07:09 AM
Can Bash determine if /mnt/place is mounted on? Cathinfo Programming 9 07-31-2007 07:17 PM
BASH - determine when file is no longer written to marwal Programming 10 03-27-2007 06:51 PM
Bash scripting and trying to determine whether a directory exists? obelxi Programming 9 04-18-2005 11:22 PM
Redhat Patchlevel mailnickykav Red Hat 2 03-23-2005 06:06 AM


All times are GMT -5. The time now is 03:35 PM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration