stdcxx-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From abl...@apache.org
Subject svn commit: r643120 - /stdcxx/trunk/util/output.cpp
Date Mon, 31 Mar 2008 20:04:02 GMT
Author: ablack
Date: Mon Mar 31 13:03:58 2008
New Revision: 643120

URL: http://svn.apache.org/viewvc?rev=643120&view=rev
Log:
2008-03-31  Andrew Black  <ablack@roguewave.com>

	STDCXX-426
	* util/output.cpp (struct readback): Add convenience data structure
	  for backwards file reading.
	  (rbinit): Add method to initialize structure.
	  (rbbof): Add method to check if structure points to the beginning
	  of a file.
	  (rbsync): Add method to synchronize the file handle the structure
	  is built on to the structure.
	  (rbgetc): Add method to retrieve a character from the file and
	  move the structure one position closer to the start
	  (rbscanf): Add methods to search for a string using the
	  structure, possibly capturing an unsigned integer in the process.
	  (check_test, check_compat_test): Alter to use above methods.


Modified:
    stdcxx/trunk/util/output.cpp

Modified: stdcxx/trunk/util/output.cpp
URL: http://svn.apache.org/viewvc/stdcxx/trunk/util/output.cpp?rev=643120&r1=643119&r2=643120&view=diff
==============================================================================
--- stdcxx/trunk/util/output.cpp (original)
+++ stdcxx/trunk/util/output.cpp Mon Mar 31 13:03:58 2008
@@ -44,6 +44,239 @@
 #  define ENOENT 2
 #endif   /* ENOENT */
 
+/**
+   Arbitrary constant controling static read buffer size.
+
+   @see check_example ()
+   @see rbread ()
+*/
+#define DELTA_BUF_LEN 64
+
+/** 
+    This structure is used to encapsulate the data involved in a backwards
+    file read.
+*/
+struct readback {
+    FILE* src;
+    char buf[DELTA_BUF_LEN];
+    long bpos;
+};
+
+/**
+   Initializes the provided readback structure, with the provided file
+   handle.
+
+   @param rb pointer to readback structure to initialize
+   @param src file handle to initialize rb with.
+   @returns true if successfully initialized, false otherwise.
+*/
+static bool
+rbinit (struct readback* rb, FILE* const src)
+{
+    const size_t buflen = sizeof rb->buf;
+    long fpos;
+    assert (0 != rb);
+    assert (0 != src);
+
+    rb->src = src;
+    if (-1 == fseek (rb->src, 0, SEEK_END))
+        return false;
+    fpos = ftell (rb->src);
+    if (-1 == fpos)
+        return false;
+
+    if (fpos <= buflen)
+        rb->bpos = fpos;
+    else
+        rb->bpos = buflen;
+
+    if (-1 == fseek (rb->src, fpos - rb->bpos, SEEK_SET))
+        return false;
+
+    return rb->bpos == fread (rb->buf, 1, rb->bpos, rb->src);
+}
+
+/** 
+   This method is semi-analagous to feof.
+   
+   @param rb pointer to readback structure to check begin-of-file state for
+   @returns true if structure points to the begining of the file, false 
+   otherwise
+*/
+static bool
+rbbof (const struct readback* const rb)
+{
+    assert (0 != rb);
+    assert (0 != rb->src);
+    return (0 == rb->bpos) && (0 == ftell (rb->src));
+}
+
+/**
+   Syncronizes the file handle underlying a readback structure to the
+   pointer in the structure.  This method is called if you wish to start
+   reading forward from the current point in the readback structure.
+
+   @param rb pointer to the readback structure to syncronize.
+   @return true if the structure was successfully syncronized, false 
+   otherwise.
+*/
+static bool
+rbsync (struct readback* const rb)
+{
+    assert (0 != rb);
+    assert (0 != rb->src);
+    const size_t buflen = sizeof rb->buf;
+    long fpos = ftell (rb->src) - buflen;
+    if (0 > fpos)
+        fpos=0;
+    fpos += rb->bpos;
+    rb->bpos=0;
+
+    return -1 != fseek (rb->src, fpos, SEEK_SET);
+}
+
+/**
+   Updates the provided readback structure, returning the last unread 
+   character in the file.  This method is semi-analagous to fgetc.
+   
+   @param rb pointer to readback structure to read from.
+   @return EOF if beginning of file or I/O error, read character
+   otherwise.
+*/
+static char
+rbgetc (struct readback* rb)
+{
+    const size_t buflen = sizeof rb->buf;
+    assert (0 != rb);
+    assert (0 != rb->src);
+    if (!rb->bpos) {
+        const size_t bufdelta = buflen << 1;
+        long fpos = ftell (rb->src);
+        long seek;
+
+        if (-1 == fpos)
+            return EOF;
+
+        if (bufdelta <= fpos) {
+            seek = fpos - bufdelta;
+            rb->bpos = buflen;
+        }
+        else if (buflen < fpos) {
+            seek = 0;
+            rb->bpos = fpos - buflen;
+        }
+        else {
+            fseek (rb->src, 0, SEEK_SET);
+            return EOF;
+        }
+
+        if (-1 == fseek (rb->src, seek, SEEK_SET))
+            return EOF;
+
+        if (rb->bpos != fread (rb->buf, 1, rb->bpos, rb->src))
+            return EOF;
+    }
+    assert (0 < rb->bpos && rb->bpos <= buflen);
+
+    return rb->buf [--rb->bpos];
+}
+
+/**
+   This method is semi-analagous to fscanf, with some key differences.
+   First, it opperates on a readback structure.  Second, it scans until
+   either the search pattern is matched, or until the begining of the file
+   is reached.  Third, it reads backwards from the end of the file.
+
+   Limitations: string to match can't end in a repeated set of characters
+   (ie: 'singing' has the repeated characters 'ing')
+
+   @param rb pointer to readback structure to operate on
+   @param match string to search for
+   @return true if match is found, false if begining of file is reached
+*/
+static bool
+rbscanf (struct readback* rb, const char* const match)
+{
+    char tok;
+    size_t matched;
+    size_t count;
+    assert (0 != rb);
+    assert (0 != match);
+
+    matched = count = strlen (match) - 1;
+    
+    for(tok = rbgetc(rb); matched && !rbbof (rb); tok = rbgetc (rb)) {
+        if (tok == match [matched])
+            --matched;
+        else
+            matched = count;
+    }
+    return !matched;
+}
+
+/**
+   This method is semi-analagous to fscanf, reading backwards on a readback
+   structure, starting from the end of the file.
+
+   This method searches backwards for the first (last) number and captures
+   it.  It then checks if the match string exists directly after (before)
+   the captured value.  If this is the case, a match is considered to have
+   been found, and the captured value is copied to val.  Otherwise, the 
+   search process is restarted.  If the search hits the beginning of the 
+   file, matching is considered to have failed, and val is unaltered.
+
+   Limitations: string to match can't end in a repeated set of characters
+   (ie: 'singing' has the repeated characters 'ing'.) or a repeated set
+   of characters, bordering on either side of one or more numbers (ie: 
+   'xyzzy9zzy' has the repeated characters 'zzy')
+
+   @param rb pointer to readback structure to operate on.
+   @param match string to search for.
+   @param val reference to variable to store captured value in.
+   @return true if match is found, false if begining of file is reached.
+*/
+static bool
+rbscanf (struct readback* rb, const char* const match, unsigned& val)
+{
+    size_t count;
+    unsigned tval =0;
+    unsigned radix;
+    assert (0 != rb);
+    assert (0 != match);
+
+    count = strlen (match) - 1;
+    
+    while (!rbbof(rb)) {
+        char tok;
+        size_t matched = count;
+
+        tval=0;
+        radix=1;
+
+        /* Search for a numeric digit */
+        for (tok = rbgetc (rb); 
+            (tok < '0' || tok > '9') && !rbbof (rb); 
+             tok = rbgetc (rb)) /* Do nothing */;
+
+        /* Read in the number. */
+        for ( ; tok >= '0' && tok <= '9' && !rbbof (rb); 
+            tok = rbgetc (rb)) {
+            tval += (tok-'0') * radix;
+            radix *= 10;
+        }
+
+        /* Make certain the content prior to the number in the file 
+           matches the search pattern. */
+        for( ; matched && tok == match [matched] && !rbbof (rb); 
+            tok = rbgetc (rb), --matched) /* Do nothing */;
+
+        if (tok == match [matched]) {
+            val = tval;
+            return true;
+        }
+    }
+    return false;
+}
 
 /**
    Parses contents of the open file handle data for test target_name.
@@ -58,6 +291,7 @@
 static void
 check_test (FILE* data, struct target_status* status)
 {
+    struct readback buf;
     unsigned r_lvl    = 0;   /* diagnostic severity level */
     unsigned r_active = 0;   /* number of active diagnostics */
     unsigned r_total  = 0;   /* total number of diagnostics */
@@ -73,15 +307,28 @@
     assert (0 != data);
     assert (0 != status);
 
-    tok = fgetc (data);
+    if (!rbinit (&buf, data)) {
+        status->status = ST_SYSTEM_ERROR;
+        return;
+    }
 
-    if (feof (data)) {
+    if (rbbof (&buf)) {
         /* target produced no output (regression test?) */
         status->status = ST_NO_OUTPUT;
         return;
     }
 
-    for ( ; fsm < 6 && !feof (data); tok = fgetc (data)) {
+    if (!rbscanf (&buf, "| INACTIVE |\n# +")) {
+        status->status = ST_FORMAT;
+        return;
+    }
+
+    rbsync(&buf);
+
+    /* While it'd probably be (slightly) faster to seek to a fixed position 
+       after the file pointer has been synced, this should be more reliable 
+    */
+    for (tok = fgetc (data); fsm < 6 && !feof (data); tok = fgetc (data)) {
         switch (tok) {
         case '\n':
             fsm = 1;
@@ -150,58 +397,25 @@
 static void
 check_compat_test (FILE* data, struct target_status* status)
 {
-    int read = 0;
-    unsigned fsm = 0;
-    char tok;
+    struct readback buf;
 
     assert (0 != data);
     assert (0 != status);
 
-    tok = fgetc (data);
-
-    if (feof (data)) {
+    if (!rbinit (&buf, data)) {
+        status->status = ST_SYSTEM_ERROR;
+    } 
+    else if (rbbof (&buf)) {
         /* target produced no output (regression test?) */
         status->status = ST_NO_OUTPUT;
-        return;
-    }
-
-    for ( ; !feof (data); tok = fgetc (data)) {
-        switch (tok) {
-        case '\n':
-            fsm = 1;
-            break;
-        case '#':
-            if (1 == fsm || 2 == fsm)
-                ++fsm;
-            else
-                fsm = 0;
-            break;
-        case ' ':
-            if (3 == fsm) 
-                ++fsm;
-            else
-                fsm = 0;
-            break;
-        case 'W':
-            if (4 == fsm && !feof (data)) /* leading "## W" eaten */
-                read = fscanf (data, "arnings = %u\n## Assertions = %u\n"
-                       "## FailedAssertions = %u",
-                       &status->t_warn, &status->assert, &status->failed);
-        default:
-            fsm = 0;
-        }
     }
-    if (3 != read) {
+    else if (   !rbscanf (&buf, "## FailedAssertions = ", status->failed)
+             || !rbscanf (&buf, "## Assertions = ", status->assert)
+	     || !rbscanf (&buf, "## Warnings = ", status->t_warn)) {
         status->status = ST_FORMAT;
     }
 }
 
-/**
-   Arbitrary constant controling static read buffer size.
-
-   @see check_example ()
-*/
-#define DELTA_BUF_LEN 64
 
 /**
    Parses output file out_name for the example target_name.



Mime
View raw message