os/ossrv/ofdbus/dbus/tsrc/testapps/dbus_test_cases/decode-gcov.c
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/ossrv/ofdbus/dbus/tsrc/testapps/dbus_test_cases/decode-gcov.c	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,2666 @@
     1.4 +
     1.5 + /* -*- mode: C; c-file-style: "gnu" -*- */
     1.6 +/* decode-gcov.c gcov decoder program
     1.7 + *
     1.8 + * Portion Copyright © 2008 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
     1.9 + * Copyright (C) 2003  Red Hat Inc.
    1.10 + *
    1.11 + * Partially derived from gcov,
    1.12 + * Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
    1.13 + * 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
    1.14 + *
    1.15 + * This file is NOT licensed under the Academic Free License
    1.16 + * as it is largely derived from gcov.c and gcov-io.h in the
    1.17 + * gcc source code.
    1.18 + * 
    1.19 + * This program is free software; you can redistribute it and/or modify
    1.20 + * it under the terms of the GNU General Public License as published by
    1.21 + * the Free Software Foundation; either version 2 of the License, or
    1.22 + * (at your option) any later version.
    1.23 + *
    1.24 + * This program is distributed in the hope that it will be useful,
    1.25 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.26 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.27 + * GNU General Public License for more details.
    1.28 + * 
    1.29 + * You should have received a copy of the GNU General Public License
    1.30 + * along with this program; if not, write to the Free Software
    1.31 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    1.32 + *
    1.33 + */
    1.34 +
    1.35 +#define DBUS_COMPILATION /* cheat */
    1.36 +#ifndef __SYMBIAN32__
    1.37 +#include <dbus/dbus-list.h>
    1.38 +#include <dbus/dbus-string.h>
    1.39 +#include <dbus/dbus-sysdeps.h>
    1.40 +#include <dbus/dbus-hash.h>
    1.41 +#else
    1.42 +#include "dbus-list.h"
    1.43 +#include "dbus-string.h"
    1.44 +#include "dbus-sysdeps.h"
    1.45 +#include "dbus-hash.h"
    1.46 +#endif
    1.47 +
    1.48 +
    1.49 +#undef DBUS_COMPILATION
    1.50 +#include <stdio.h>
    1.51 +#include <stdlib.h>
    1.52 +#include <string.h>
    1.53 +
    1.54 +#ifdef SYMBIAN
    1.55 +#define DBUS_HAVE_INT64 1
    1.56 +#endif
    1.57 +
    1.58 +#ifndef DBUS_HAVE_INT64
    1.59 +#error "gcov support can't be built without 64-bit integer support"
    1.60 +#endif
    1.61 +
    1.62 +static void
    1.63 +die (const char *message)
    1.64 +{
    1.65 +  fprintf (stderr, "%s", message);
    1.66 +  exit (1);
    1.67 +}
    1.68 +
    1.69 +/* This bizarro function is from gcov-io.h in gcc source tree */
    1.70 +static int
    1.71 +fetch_long (long        *dest,
    1.72 +            const char  *source,
    1.73 +            size_t       bytes)
    1.74 +{
    1.75 +  long value = 0;
    1.76 +  int i;
    1.77 +                                                                                
    1.78 +  for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--)
    1.79 +    if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 ))
    1.80 +      return 1;
    1.81 +                                                                                
    1.82 +  for (; i >= 0; i--)
    1.83 +    value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255));
    1.84 +                                                                                
    1.85 +  if ((source[bytes - 1] & 128) && (value > 0))
    1.86 +    value = - value;
    1.87 +                                                                                
    1.88 +  *dest = value;
    1.89 +  return 0;
    1.90 +}
    1.91 +
    1.92 +static int
    1.93 +fetch_long64 (dbus_int64_t *dest,
    1.94 +              const char   *source,
    1.95 +              size_t        bytes)
    1.96 +{
    1.97 +  dbus_int64_t value = 0;
    1.98 +  int i;
    1.99 +                                                                                
   1.100 +  for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--)
   1.101 +    if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 ))
   1.102 +      return 1;
   1.103 +                                                                                
   1.104 +  for (; i >= 0; i--)
   1.105 +    value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255));
   1.106 +                                                                                
   1.107 +  if ((source[bytes - 1] & 128) && (value > 0))
   1.108 +    value = - value;
   1.109 +                                                                                
   1.110 +  *dest = value;
   1.111 +  return 0;
   1.112 +}
   1.113 +
   1.114 +#define BB_FILENAME 	(-1)
   1.115 +#define BB_FUNCTION 	(-2)
   1.116 +#define BB_ENDOFLIST	0
   1.117 +
   1.118 +static dbus_bool_t
   1.119 +string_get_int (const DBusString *str,
   1.120 +                int               start,
   1.121 +                long             *val)
   1.122 +{
   1.123 +  const char *p;
   1.124 +  
   1.125 +  if ((_dbus_string_get_length (str) - start) < 4)
   1.126 +    return FALSE;
   1.127 +
   1.128 +  p = _dbus_string_get_const_data (str);
   1.129 +
   1.130 +  p += start;
   1.131 +
   1.132 +  fetch_long (val, p, 4);
   1.133 +  
   1.134 +  return TRUE;
   1.135 +}
   1.136 +
   1.137 +static dbus_bool_t
   1.138 +string_get_int64 (const DBusString *str,
   1.139 +                  int               start,
   1.140 +                  dbus_int64_t     *val)
   1.141 +{
   1.142 +  const char *p;
   1.143 +  
   1.144 +  if ((_dbus_string_get_length (str) - start) < 8)
   1.145 +    return FALSE;
   1.146 +
   1.147 +  p = _dbus_string_get_const_data (str);
   1.148 +
   1.149 +  p += start;
   1.150 +
   1.151 +  fetch_long64 (val, p, 8);
   1.152 +  
   1.153 +  return TRUE;
   1.154 +}
   1.155 +
   1.156 +static dbus_bool_t
   1.157 +string_get_string (const DBusString *str,
   1.158 +                   int               start,
   1.159 +                   long              terminator,
   1.160 +                   DBusString       *val,
   1.161 +                   int              *end)
   1.162 +{
   1.163 +  int i;
   1.164 +  long n;
   1.165 +  
   1.166 +  i = start;
   1.167 +  while (string_get_int (str, i, &n))
   1.168 +    {
   1.169 +      unsigned char b;
   1.170 +      
   1.171 +      i += 4;
   1.172 +      
   1.173 +      if (n == terminator)
   1.174 +        break;
   1.175 +
   1.176 +      b = n & 0xff;
   1.177 +      if (b)
   1.178 +        {
   1.179 +          _dbus_string_append_byte (val, b);
   1.180 +          b = (n >> 8) & 0xff;
   1.181 +          if (b)
   1.182 +            {
   1.183 +              _dbus_string_append_byte (val, b);
   1.184 +              b = (n >> 16) & 0xff;
   1.185 +              if (b)
   1.186 +                {
   1.187 +                  _dbus_string_append_byte (val, b);
   1.188 +                  b = (n >> 24) & 0xff;
   1.189 +                  if (b)
   1.190 +                    _dbus_string_append_byte (val, b);
   1.191 +                }
   1.192 +            }
   1.193 +        }
   1.194 +    }
   1.195 +
   1.196 +  *end = i;
   1.197 +  
   1.198 +  return TRUE;
   1.199 +}
   1.200 +
   1.201 +#ifdef DBUS_HAVE_GCC33_GCOV
   1.202 +/* In gcc33 .bbg files, there's a function name of the form:
   1.203 + *   -1, length, name (padded to 4), -1, checksum
   1.204 + */
   1.205 +static dbus_bool_t
   1.206 +string_get_function (const DBusString *str,
   1.207 +                     int               start,
   1.208 +                     DBusString       *funcname,
   1.209 +                     int              *checksum,
   1.210 +                     int              *next)
   1.211 +{
   1.212 +  int end;
   1.213 +  long val;
   1.214 +  int i;
   1.215 +
   1.216 +  i = start;
   1.217 +  
   1.218 +  if (!string_get_int (str, i, &val))
   1.219 +    die ("no room for -1 before function name\n");
   1.220 +        
   1.221 +  i += 4;
   1.222 +
   1.223 +  if (val != -1)
   1.224 +    die ("value before function name is not -1\n");
   1.225 +  
   1.226 +  if (!string_get_int (str, i, &val))
   1.227 +    die ("no length found for function name\n");
   1.228 +        
   1.229 +  i += 4;
   1.230 +
   1.231 +  end = i + val;
   1.232 +  if (end > _dbus_string_get_length (str))
   1.233 +    die ("Function name length points past end of file\n");
   1.234 +
   1.235 +  if (!_dbus_string_append (funcname,
   1.236 +                            _dbus_string_get_const_data (str) + i))
   1.237 +    die ("no memory\n");
   1.238 +        
   1.239 +  /* skip alignment padding the length doesn't include the nul so add 1
   1.240 +   */
   1.241 +  i = _DBUS_ALIGN_VALUE (end + 1, 4);
   1.242 +        
   1.243 +  if (!string_get_int (str, i, &val) ||
   1.244 +      val != -1)
   1.245 +    die ("-1 at end of function name not found\n");
   1.246 +        
   1.247 +  i += 4;
   1.248 +
   1.249 +  if (!string_get_int (str, i, &val))
   1.250 +    die ("no checksum found at end of function name\n");
   1.251 +        
   1.252 +  i += 4;
   1.253 +
   1.254 +  *checksum = val;
   1.255 +
   1.256 +  *next = i;
   1.257 +
   1.258 +  return TRUE;
   1.259 +}
   1.260 +#endif /* DBUS_HAVE_GCC33_GCOV */
   1.261 +
   1.262 +static void
   1.263 +dump_bb_file (const DBusString *contents)
   1.264 +{
   1.265 +  int i;
   1.266 +  long val;
   1.267 +  int n_functions;
   1.268 +
   1.269 +  n_functions = 0;
   1.270 +  i = 0;
   1.271 +  while (string_get_int (contents, i, &val))
   1.272 +    {
   1.273 +      i += 4;
   1.274 +      
   1.275 +      switch (val)
   1.276 +        {
   1.277 +        case BB_FILENAME:
   1.278 +          {
   1.279 +            DBusString f;
   1.280 +
   1.281 +            if (!_dbus_string_init (&f))
   1.282 +              die ("no memory\n");
   1.283 +
   1.284 +            if (string_get_string (contents, i,
   1.285 +                                   BB_FILENAME,
   1.286 +                                   &f, &i))
   1.287 +              {
   1.288 +                printf ("File %s\n", _dbus_string_get_const_data (&f));
   1.289 +              }
   1.290 +            _dbus_string_free (&f);
   1.291 +          }
   1.292 +          break;
   1.293 +        case BB_FUNCTION:
   1.294 +          {
   1.295 +            DBusString f;
   1.296 +            if (!_dbus_string_init (&f))
   1.297 +              die ("no memory\n");
   1.298 +
   1.299 +            if (string_get_string (contents, i,
   1.300 +                                   BB_FUNCTION,
   1.301 +                                   &f, &i))
   1.302 +              {
   1.303 +                printf ("Function %s\n", _dbus_string_get_const_data (&f));
   1.304 +              }
   1.305 +            _dbus_string_free (&f);
   1.306 +
   1.307 +            n_functions += 1;
   1.308 +          }
   1.309 +          break;
   1.310 +        case BB_ENDOFLIST:
   1.311 +          printf ("End of block\n");
   1.312 +          break;
   1.313 +        default:
   1.314 +          printf ("Line %ld\n", val);
   1.315 +          break;
   1.316 +        }
   1.317 +    }
   1.318 +
   1.319 +  printf ("%d functions in file\n", n_functions);
   1.320 +}
   1.321 +
   1.322 +#define FLAG_ON_TREE 0x1
   1.323 +#define FLAG_FAKE 0x2
   1.324 +#define FLAG_FALL_THROUGH 0x4
   1.325 +
   1.326 +static void
   1.327 +dump_bbg_file (const DBusString *contents)
   1.328 +{
   1.329 +  int i;
   1.330 +  long val;
   1.331 +  int n_functions;
   1.332 +  int n_arcs;
   1.333 +  int n_blocks;
   1.334 +  int n_arcs_off_tree;
   1.335 +  
   1.336 +  n_arcs_off_tree = 0;
   1.337 +  n_blocks = 0;
   1.338 +  n_arcs = 0;
   1.339 +  n_functions = 0;
   1.340 +  i = 0;
   1.341 +  while (i < _dbus_string_get_length (contents))
   1.342 +    {
   1.343 +      long n_blocks_in_func;
   1.344 +      long n_arcs_in_func; 
   1.345 +      int j;
   1.346 +
   1.347 +#ifdef DBUS_HAVE_GCC33_GCOV
   1.348 +      /* In gcc33 .bbg files, there's a function name of the form:
   1.349 +       *   -1, length, name (padded to 4), -1, checksum
   1.350 +       * after that header on each function description, it's
   1.351 +       * the same as in gcc32
   1.352 +       */
   1.353 +
   1.354 +      {
   1.355 +        DBusString funcname;
   1.356 +        int checksum;
   1.357 +        
   1.358 +        if (!_dbus_string_init (&funcname))
   1.359 +          die ("no memory\n");
   1.360 +
   1.361 +        if (!string_get_function (contents, i,
   1.362 +                                  &funcname, &checksum, &i))
   1.363 +          die ("could not read function name\n");
   1.364 +        
   1.365 +        printf ("Function name is \"%s\" checksum %d\n",
   1.366 +                _dbus_string_get_const_data (&funcname),
   1.367 +                checksum);
   1.368 +        
   1.369 +        _dbus_string_free (&funcname);
   1.370 +      }
   1.371 +#endif /* DBUS_HAVE_GCC33_GCOV */
   1.372 +      
   1.373 +      if (!string_get_int (contents, i, &val))
   1.374 +        die ("no count of blocks in func found\n");
   1.375 +      
   1.376 +      i += 4;
   1.377 +      
   1.378 +      n_blocks_in_func = val;
   1.379 +
   1.380 +      if (!string_get_int (contents, i, &n_arcs_in_func))
   1.381 +        break;
   1.382 +
   1.383 +      i += 4;
   1.384 +
   1.385 +      printf ("Function has %ld blocks and %ld arcs\n",
   1.386 +              n_blocks_in_func, n_arcs_in_func);
   1.387 +
   1.388 +      n_functions += 1;
   1.389 +      n_blocks += n_blocks_in_func;
   1.390 +      n_arcs += n_arcs_in_func;
   1.391 +      
   1.392 +      j = 0;
   1.393 +      while (j < n_blocks_in_func)
   1.394 +        {
   1.395 +          long n_arcs_in_block;
   1.396 +          int k;
   1.397 +          
   1.398 +          if (!string_get_int (contents, i, &n_arcs_in_block))
   1.399 +            break;
   1.400 +
   1.401 +          i += 4;
   1.402 +
   1.403 +          printf ("  Block has %ld arcs\n", n_arcs_in_block);
   1.404 +          
   1.405 +          k = 0;
   1.406 +          while (k < n_arcs_in_block)
   1.407 +            {
   1.408 +              long destination_block;
   1.409 +              long flags;
   1.410 +              
   1.411 +              if (!string_get_int (contents, i, &destination_block))
   1.412 +                break;
   1.413 +
   1.414 +              i += 4;
   1.415 +              
   1.416 +              if (!string_get_int (contents, i, &flags))
   1.417 +                break;
   1.418 +
   1.419 +              i += 4;
   1.420 +
   1.421 +              printf ("    Arc has destination block %ld flags 0x%lx\n",
   1.422 +                      destination_block, flags);
   1.423 +
   1.424 +              if ((flags & FLAG_ON_TREE) == 0)
   1.425 +                n_arcs_off_tree += 1;
   1.426 +              
   1.427 +              ++k;
   1.428 +            }
   1.429 +
   1.430 +          if (k < n_arcs_in_block)
   1.431 +            break;
   1.432 +          
   1.433 +          ++j;
   1.434 +        }
   1.435 +
   1.436 +      if (j < n_blocks_in_func)
   1.437 +        break;
   1.438 +
   1.439 +      if (!string_get_int (contents, i, &val))
   1.440 +        break;
   1.441 +
   1.442 +      i += 4;
   1.443 +
   1.444 +      if (val != -1)
   1.445 +        die ("-1 separator not found\n");
   1.446 +    }
   1.447 +
   1.448 +  printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
   1.449 +          n_functions, n_blocks, n_arcs, n_arcs_off_tree);
   1.450 +}
   1.451 +
   1.452 +#ifndef DBUS_HAVE_GCC33_GCOV
   1.453 +
   1.454 +/* gcc 3.2 version:
   1.455 + * The da file contains first a count of arcs in the file,
   1.456 + * then a count of executions for all "off tree" arcs
   1.457 + * in the file.
   1.458 + */
   1.459 +static void
   1.460 +dump_da_file (const DBusString *contents)
   1.461 +{
   1.462 +  int i;
   1.463 +  dbus_int64_t val;
   1.464 +  int n_arcs;
   1.465 +  int claimed_n_arcs;
   1.466 +
   1.467 +  i = 0;
   1.468 +  if (!string_get_int64 (contents, i, &val))
   1.469 +    return;
   1.470 +
   1.471 +  i += 8;
   1.472 +  
   1.473 +  printf ("%ld arcs in file\n", (long) val);
   1.474 +  claimed_n_arcs = val;
   1.475 +  
   1.476 +  n_arcs = 0;
   1.477 +  while (string_get_int64 (contents, i, &val))
   1.478 +    {
   1.479 +      i += 8;
   1.480 +
   1.481 +      printf ("%ld executions of arc %d\n",
   1.482 +              (long) val, n_arcs);
   1.483 +
   1.484 +      ++n_arcs;
   1.485 +    }
   1.486 +
   1.487 +  if (n_arcs != claimed_n_arcs)
   1.488 +    {
   1.489 +      printf ("File claimed to have %d arcs but only had %d\n",
   1.490 +              claimed_n_arcs, n_arcs);
   1.491 +    }
   1.492 +}
   1.493 +
   1.494 +#else /* DBUS_HAVE_GCC33_GCOV */
   1.495 +
   1.496 +/* gcc 3.3 version:
   1.497 + * The da file is more complex than 3.2.
   1.498 + *
   1.499 + * We have a magic value of "-123" only it isn't really
   1.500 + * -123, it's -123 as encoded by the crackass gcov-io.h
   1.501 + * routines. Anyway, 4 bytes.
   1.502 + *
   1.503 + * We then have:
   1.504 + *
   1.505 + *   - 4 byte count of how many functions in the following list
   1.506 + *   - 4 byte length of random extra data
   1.507 + *   - the random extra data, just skip it, info pages have some
   1.508 + *     details on what might be in there or see __bb_exit_func in gcc
   1.509 + *   - then for each function (number of functions given above):
   1.510 + *     . -1, length, funcname, alignment padding, -1
   1.511 + *     . checksum
   1.512 + *     . 4 byte number of arcs in function
   1.513 + *     . 8 bytes each, a count of execution for each arc
   1.514 + *
   1.515 + * Now, the whole thing *starting with the magic* can repeat.
   1.516 + * This is caused by multiple runs of the profiled app appending
   1.517 + * to the file.
   1.518 + */
   1.519 +static void
   1.520 +dump_da_file (const DBusString *contents)
   1.521 +{
   1.522 +  int i;
   1.523 +  dbus_int64_t v64;
   1.524 +  long val;
   1.525 +  int n_sections;
   1.526 +  int total_functions;
   1.527 +
   1.528 +  total_functions = 0;
   1.529 +  n_sections = 0;
   1.530 +
   1.531 +  i = 0;
   1.532 +  while (i < _dbus_string_get_length (contents))
   1.533 +    {
   1.534 +      int claimed_n_functions;
   1.535 +      int n_functions;
   1.536 +      int total_arcs;
   1.537 +
   1.538 +      printf (".da file section %d\n", n_sections);
   1.539 +      
   1.540 +      if (!string_get_int (contents, i, &val))
   1.541 +        die ("no magic found in .da file\n");
   1.542 +
   1.543 +      i += 4;
   1.544 +
   1.545 +      if (val != -123)
   1.546 +        die ("wrong file magic in .da file\n");
   1.547 +
   1.548 +      if (!string_get_int (contents, i, &val))
   1.549 +        die ("no function count in .da file\n");
   1.550 +      i += 4;
   1.551 +      claimed_n_functions = val;
   1.552 +
   1.553 +      printf ("%d functions expected in section %d of .da file\n",
   1.554 +              claimed_n_functions, n_sections);
   1.555 +      
   1.556 +      if (!string_get_int (contents, i, &val))
   1.557 +        die ("no extra data length in .da file\n");
   1.558 +
   1.559 +      i += 4;
   1.560 +
   1.561 +      i += val;
   1.562 +
   1.563 +      total_arcs = 0;
   1.564 +      n_functions = 0;
   1.565 +      while (n_functions < claimed_n_functions)
   1.566 +        {
   1.567 +          DBusString funcname;
   1.568 +          int checksum;
   1.569 +          int claimed_n_arcs;
   1.570 +          int n_arcs;
   1.571 +          
   1.572 +          if (!_dbus_string_init (&funcname))
   1.573 +            die ("no memory\n");
   1.574 +          
   1.575 +          if (!string_get_function (contents, i,
   1.576 +                                    &funcname, &checksum, &i))
   1.577 +            die ("could not read function name\n");
   1.578 +          
   1.579 +          if (!string_get_int (contents, i, &val))
   1.580 +            die ("no arc count for function\n");
   1.581 +          
   1.582 +          i += 4;
   1.583 +          claimed_n_arcs = val;
   1.584 +          
   1.585 +          printf ("  %d arcs in function %d %s checksum %d\n",
   1.586 +                  claimed_n_arcs, n_functions,
   1.587 +                  _dbus_string_get_const_data (&funcname),
   1.588 +                  checksum);
   1.589 +          
   1.590 +          n_arcs = 0;
   1.591 +          while (n_arcs < claimed_n_arcs)
   1.592 +            {
   1.593 +              if (!string_get_int64 (contents, i, &v64))
   1.594 +                die ("did not get execution count for arc\n");
   1.595 +              
   1.596 +              i += 8;
   1.597 +              
   1.598 +              printf ("    %ld executions of arc %d (total arcs %d)\n",
   1.599 +                      (long) v64, n_arcs, total_arcs + n_arcs);
   1.600 +              
   1.601 +              ++n_arcs;
   1.602 +            }
   1.603 +
   1.604 +          _dbus_string_free (&funcname);
   1.605 +
   1.606 +          total_arcs += n_arcs;
   1.607 +          ++n_functions;
   1.608 +        }
   1.609 +
   1.610 +      printf ("total of %d functions and %d arcs in section %d\n",
   1.611 +              n_functions, total_arcs, n_sections);
   1.612 +      
   1.613 +      total_functions += n_functions;
   1.614 +      ++n_sections;
   1.615 +    }
   1.616 +
   1.617 +  printf ("%d total function sections in %d total .da file sections\n",
   1.618 +          total_functions, n_sections);
   1.619 +}
   1.620 +
   1.621 +#endif /* DBUS_HAVE_GCC33_GCOV */
   1.622 +
   1.623 +typedef struct Arc Arc;
   1.624 +typedef struct Block Block;
   1.625 +typedef struct Function Function;
   1.626 +typedef struct File File;
   1.627 +typedef struct Line Line;
   1.628 +
   1.629 +struct Arc
   1.630 +{
   1.631 +  int source;
   1.632 +  int target;
   1.633 +  dbus_int64_t arc_count;
   1.634 +  unsigned int count_valid : 1;
   1.635 +  unsigned int on_tree : 1;
   1.636 +  unsigned int fake : 1;
   1.637 +  unsigned int fall_through : 1;
   1.638 +  Arc *pred_next;
   1.639 +  Arc *succ_next;
   1.640 +};
   1.641 +
   1.642 +struct Block
   1.643 +{
   1.644 +  Arc *succ;
   1.645 +  Arc *pred;
   1.646 +  dbus_int64_t succ_count;
   1.647 +  dbus_int64_t pred_count;
   1.648 +  dbus_int64_t exec_count;
   1.649 +  DBusList *lines;
   1.650 +  unsigned int count_valid : 1;
   1.651 +  unsigned int on_tree : 1;
   1.652 +  unsigned int inside_dbus_build_tests : 1;
   1.653 +};
   1.654 +
   1.655 +struct Function
   1.656 +{
   1.657 +  char *name;
   1.658 +  int checksum;
   1.659 +  Block *block_graph;
   1.660 +  int n_blocks;
   1.661 +  /* number of blocks in DBUS_BUILD_TESTS */
   1.662 +  int n_test_blocks;
   1.663 +  int n_test_blocks_executed;
   1.664 +  /* number of blocks outside DBUS_BUILD_TESTS */
   1.665 +  int n_nontest_blocks;
   1.666 +  int n_nontest_blocks_executed;
   1.667 +  /* Summary result flags */
   1.668 +  unsigned int unused : 1;
   1.669 +  unsigned int inside_dbus_build_tests : 1;
   1.670 +  unsigned int partial : 1; /* only some of the blocks were executed */
   1.671 +};
   1.672 +
   1.673 +struct Line
   1.674 +{
   1.675 +  int    number;
   1.676 +  char  *text;
   1.677 +  DBusList *blocks;
   1.678 +  unsigned int inside_dbus_build_tests : 1;
   1.679 +  unsigned int partial : 1; /* only some of the blocks were executed */
   1.680 +};
   1.681 +
   1.682 +struct File
   1.683 +{
   1.684 +  char *name;
   1.685 +  Line *lines;
   1.686 +  int   n_lines;
   1.687 +  DBusList *functions;
   1.688 +};
   1.689 +
   1.690 +static void
   1.691 +function_add_arc (Function *function,
   1.692 +                  long      source,
   1.693 +                  long      target,
   1.694 +                  long      flags)
   1.695 +{
   1.696 +  Arc *arc;
   1.697 +
   1.698 +  arc = dbus_new0 (Arc, 1);
   1.699 +  if (arc == NULL)
   1.700 +    die ("no memory\n");
   1.701 +  
   1.702 +  arc->target = target;
   1.703 +  arc->source = source;
   1.704 +
   1.705 +  arc->succ_next = function->block_graph[source].succ;
   1.706 +  function->block_graph[source].succ = arc;
   1.707 +  function->block_graph[source].succ_count += 1;
   1.708 +
   1.709 +  arc->pred_next = function->block_graph[target].pred;
   1.710 +  function->block_graph[target].pred = arc;
   1.711 +  function->block_graph[target].pred_count += 1;
   1.712 +
   1.713 +  if ((flags & FLAG_ON_TREE) != 0)
   1.714 +    arc->on_tree = TRUE;
   1.715 +
   1.716 +  if ((flags & FLAG_FAKE) != 0)
   1.717 +    arc->fake = TRUE;
   1.718 +
   1.719 +  if ((flags & FLAG_FALL_THROUGH) != 0)
   1.720 +    arc->fall_through = TRUE;
   1.721 +}
   1.722 +
   1.723 +
   1.724 +static Arc*
   1.725 +reverse_arcs (Arc *arc)
   1.726 +{
   1.727 +  struct Arc *prev = 0;
   1.728 +  struct Arc *next;
   1.729 +
   1.730 +  for ( ; arc; arc = next)
   1.731 +    {
   1.732 +      next = arc->succ_next;
   1.733 +      arc->succ_next = prev;
   1.734 +      prev = arc;
   1.735 +    }
   1.736 +
   1.737 +  return prev;
   1.738 +}
   1.739 +
   1.740 +static void
   1.741 +function_reverse_succ_arcs (Function *func)
   1.742 +{
   1.743 +  /* Must reverse the order of all succ arcs, to ensure that they match
   1.744 +   * the order of the data in the .da file.
   1.745 +   */
   1.746 +  int i;
   1.747 +  
   1.748 +  for (i = 0; i < func->n_blocks; i++)
   1.749 +    if (func->block_graph[i].succ)
   1.750 +      func->block_graph[i].succ = reverse_arcs (func->block_graph[i].succ);
   1.751 +}
   1.752 +
   1.753 +static void
   1.754 +get_functions_from_bbg (const DBusString  *contents,
   1.755 +                        DBusList         **functions)
   1.756 +{
   1.757 +  int i;
   1.758 +  long val;
   1.759 +  int n_functions;
   1.760 +  int n_arcs;
   1.761 +  int n_blocks;
   1.762 +  int n_arcs_off_tree;
   1.763 +
   1.764 +#if 0
   1.765 +  printf ("Loading arcs and blocks from .bbg file\n");
   1.766 +#endif
   1.767 +  
   1.768 +  n_arcs_off_tree = 0;
   1.769 +  n_blocks = 0;
   1.770 +  n_arcs = 0;
   1.771 +  n_functions = 0;
   1.772 +  i = 0;
   1.773 +  while (i < _dbus_string_get_length (contents))
   1.774 +    {
   1.775 +      Function *func;
   1.776 +      long n_blocks_in_func;
   1.777 +      long n_arcs_in_func; 
   1.778 +      int j;
   1.779 +
   1.780 +#ifdef DBUS_HAVE_GCC33_GCOV
   1.781 +      DBusString funcname;
   1.782 +      int checksum;
   1.783 +
   1.784 +      /* In gcc33 .bbg files, there's a function name of the form:
   1.785 +       *   -1, length, name (padded to 4), -1, checksum
   1.786 +       * after that header on each function description, it's
   1.787 +       * the same as in gcc32
   1.788 +       */
   1.789 +      if (!_dbus_string_init (&funcname))
   1.790 +        die ("no memory\n");
   1.791 +      
   1.792 +      if (!string_get_function (contents, i,
   1.793 +                                &funcname, &checksum, &i))
   1.794 +        die ("could not read function name\n");
   1.795 +#endif /* DBUS_HAVE_GCC33_GCOV */
   1.796 +
   1.797 +      if (!string_get_int (contents, i, &val))
   1.798 +        break;
   1.799 +      
   1.800 +      n_blocks_in_func = val;
   1.801 +      
   1.802 +      i += 4;
   1.803 +
   1.804 +      if (!string_get_int (contents, i, &n_arcs_in_func))
   1.805 +        break;
   1.806 +
   1.807 +      i += 4;
   1.808 +
   1.809 +      n_functions += 1;
   1.810 +      n_blocks += n_blocks_in_func;
   1.811 +      n_arcs += n_arcs_in_func;
   1.812 +
   1.813 +      func = dbus_new0 (Function, 1);
   1.814 +      if (func == NULL)
   1.815 +        die ("no memory\n");
   1.816 +
   1.817 +#ifdef DBUS_HAVE_GCC33_GCOV
   1.818 +      func->name = _dbus_strdup (_dbus_string_get_const_data (&funcname));
   1.819 +      func->checksum = checksum;
   1.820 +      _dbus_string_free (&funcname);
   1.821 +#endif
   1.822 +      
   1.823 +      func->block_graph = dbus_new0 (Block, n_blocks_in_func);
   1.824 +      func->n_blocks = n_blocks_in_func;
   1.825 +      
   1.826 +      j = 0;
   1.827 +      while (j < n_blocks_in_func)
   1.828 +        {
   1.829 +          long n_arcs_in_block;
   1.830 +          int k;
   1.831 +          
   1.832 +          if (!string_get_int (contents, i, &n_arcs_in_block))
   1.833 +            break;
   1.834 +
   1.835 +          i += 4;
   1.836 +          
   1.837 +          k = 0;
   1.838 +          while (k < n_arcs_in_block)
   1.839 +            {
   1.840 +              long destination_block;
   1.841 +              long flags;
   1.842 +              
   1.843 +              if (!string_get_int (contents, i, &destination_block))
   1.844 +                break;
   1.845 +
   1.846 +              i += 4;
   1.847 +              
   1.848 +              if (!string_get_int (contents, i, &flags))
   1.849 +                break;
   1.850 +
   1.851 +              i += 4;
   1.852 +
   1.853 +              if ((flags & FLAG_ON_TREE) == 0)
   1.854 +                n_arcs_off_tree += 1;
   1.855 +
   1.856 +              function_add_arc (func, j, destination_block,
   1.857 +                                flags);
   1.858 +              
   1.859 +              ++k;
   1.860 +            }
   1.861 +
   1.862 +          if (k < n_arcs_in_block)
   1.863 +            break;
   1.864 +          
   1.865 +          ++j;
   1.866 +        }
   1.867 +
   1.868 +      if (j < n_blocks_in_func)
   1.869 +        break;
   1.870 +
   1.871 +      function_reverse_succ_arcs (func);
   1.872 +      
   1.873 +      if (!_dbus_list_append (functions, func))
   1.874 +        die ("no memory\n");
   1.875 +      
   1.876 +      if (!string_get_int (contents, i, &val))
   1.877 +        break;
   1.878 +
   1.879 +      i += 4;
   1.880 +
   1.881 +      if (val != -1)
   1.882 +        die ("-1 separator not found in .bbg file\n");
   1.883 +    }
   1.884 +
   1.885 +#if 0
   1.886 +  printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
   1.887 +          n_functions, n_blocks, n_arcs, n_arcs_off_tree);
   1.888 +#endif
   1.889 +  
   1.890 +  _dbus_assert (n_functions == _dbus_list_get_length (functions));
   1.891 +}
   1.892 +
   1.893 +#ifdef DBUS_HAVE_GCC33_GCOV
   1.894 +static void
   1.895 +add_counts_from_da (const DBusString  *contents,
   1.896 +                    DBusList         **functions)
   1.897 +{
   1.898 +  int i;
   1.899 +  dbus_int64_t v64;
   1.900 +  long val;
   1.901 +  int n_sections;
   1.902 +  DBusList *link;
   1.903 +  Function *current_func;  
   1.904 +  int current_block;
   1.905 +  Arc *current_arc;
   1.906 +
   1.907 +  n_sections = 0;
   1.908 +
   1.909 +  i = 0;
   1.910 +  while (i < _dbus_string_get_length (contents))
   1.911 +    {
   1.912 +      int claimed_n_functions;
   1.913 +      int n_functions;
   1.914 +      
   1.915 +      if (!string_get_int (contents, i, &val))
   1.916 +        die ("no magic found in .da file\n");
   1.917 +
   1.918 +      i += 4;
   1.919 +
   1.920 +      if (val != -123)
   1.921 +        die ("wrong file magic in .da file\n");
   1.922 +
   1.923 +      if (!string_get_int (contents, i, &val))
   1.924 +        die ("no function count in .da file\n");
   1.925 +      i += 4;
   1.926 +      claimed_n_functions = val;
   1.927 +      
   1.928 +      if (!string_get_int (contents, i, &val))
   1.929 +        die ("no extra data length in .da file\n");
   1.930 +
   1.931 +      i += 4;
   1.932 +
   1.933 +      i += val;
   1.934 +
   1.935 +      link = _dbus_list_get_first_link (functions);
   1.936 +      if (link == NULL)
   1.937 +        goto no_more_functions;
   1.938 +      
   1.939 +      n_functions = 0;
   1.940 +      while (n_functions < claimed_n_functions && link != NULL)
   1.941 +        {
   1.942 +          DBusString funcname;
   1.943 +          int checksum;
   1.944 +          int claimed_n_arcs;
   1.945 +          int n_arcs;
   1.946 +
   1.947 +          current_func = link->data;
   1.948 +          current_block = 0;
   1.949 +          current_arc = current_func->block_graph[current_block].succ;
   1.950 +          
   1.951 +          if (!_dbus_string_init (&funcname))
   1.952 +            die ("no memory\n");
   1.953 +          
   1.954 +          if (!string_get_function (contents, i,
   1.955 +                                    &funcname, &checksum, &i))
   1.956 +            die ("could not read function name\n");
   1.957 +
   1.958 +          if (!_dbus_string_equal_c_str (&funcname, current_func->name))
   1.959 +            {
   1.960 +              fprintf (stderr, "Expecting .da info for %s but got %s\n",
   1.961 +                       current_func->name,
   1.962 +                       _dbus_string_get_const_data (&funcname));
   1.963 +              exit (1);
   1.964 +            }
   1.965 +          
   1.966 +          if (checksum != current_func->checksum)
   1.967 +            die (".da file checksum doesn't match checksum from .bbg file\n");
   1.968 +          
   1.969 +          if (!string_get_int (contents, i, &val))
   1.970 +            die ("no arc count for function\n");
   1.971 +          
   1.972 +          i += 4;
   1.973 +          claimed_n_arcs = val;
   1.974 +
   1.975 +          /* For each arc in the profile, find the corresponding
   1.976 +           * arc in the function and increment its count
   1.977 +           */
   1.978 +          n_arcs = 0;
   1.979 +          while (n_arcs < claimed_n_arcs)
   1.980 +            {
   1.981 +              if (!string_get_int64 (contents, i, &v64))
   1.982 +                die ("did not get execution count for arc\n");
   1.983 +              
   1.984 +              i += 8;
   1.985 +
   1.986 +              /* Find the next arc in the function that isn't on tree */
   1.987 +              while (current_arc == NULL ||
   1.988 +                     current_arc->on_tree)
   1.989 +                {
   1.990 +                  if (current_arc == NULL)
   1.991 +                    {
   1.992 +                      ++current_block;
   1.993 +              
   1.994 +                      if (current_block >= current_func->n_blocks)
   1.995 +                        die ("too many blocks in function\n");
   1.996 +              
   1.997 +                      current_arc = current_func->block_graph[current_block].succ;
   1.998 +                    }
   1.999 +                  else
  1.1000 +                    {
  1.1001 +                      current_arc = current_arc->succ_next;
  1.1002 +                    }
  1.1003 +                }
  1.1004 +              
  1.1005 +              _dbus_assert (current_arc != NULL);
  1.1006 +              _dbus_assert (!current_arc->on_tree);
  1.1007 +              
  1.1008 +              current_arc->arc_count = v64;
  1.1009 +              current_arc->count_valid = TRUE;
  1.1010 +              current_func->block_graph[current_block].succ_count -= 1;
  1.1011 +              current_func->block_graph[current_arc->target].pred_count -= 1;
  1.1012 +              
  1.1013 +              ++n_arcs;
  1.1014 +              
  1.1015 +              current_arc = current_arc->succ_next;
  1.1016 +            }
  1.1017 +
  1.1018 +          _dbus_string_free (&funcname);
  1.1019 +
  1.1020 +          link = _dbus_list_get_next_link (functions, link);
  1.1021 +          ++n_functions;
  1.1022 +
  1.1023 +          if (link == NULL && n_functions < claimed_n_functions)
  1.1024 +            {
  1.1025 +              fprintf (stderr, "Ran out of functions loading .da file\n");
  1.1026 +              goto no_more_functions;
  1.1027 +            }
  1.1028 +        }
  1.1029 +
  1.1030 +    no_more_functions:
  1.1031 +      
  1.1032 +      ++n_sections;
  1.1033 +    }
  1.1034 +}
  1.1035 +#else /* DBUS_HAVE_GCC33_GCOV */
  1.1036 +static void
  1.1037 +add_counts_from_da (const DBusString  *contents,
  1.1038 +                    DBusList         **functions)
  1.1039 +{
  1.1040 +  int i;
  1.1041 +  dbus_int64_t val;
  1.1042 +  int n_arcs;
  1.1043 +  int claimed_n_arcs;
  1.1044 +  DBusList *link;
  1.1045 +  Function *current_func;  
  1.1046 +  int current_block;
  1.1047 +  Arc *current_arc;
  1.1048 +
  1.1049 +#if 0
  1.1050 +  printf ("Loading execution count for each arc from .da file\n");
  1.1051 +#endif
  1.1052 +  
  1.1053 +  i = 0;
  1.1054 +  if (!string_get_int64 (contents, i, &val))
  1.1055 +    return;
  1.1056 +
  1.1057 +  i += 8;
  1.1058 +  
  1.1059 +  claimed_n_arcs = val;
  1.1060 +
  1.1061 +  link = _dbus_list_get_first_link (functions);
  1.1062 +  if (link == NULL)
  1.1063 +    goto done;
  1.1064 +
  1.1065 +  current_func = link->data;
  1.1066 +  current_block = 0;
  1.1067 +  current_arc = current_func->block_graph[current_block].succ;
  1.1068 +  
  1.1069 +  n_arcs = 0;
  1.1070 +  while (string_get_int64 (contents, i, &val))
  1.1071 +    {
  1.1072 +      i += 8;
  1.1073 +
  1.1074 +      while (current_arc == NULL ||
  1.1075 +             current_arc->on_tree)
  1.1076 +        {
  1.1077 +          if (current_arc == NULL)
  1.1078 +            {
  1.1079 +              ++current_block;
  1.1080 +              
  1.1081 +              if (current_block == current_func->n_blocks)
  1.1082 +                {
  1.1083 +                  link = _dbus_list_get_next_link (functions, link);
  1.1084 +                  if (link == NULL)
  1.1085 +                    {
  1.1086 +                      fprintf (stderr, "Ran out of functions loading .da file\n");
  1.1087 +                      goto done;
  1.1088 +                    }
  1.1089 +                  current_func = link->data;
  1.1090 +                  current_block = 0;
  1.1091 +                }
  1.1092 +              
  1.1093 +              current_arc = current_func->block_graph[current_block].succ;
  1.1094 +            }
  1.1095 +          else
  1.1096 +            {
  1.1097 +              current_arc = current_arc->succ_next;
  1.1098 +            }
  1.1099 +        }
  1.1100 +
  1.1101 +      _dbus_assert (current_arc != NULL);
  1.1102 +      _dbus_assert (!current_arc->on_tree);
  1.1103 +
  1.1104 +      current_arc->arc_count = val;
  1.1105 +      current_arc->count_valid = TRUE;
  1.1106 +      current_func->block_graph[current_block].succ_count -= 1;
  1.1107 +      current_func->block_graph[current_arc->target].pred_count -= 1;
  1.1108 +      
  1.1109 +      ++n_arcs;
  1.1110 +
  1.1111 +      current_arc = current_arc->succ_next;
  1.1112 +    }
  1.1113 +
  1.1114 + done:
  1.1115 +  
  1.1116 +  if (n_arcs != claimed_n_arcs)
  1.1117 +    {
  1.1118 +      fprintf (stderr, "File claimed to have %d arcs but only had %d\n",
  1.1119 +               claimed_n_arcs, n_arcs);
  1.1120 +      exit (1);
  1.1121 +    }
  1.1122 +
  1.1123 +#if 0
  1.1124 +  printf ("%d arcs in file\n", n_arcs);
  1.1125 +#endif
  1.1126 +}
  1.1127 +#endif
  1.1128 +
  1.1129 +static void
  1.1130 +function_solve_graph (Function *func)
  1.1131 +{
  1.1132 +  int passes, changes;
  1.1133 +  dbus_int64_t total;
  1.1134 +  int i;
  1.1135 +  Arc *arc;
  1.1136 +  Block *block_graph;
  1.1137 +  int n_blocks;
  1.1138 +
  1.1139 +#if 0
  1.1140 +  printf ("Solving function graph\n");
  1.1141 +#endif
  1.1142 +  
  1.1143 +  n_blocks = func->n_blocks;
  1.1144 +  block_graph = func->block_graph;
  1.1145 +
  1.1146 +  /* For every block in the file,
  1.1147 +     - if every exit/entrance arc has a known count, then set the block count
  1.1148 +     - if the block count is known, and every exit/entrance arc but one has
  1.1149 +     a known execution count, then set the count of the remaining arc
  1.1150 +
  1.1151 +     As arc counts are set, decrement the succ/pred count, but don't delete
  1.1152 +     the arc, that way we can easily tell when all arcs are known, or only
  1.1153 +     one arc is unknown.  */
  1.1154 +
  1.1155 +  /* The order that the basic blocks are iterated through is important.
  1.1156 +     Since the code that finds spanning trees starts with block 0, low numbered
  1.1157 +     arcs are put on the spanning tree in preference to high numbered arcs.
  1.1158 +     Hence, most instrumented arcs are at the end.  Graph solving works much
  1.1159 +     faster if we propagate numbers from the end to the start.
  1.1160 +
  1.1161 +     This takes an average of slightly more than 3 passes.  */
  1.1162 +
  1.1163 +  changes = 1;
  1.1164 +  passes = 0;
  1.1165 +  while (changes)
  1.1166 +    {
  1.1167 +      passes++;
  1.1168 +      changes = 0;
  1.1169 +
  1.1170 +      for (i = n_blocks - 1; i >= 0; i--)
  1.1171 +	{
  1.1172 +	  if (! block_graph[i].count_valid)
  1.1173 +	    {
  1.1174 +	      if (block_graph[i].succ_count == 0)
  1.1175 +		{
  1.1176 +		  total = 0;
  1.1177 +		  for (arc = block_graph[i].succ; arc;
  1.1178 +		       arc = arc->succ_next)
  1.1179 +		    total += arc->arc_count;
  1.1180 +		  block_graph[i].exec_count = total;
  1.1181 +		  block_graph[i].count_valid = 1;
  1.1182 +		  changes = 1;
  1.1183 +		}
  1.1184 +	      else if (block_graph[i].pred_count == 0)
  1.1185 +		{
  1.1186 +		  total = 0;
  1.1187 +		  for (arc = block_graph[i].pred; arc;
  1.1188 +		       arc = arc->pred_next)
  1.1189 +		    total += arc->arc_count;
  1.1190 +		  block_graph[i].exec_count = total;
  1.1191 +		  block_graph[i].count_valid = 1;
  1.1192 +		  changes = 1;
  1.1193 +		}
  1.1194 +	    }
  1.1195 +	  if (block_graph[i].count_valid)
  1.1196 +	    {
  1.1197 +	      if (block_graph[i].succ_count == 1)
  1.1198 +		{
  1.1199 +		  total = 0;
  1.1200 +		  /* One of the counts will be invalid, but it is zero,
  1.1201 +		     so adding it in also doesn't hurt.  */
  1.1202 +		  for (arc = block_graph[i].succ; arc;
  1.1203 +		       arc = arc->succ_next)
  1.1204 +		    total += arc->arc_count;
  1.1205 +		  /* Calculate count for remaining arc by conservation.  */
  1.1206 +		  total = block_graph[i].exec_count - total;
  1.1207 +		  /* Search for the invalid arc, and set its count.  */
  1.1208 +		  for (arc = block_graph[i].succ; arc;
  1.1209 +		       arc = arc->succ_next)
  1.1210 +		    if (! arc->count_valid)
  1.1211 +		      break;
  1.1212 +		  if (! arc)
  1.1213 +		    die ("arc == NULL\n");
  1.1214 +		  arc->count_valid = 1;
  1.1215 +		  arc->arc_count = total;
  1.1216 +		  block_graph[i].succ_count -= 1;
  1.1217 +
  1.1218 +		  block_graph[arc->target].pred_count -= 1;
  1.1219 +		  changes = 1;
  1.1220 +		}
  1.1221 +	      if (block_graph[i].pred_count == 1)
  1.1222 +		{
  1.1223 +		  total = 0;
  1.1224 +		  /* One of the counts will be invalid, but it is zero,
  1.1225 +		     so adding it in also doesn't hurt.  */
  1.1226 +		  for (arc = block_graph[i].pred; arc;
  1.1227 +		       arc = arc->pred_next)
  1.1228 +		    total += arc->arc_count;
  1.1229 +		  /* Calculate count for remaining arc by conservation.  */
  1.1230 +		  total = block_graph[i].exec_count - total;
  1.1231 +		  /* Search for the invalid arc, and set its count.  */
  1.1232 +		  for (arc = block_graph[i].pred; arc;
  1.1233 +		       arc = arc->pred_next)
  1.1234 +		    if (! arc->count_valid)
  1.1235 +		      break;
  1.1236 +		  if (! arc)
  1.1237 +                    die ("arc == NULL\n");
  1.1238 +		  arc->count_valid = 1;
  1.1239 +		  arc->arc_count = total;
  1.1240 +		  block_graph[i].pred_count -= 1;
  1.1241 +
  1.1242 +		  block_graph[arc->source].succ_count -= 1;
  1.1243 +		  changes = 1;
  1.1244 +		}
  1.1245 +	    }
  1.1246 +	}
  1.1247 +    }
  1.1248 +
  1.1249 +  /* If the graph has been correctly solved, every block will have a
  1.1250 +   * succ and pred count of zero.
  1.1251 +   */
  1.1252 +  {
  1.1253 +    dbus_bool_t header = FALSE;
  1.1254 +    for (i = 0; i < n_blocks; i++)
  1.1255 +      {
  1.1256 +        if (block_graph[i].succ_count || block_graph[i].pred_count)
  1.1257 +          {
  1.1258 +            if (!header)
  1.1259 +              {
  1.1260 +                fprintf (stderr, "WARNING: Block graph solved incorrectly for function %s\n",
  1.1261 +                         func->name);
  1.1262 +                fprintf (stderr, " this error reflects a bug in decode-gcov.c or perhaps bogus data\n");
  1.1263 +                header = TRUE;
  1.1264 +              }
  1.1265 +            fprintf (stderr, " block %d has succ_count = %d pred_count = %d\n",
  1.1266 +                     i, (int) block_graph[i].succ_count, (int) block_graph[i].pred_count);
  1.1267 +          }
  1.1268 +      }
  1.1269 +  }
  1.1270 +}
  1.1271 +
  1.1272 +static void
  1.1273 +solve_graphs (DBusList **functions)
  1.1274 +{
  1.1275 +  DBusList *link;
  1.1276 +
  1.1277 +  link = _dbus_list_get_first_link (functions);
  1.1278 +  while (link != NULL)
  1.1279 +    {
  1.1280 +      Function *func = link->data;
  1.1281 +
  1.1282 +      function_solve_graph (func);
  1.1283 +      
  1.1284 +      link = _dbus_list_get_next_link (functions, link);
  1.1285 +    }
  1.1286 +}
  1.1287 +
  1.1288 +static void
  1.1289 +load_functions_for_c_file (const DBusString *filename,
  1.1290 +                           DBusList        **functions)
  1.1291 +{
  1.1292 +  DBusString bbg_filename;
  1.1293 +  DBusString da_filename;
  1.1294 +  DBusString gcno_filename;
  1.1295 +  DBusString gcda_filename;
  1.1296 +  DBusString contents;
  1.1297 +  DBusString *name;
  1.1298 +  DBusError error;
  1.1299 +
  1.1300 +  /* With latest gcc it's .gcno instead of .bbg and
  1.1301 +   * gcda instead of .da
  1.1302 +   */
  1.1303 +  
  1.1304 +  dbus_error_init (&error);
  1.1305 +  
  1.1306 +  if (!_dbus_string_init (&bbg_filename) ||
  1.1307 +      !_dbus_string_init (&da_filename) ||
  1.1308 +      !_dbus_string_init (&gcno_filename) ||
  1.1309 +      !_dbus_string_init (&gcda_filename) ||
  1.1310 +      !_dbus_string_copy (filename, 0, &bbg_filename, 0) ||
  1.1311 +      !_dbus_string_copy (filename, 0, &da_filename, 0) ||
  1.1312 +      !_dbus_string_copy (filename, 0, &gcno_filename, 0) ||
  1.1313 +      !_dbus_string_copy (filename, 0, &gcda_filename, 0) ||
  1.1314 +      !_dbus_string_init (&contents))
  1.1315 +    die ("no memory\n");
  1.1316 +
  1.1317 +  _dbus_string_shorten (&bbg_filename, 2);
  1.1318 +  _dbus_string_shorten (&da_filename, 2);
  1.1319 +
  1.1320 +  if (!_dbus_string_append (&bbg_filename, ".bbg") ||
  1.1321 +      !_dbus_string_append (&da_filename, ".da") ||
  1.1322 +      !_dbus_string_append (&bbg_filename, ".gcno") ||
  1.1323 +      !_dbus_string_append (&bbg_filename, ".gcda"))
  1.1324 +    die ("no memory\n");
  1.1325 +
  1.1326 +  if (_dbus_file_exists (_dbus_string_get_const_data (&gcno_filename)))
  1.1327 +    name = &gcno_filename;
  1.1328 +  else
  1.1329 +    name = &bbg_filename;
  1.1330 +  
  1.1331 +  if (!_dbus_file_get_contents (&contents, name,
  1.1332 +                                &error))
  1.1333 +    {
  1.1334 +      fprintf (stderr, "Could not open file: %s\n",
  1.1335 +               error.message);
  1.1336 +      exit (1);
  1.1337 +    }
  1.1338 +
  1.1339 +  get_functions_from_bbg (&contents, functions);
  1.1340 +
  1.1341 +  _dbus_string_set_length (&contents, 0);
  1.1342 +
  1.1343 +  if (_dbus_file_exists (_dbus_string_get_const_data (&gcda_filename)))
  1.1344 +    name = &gcda_filename;
  1.1345 +  else
  1.1346 +    name = &da_filename;
  1.1347 +  
  1.1348 +  if (!_dbus_file_get_contents (&contents, name,
  1.1349 +                                &error))
  1.1350 +    {
  1.1351 +      /* Try .libs/file.da */
  1.1352 +      int slash;
  1.1353 +
  1.1354 +      if (_dbus_string_find_byte_backward (name,
  1.1355 +                                           _dbus_string_get_length (name),
  1.1356 +                                           '/',
  1.1357 +                                           &slash))
  1.1358 +        {
  1.1359 +          DBusString libs;
  1.1360 +          _dbus_string_init_const (&libs, "/.libs");
  1.1361 +
  1.1362 +          if (!_dbus_string_copy (&libs, 0, name, slash))
  1.1363 +            die ("no memory");
  1.1364 +
  1.1365 +          dbus_error_free (&error);
  1.1366 +          if (!_dbus_file_get_contents (&contents, name,
  1.1367 +                                        &error))
  1.1368 +            {
  1.1369 +              fprintf (stderr, "Could not open file: %s\n",
  1.1370 +                       error.message);
  1.1371 +              exit (1);
  1.1372 +            }
  1.1373 +        }
  1.1374 +      else
  1.1375 +        {
  1.1376 +          fprintf (stderr, "Could not open file: %s\n",
  1.1377 +                   error.message);
  1.1378 +          exit (1);
  1.1379 +        }
  1.1380 +    }
  1.1381 +  
  1.1382 +  add_counts_from_da (&contents, functions);
  1.1383 +  
  1.1384 +  solve_graphs (functions);
  1.1385 +
  1.1386 +  _dbus_string_free (&contents);
  1.1387 +  _dbus_string_free (&da_filename);
  1.1388 +  _dbus_string_free (&bbg_filename);
  1.1389 +}
  1.1390 +
  1.1391 +static void
  1.1392 +get_lines_from_bb_file (const DBusString *contents,
  1.1393 +                        File             *fl)
  1.1394 +{
  1.1395 +  int i;
  1.1396 +  long val;
  1.1397 +  int n_functions;
  1.1398 +  dbus_bool_t in_our_file;
  1.1399 +  DBusList *link;
  1.1400 +  Function *func;
  1.1401 +  int block;
  1.1402 +
  1.1403 +#if 0
  1.1404 +  printf ("Getting line numbers for blocks from .bb file\n");
  1.1405 +#endif
  1.1406 +  
  1.1407 +  /* There's this "filename" field in the .bb file which
  1.1408 +   * mysteriously comes *after* the first function in the
  1.1409 +   * file in the .bb file; and every .bb file seems to
  1.1410 +   * have only one filename. I don't understand
  1.1411 +   * what's going on here, so just set in_our_file = TRUE
  1.1412 +   * at the start categorically.
  1.1413 +   */
  1.1414 +  
  1.1415 +  block = 0;
  1.1416 +  func = NULL;
  1.1417 +  in_our_file = TRUE;
  1.1418 +  link = _dbus_list_get_first_link (&fl->functions);
  1.1419 +  n_functions = 0;
  1.1420 +  i = 0;
  1.1421 +  while (string_get_int (contents, i, &val))
  1.1422 +    {
  1.1423 +      i += 4;
  1.1424 +      
  1.1425 +      switch (val)
  1.1426 +        {
  1.1427 +        case BB_FILENAME:
  1.1428 +          {
  1.1429 +            DBusString f;
  1.1430 +
  1.1431 +            if (!_dbus_string_init (&f))
  1.1432 +              die ("no memory\n");
  1.1433 +
  1.1434 +            if (string_get_string (contents, i,
  1.1435 +                                   BB_FILENAME,
  1.1436 +                                   &f, &i))
  1.1437 +              {
  1.1438 +                /* fl->name is a full path and the filename in .bb is
  1.1439 +                 * not.
  1.1440 +                 */
  1.1441 +                DBusString tmp_str;
  1.1442 +
  1.1443 +                _dbus_string_init_const (&tmp_str, fl->name);
  1.1444 +                
  1.1445 +                if (_dbus_string_ends_with_c_str (&tmp_str,
  1.1446 +                                                  _dbus_string_get_const_data (&f)))
  1.1447 +                  in_our_file = TRUE;
  1.1448 +                else
  1.1449 +                  in_our_file = FALSE;
  1.1450 +                
  1.1451 +#if 0
  1.1452 +                fprintf (stderr,
  1.1453 +                         "File %s in .bb, looking for %s, in_our_file = %d\n",
  1.1454 +                         _dbus_string_get_const_data (&f),
  1.1455 +                         fl->name,
  1.1456 +                         in_our_file);
  1.1457 +#endif
  1.1458 +              }
  1.1459 +            _dbus_string_free (&f);
  1.1460 +          }
  1.1461 +          break;
  1.1462 +        case BB_FUNCTION:
  1.1463 +          {
  1.1464 +            DBusString f;
  1.1465 +            if (!_dbus_string_init (&f))
  1.1466 +              die ("no memory\n");
  1.1467 +
  1.1468 +            if (string_get_string (contents, i,
  1.1469 +                                   BB_FUNCTION,
  1.1470 +                                   &f, &i))
  1.1471 +              {
  1.1472 +#if 0
  1.1473 +                fprintf (stderr, "Function %s\n", _dbus_string_get_const_data (&f));
  1.1474 +#endif
  1.1475 +
  1.1476 +                block = 0;
  1.1477 +                
  1.1478 +                if (in_our_file)
  1.1479 +                  {
  1.1480 +                    if (link == NULL)
  1.1481 +                      {
  1.1482 +                        fprintf (stderr, "No function object for function %s\n",
  1.1483 +                                 _dbus_string_get_const_data (&f));
  1.1484 +                      }
  1.1485 +                    else
  1.1486 +                      {
  1.1487 +                        func = link->data;
  1.1488 +                        link = _dbus_list_get_next_link (&fl->functions, link);
  1.1489 +
  1.1490 +                        if (func->name == NULL)
  1.1491 +                          {
  1.1492 +                            if (!_dbus_string_copy_data (&f, &func->name))
  1.1493 +                              die ("no memory\n");
  1.1494 +                          }
  1.1495 +                        else
  1.1496 +                          {
  1.1497 +                            if (!_dbus_string_equal_c_str (&f, func->name))
  1.1498 +                              {
  1.1499 +                                fprintf (stderr, "got function name \"%s\" (%d) from .bbg file, but \"%s\" (%d) from .bb file\n",
  1.1500 +                                         func->name, strlen (func->name),
  1.1501 +                                         _dbus_string_get_const_data (&f),
  1.1502 +                                         _dbus_string_get_length (&f));
  1.1503 +
  1.1504 +                              }
  1.1505 +                          }
  1.1506 +                      }
  1.1507 +                  }
  1.1508 +              }
  1.1509 +            _dbus_string_free (&f);
  1.1510 +
  1.1511 +            n_functions += 1;
  1.1512 +          }
  1.1513 +          break;
  1.1514 +        case BB_ENDOFLIST:
  1.1515 +          block += 1;
  1.1516 +          break;
  1.1517 +        default:
  1.1518 +#if 0
  1.1519 +          fprintf (stderr, "Line %ld\n", val);
  1.1520 +#endif
  1.1521 +
  1.1522 +          if (val >= fl->n_lines)
  1.1523 +            {
  1.1524 +              fprintf (stderr, "Line %ld but file only has %d lines\n",
  1.1525 +                       val, fl->n_lines);
  1.1526 +            }
  1.1527 +          else if (func != NULL)
  1.1528 +            {
  1.1529 +              val -= 1; /* To convert the 1-based line number to 0-based */
  1.1530 +              _dbus_assert (val >= 0);
  1.1531 +              
  1.1532 +              if (block < func->n_blocks)
  1.1533 +                {
  1.1534 +                  if (!_dbus_list_append (&func->block_graph[block].lines,
  1.1535 +                                          &fl->lines[val]))
  1.1536 +                    die ("no memory\n");
  1.1537 +                  
  1.1538 +                  
  1.1539 +                  if (!_dbus_list_append (&fl->lines[val].blocks,
  1.1540 +                                          &func->block_graph[block]))
  1.1541 +                    die ("no memory\n");
  1.1542 +                }
  1.1543 +              else
  1.1544 +                {
  1.1545 +                  fprintf (stderr, "Line number for block %d but function only has %d blocks\n",
  1.1546 +                           block, func->n_blocks);
  1.1547 +                }
  1.1548 +            }
  1.1549 +          else
  1.1550 +            {
  1.1551 +              fprintf (stderr, "Line %ld given outside of any function\n",
  1.1552 +                       val);
  1.1553 +            }
  1.1554 +          
  1.1555 +          break;
  1.1556 +        }
  1.1557 +    }
  1.1558 +
  1.1559 +#if 0
  1.1560 +  printf ("%d functions in file\n", n_functions);
  1.1561 +#endif
  1.1562 +}
  1.1563 +
  1.1564 +
  1.1565 +static void
  1.1566 +load_block_line_associations (const DBusString *filename,
  1.1567 +                              File             *f)
  1.1568 +{
  1.1569 +  DBusString bb_filename;
  1.1570 +  DBusString contents;
  1.1571 +  DBusError error;
  1.1572 +
  1.1573 +  dbus_error_init (&error);
  1.1574 +  
  1.1575 +  if (!_dbus_string_init (&bb_filename) ||
  1.1576 +      !_dbus_string_copy (filename, 0, &bb_filename, 0) ||
  1.1577 +      !_dbus_string_init (&contents))
  1.1578 +    die ("no memory\n");
  1.1579 +
  1.1580 +  _dbus_string_shorten (&bb_filename, 2);
  1.1581 +
  1.1582 +  if (!_dbus_string_append (&bb_filename, ".bb"))
  1.1583 +    die ("no memory\n");
  1.1584 +      
  1.1585 +  if (!_dbus_file_get_contents (&contents, &bb_filename,
  1.1586 +                                &error))
  1.1587 +    {
  1.1588 +      fprintf (stderr, "Could not open file: %s\n",
  1.1589 +               error.message);
  1.1590 +      exit (1);
  1.1591 +    }
  1.1592 +  
  1.1593 +  get_lines_from_bb_file (&contents, f);
  1.1594 +
  1.1595 +  _dbus_string_free (&contents);
  1.1596 +  _dbus_string_free (&bb_filename);
  1.1597 +}
  1.1598 +
  1.1599 +static int
  1.1600 +count_lines_in_string (const DBusString *str)
  1.1601 +{
  1.1602 +  int n_lines;
  1.1603 +  const char *p;
  1.1604 +  const char *prev;
  1.1605 +  const char *end;
  1.1606 +  const char *last_line_end;
  1.1607 +
  1.1608 +#if 0
  1.1609 +  printf ("Counting lines in source file\n");
  1.1610 +#endif
  1.1611 +  
  1.1612 +  n_lines = 0;  
  1.1613 +  prev = NULL;
  1.1614 +  p = _dbus_string_get_const_data (str);
  1.1615 +  end = p + _dbus_string_get_length (str);
  1.1616 +  last_line_end = p;
  1.1617 +  while (p != end)
  1.1618 +    {
  1.1619 +      /* too lazy to handle \r\n as one linebreak */
  1.1620 +      if (*p == '\n' || *p == '\r')
  1.1621 +        {
  1.1622 +          ++n_lines;
  1.1623 +          last_line_end = p + 1;
  1.1624 +        }
  1.1625 +
  1.1626 +      prev = p;
  1.1627 +      ++p;
  1.1628 +    }
  1.1629 +
  1.1630 +  if (last_line_end != p)
  1.1631 +    ++n_lines;
  1.1632 +  
  1.1633 +  return n_lines;
  1.1634 +}
  1.1635 +
  1.1636 +static void
  1.1637 +fill_line_content (const DBusString *str,
  1.1638 +                   Line             *lines)
  1.1639 +{
  1.1640 +  int n_lines;
  1.1641 +  const char *p;
  1.1642 +  const char *prev;
  1.1643 +  const char *end;
  1.1644 +  const char *last_line_end;
  1.1645 +
  1.1646 +#if 0
  1.1647 +  printf ("Saving contents of each line in source file\n");
  1.1648 +#endif
  1.1649 +  
  1.1650 +  n_lines = 0;
  1.1651 +  prev = NULL;
  1.1652 +  p = _dbus_string_get_const_data (str);
  1.1653 +  end = p + _dbus_string_get_length (str);
  1.1654 +  last_line_end = p;
  1.1655 +  while (p != end)
  1.1656 +    {
  1.1657 +      if (*p == '\n' || *p == '\r')
  1.1658 +        {
  1.1659 +          lines[n_lines].text = dbus_malloc0 (p - last_line_end + 1);
  1.1660 +          if (lines[n_lines].text == NULL)
  1.1661 +            die ("no memory\n");
  1.1662 +
  1.1663 +          memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
  1.1664 +          lines[n_lines].number = n_lines + 1;
  1.1665 +          
  1.1666 +          ++n_lines;
  1.1667 +
  1.1668 +          last_line_end = p + 1;
  1.1669 +        }
  1.1670 +
  1.1671 +      prev = p;
  1.1672 +      ++p;
  1.1673 +    }
  1.1674 +
  1.1675 +  if (p != last_line_end)
  1.1676 +    {
  1.1677 +      memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
  1.1678 +      ++n_lines;
  1.1679 +    }
  1.1680 +}
  1.1681 +
  1.1682 +static void
  1.1683 +mark_inside_dbus_build_tests (File  *f)
  1.1684 +{
  1.1685 +  int i;
  1.1686 +  DBusList *link;
  1.1687 +  int inside_depth;
  1.1688 +
  1.1689 +  inside_depth = 0;
  1.1690 +  i = 0;
  1.1691 +  while (i < f->n_lines)
  1.1692 +    {
  1.1693 +      Line *l = &f->lines[i];
  1.1694 +      dbus_bool_t is_verbose;
  1.1695 +
  1.1696 +      is_verbose = strstr (l->text, "_dbus_verbose") != NULL;
  1.1697 +
  1.1698 +      if (inside_depth == 0)
  1.1699 +        {
  1.1700 +          const char *a, *b;
  1.1701 +          
  1.1702 +          a = strstr (l->text, "#if");
  1.1703 +          b = strstr (l->text, "DBUS_BUILD_TESTS");
  1.1704 +          if (a && b && (a < b))
  1.1705 +            inside_depth += 1;
  1.1706 +        }
  1.1707 +      else
  1.1708 +        {
  1.1709 +          if (strstr (l->text, "#if") != NULL)
  1.1710 +            inside_depth += 1;
  1.1711 +          else if (strstr (l->text, "#endif") != NULL)
  1.1712 +            inside_depth -= 1;
  1.1713 +        }
  1.1714 +
  1.1715 +      if (inside_depth > 0 || is_verbose)
  1.1716 +        {
  1.1717 +          /* Mark the line and its blocks */
  1.1718 +          DBusList *blink;
  1.1719 +
  1.1720 +          l->inside_dbus_build_tests = TRUE;
  1.1721 +          
  1.1722 +          blink = _dbus_list_get_first_link (&l->blocks);
  1.1723 +          while (blink != NULL)
  1.1724 +            {
  1.1725 +              Block *b = blink->data;
  1.1726 +
  1.1727 +              b->inside_dbus_build_tests = TRUE;
  1.1728 +              
  1.1729 +              blink = _dbus_list_get_next_link (&l->blocks, blink);
  1.1730 +            }
  1.1731 +        }
  1.1732 +      
  1.1733 +      ++i;
  1.1734 +    }
  1.1735 +
  1.1736 +  /* Now mark functions where for all blocks that are associated
  1.1737 +   * with a source line, the block is inside_dbus_build_tests.
  1.1738 +   */
  1.1739 +  link = _dbus_list_get_first_link (&f->functions);
  1.1740 +  while (link != NULL)
  1.1741 +    {
  1.1742 +      Function *func = link->data;
  1.1743 +
  1.1744 +      /* The issue is that some blocks aren't associated with a source line.
  1.1745 +       * Assume they are inside/outside tests according to the source
  1.1746 +       * line of the preceding block. For the first block, make it
  1.1747 +       * match the first following block with a line associated.
  1.1748 +       */
  1.1749 +      if (func->block_graph[0].lines == NULL)
  1.1750 +        {
  1.1751 +          /* find first following line */
  1.1752 +          i = 1;
  1.1753 +          while (i < func->n_blocks)
  1.1754 +            {
  1.1755 +              if (func->block_graph[i].lines != NULL)
  1.1756 +                {
  1.1757 +                  func->block_graph[0].inside_dbus_build_tests =
  1.1758 +                    func->block_graph[i].inside_dbus_build_tests;
  1.1759 +                  break;
  1.1760 +                }
  1.1761 +              
  1.1762 +              ++i;
  1.1763 +            }
  1.1764 +        }
  1.1765 +
  1.1766 +      /* Now mark all blocks but the first */
  1.1767 +      i = 1;
  1.1768 +      while (i < func->n_blocks)
  1.1769 +        {
  1.1770 +          if (func->block_graph[i].lines == NULL)
  1.1771 +            {
  1.1772 +              func->block_graph[i].inside_dbus_build_tests =
  1.1773 +                func->block_graph[i-1].inside_dbus_build_tests;
  1.1774 +            }
  1.1775 +          
  1.1776 +          ++i;
  1.1777 +        }
  1.1778 +      
  1.1779 +      i = 0;
  1.1780 +      while (i < func->n_blocks)
  1.1781 +        {
  1.1782 +          /* Break as soon as any block is not a test block */
  1.1783 +          if (func->block_graph[i].lines != NULL &&
  1.1784 +              !func->block_graph[i].inside_dbus_build_tests)
  1.1785 +            break;
  1.1786 +          
  1.1787 +          ++i;
  1.1788 +        }
  1.1789 +
  1.1790 +      if (i == func->n_blocks)
  1.1791 +        func->inside_dbus_build_tests = TRUE;
  1.1792 +      
  1.1793 +      link = _dbus_list_get_next_link (&f->functions, link);
  1.1794 +    } 
  1.1795 +}
  1.1796 +
  1.1797 +static void
  1.1798 +mark_coverage (File  *f)
  1.1799 +{
  1.1800 +  int i;
  1.1801 +  DBusList *link;
  1.1802 +  
  1.1803 +  i = 0;
  1.1804 +  while (i < f->n_lines)
  1.1805 +    {
  1.1806 +      Line *l = &f->lines[i];
  1.1807 +      DBusList *blink;
  1.1808 +      int n_blocks;
  1.1809 +      int n_blocks_executed;
  1.1810 +
  1.1811 +      n_blocks = 0;
  1.1812 +      n_blocks_executed = 0;
  1.1813 +      blink = _dbus_list_get_first_link (&l->blocks);
  1.1814 +      while (blink != NULL)
  1.1815 +        {
  1.1816 +          Block *b = blink->data;
  1.1817 +          
  1.1818 +          if (b->exec_count > 0)
  1.1819 +            n_blocks_executed += 1;
  1.1820 +
  1.1821 +          n_blocks += 1;
  1.1822 +          
  1.1823 +          blink = _dbus_list_get_next_link (&l->blocks, blink);
  1.1824 +        }
  1.1825 +
  1.1826 +      if (n_blocks_executed > 0 &&
  1.1827 +          n_blocks_executed < n_blocks)
  1.1828 +        l->partial = TRUE;
  1.1829 +
  1.1830 +      ++i;
  1.1831 +    }
  1.1832 +
  1.1833 +  link = _dbus_list_get_first_link (&f->functions);
  1.1834 +  while (link != NULL)
  1.1835 +    {
  1.1836 +      Function *func = link->data;
  1.1837 +      int i;
  1.1838 +      int n_test_blocks;
  1.1839 +      int n_test_blocks_executed;
  1.1840 +      int n_nontest_blocks;
  1.1841 +      int n_nontest_blocks_executed;
  1.1842 +      
  1.1843 +      n_test_blocks = 0;
  1.1844 +      n_test_blocks_executed = 0;
  1.1845 +      n_nontest_blocks = 0;
  1.1846 +      n_nontest_blocks_executed = 0;      
  1.1847 +
  1.1848 +      i = 0;
  1.1849 +      while (i < func->n_blocks)
  1.1850 +        {
  1.1851 +          if (!func->block_graph[i].inside_dbus_build_tests)
  1.1852 +            {
  1.1853 +              n_nontest_blocks += 1;
  1.1854 +
  1.1855 +              if (func->block_graph[i].exec_count > 0)
  1.1856 +                n_nontest_blocks_executed += 1;
  1.1857 +            }
  1.1858 +          else
  1.1859 +            {
  1.1860 +              n_test_blocks += 1;
  1.1861 +
  1.1862 +              if (func->block_graph[i].exec_count > 0)
  1.1863 +                n_test_blocks_executed += 1;
  1.1864 +            }
  1.1865 +
  1.1866 +          ++i;
  1.1867 +        }
  1.1868 +      
  1.1869 +      if (n_nontest_blocks_executed > 0 &&
  1.1870 +          n_nontest_blocks_executed < n_nontest_blocks)
  1.1871 +        func->partial = TRUE;
  1.1872 +
  1.1873 +      if (n_nontest_blocks_executed == 0 &&
  1.1874 +          n_nontest_blocks > 0)
  1.1875 +        func->unused = TRUE;
  1.1876 +      
  1.1877 +      func->n_test_blocks = n_test_blocks;
  1.1878 +      func->n_test_blocks_executed = n_test_blocks_executed;
  1.1879 +      func->n_nontest_blocks = n_nontest_blocks;
  1.1880 +      func->n_nontest_blocks_executed = n_nontest_blocks_executed;
  1.1881 +      
  1.1882 +      link = _dbus_list_get_next_link (&f->functions, link);
  1.1883 +    }
  1.1884 +}
  1.1885 +
  1.1886 +static File*
  1.1887 +load_c_file (const DBusString *filename)
  1.1888 +{
  1.1889 +  DBusString contents;
  1.1890 +  DBusError error;
  1.1891 +  File *f;
  1.1892 +  
  1.1893 +  f = dbus_new0 (File, 1);
  1.1894 +  if (f == NULL)
  1.1895 +    die ("no memory\n");
  1.1896 +
  1.1897 +  if (!_dbus_string_copy_data (filename, &f->name))
  1.1898 +    die ("no memory\n");
  1.1899 +  
  1.1900 +  if (!_dbus_string_init (&contents))
  1.1901 +    die ("no memory\n");
  1.1902 +      
  1.1903 +  dbus_error_init (&error);
  1.1904 +
  1.1905 +  if (!_dbus_file_get_contents (&contents, filename,
  1.1906 +                                &error))
  1.1907 +    {
  1.1908 +      fprintf (stderr, "Could not open file: %s\n",
  1.1909 +               error.message);
  1.1910 +      dbus_error_free (&error);
  1.1911 +      exit (1);
  1.1912 +    }
  1.1913 +      
  1.1914 +  load_functions_for_c_file (filename, &f->functions);
  1.1915 +
  1.1916 +  f->n_lines = count_lines_in_string (&contents);
  1.1917 +  f->lines = dbus_new0 (Line, f->n_lines);
  1.1918 +  if (f->lines == NULL)
  1.1919 +    die ("no memory\n");
  1.1920 +
  1.1921 +  fill_line_content (&contents, f->lines);
  1.1922 +  
  1.1923 +  _dbus_string_free (&contents);
  1.1924 +
  1.1925 +  load_block_line_associations (filename, f);
  1.1926 +
  1.1927 +  mark_inside_dbus_build_tests (f);
  1.1928 +  mark_coverage (f);
  1.1929 +  
  1.1930 +  return f;
  1.1931 +}
  1.1932 +
  1.1933 +typedef struct Stats Stats;
  1.1934 +
  1.1935 +struct Stats
  1.1936 +{
  1.1937 +  int n_blocks;
  1.1938 +  int n_blocks_executed;
  1.1939 +  int n_blocks_inside_dbus_build_tests;
  1.1940 +  
  1.1941 +  int n_lines; /* lines that have blocks on them */
  1.1942 +  int n_lines_executed;
  1.1943 +  int n_lines_partial;
  1.1944 +  int n_lines_inside_dbus_build_tests;
  1.1945 +  
  1.1946 +  int n_functions;
  1.1947 +  int n_functions_executed;
  1.1948 +  int n_functions_partial;
  1.1949 +  int n_functions_inside_dbus_build_tests;
  1.1950 +};
  1.1951 +
  1.1952 +static dbus_bool_t
  1.1953 +line_was_executed (Line *l)
  1.1954 +{
  1.1955 +  DBusList *link;
  1.1956 +
  1.1957 +  link = _dbus_list_get_first_link (&l->blocks);
  1.1958 +  while (link != NULL)
  1.1959 +    {
  1.1960 +      Block *b = link->data;
  1.1961 +
  1.1962 +      if (b->exec_count > 0)
  1.1963 +        return TRUE;
  1.1964 +      
  1.1965 +      link = _dbus_list_get_next_link (&l->blocks, link);
  1.1966 +    }
  1.1967 +
  1.1968 +  return FALSE;
  1.1969 +}
  1.1970 +
  1.1971 +
  1.1972 +static int
  1.1973 +line_exec_count (Line *l)
  1.1974 +{
  1.1975 +  DBusList *link;
  1.1976 +  dbus_int64_t total;
  1.1977 +
  1.1978 +  total = 0;
  1.1979 +  link = _dbus_list_get_first_link (&l->blocks);
  1.1980 +  while (link != NULL)
  1.1981 +    {
  1.1982 +      Block *b = link->data;
  1.1983 +
  1.1984 +      total += b->exec_count;
  1.1985 +      
  1.1986 +      link = _dbus_list_get_next_link (&l->blocks, link);
  1.1987 +    }
  1.1988 +
  1.1989 +  return total;
  1.1990 +}
  1.1991 +
  1.1992 +static void
  1.1993 +merge_stats_for_file (Stats *stats,
  1.1994 +                      File  *f)
  1.1995 +{
  1.1996 +  int i;
  1.1997 +  DBusList *link;
  1.1998 +  
  1.1999 +  for (i = 0; i < f->n_lines; ++i)
  1.2000 +    {
  1.2001 +      Line *l = &f->lines[i];
  1.2002 +      
  1.2003 +      if (l->inside_dbus_build_tests)
  1.2004 +        {
  1.2005 +          stats->n_lines_inside_dbus_build_tests += 1;
  1.2006 +          continue;
  1.2007 +        }
  1.2008 +      
  1.2009 +      if (line_was_executed (l))
  1.2010 +        stats->n_lines_executed += 1;
  1.2011 +
  1.2012 +      if (l->blocks != NULL)
  1.2013 +        stats->n_lines += 1;
  1.2014 +
  1.2015 +      if (l->partial)
  1.2016 +        stats->n_lines_partial += 1;
  1.2017 +    }
  1.2018 +
  1.2019 +  link = _dbus_list_get_first_link (&f->functions);
  1.2020 +  while (link != NULL)
  1.2021 +    {
  1.2022 +      Function *func = link->data;
  1.2023 +
  1.2024 +      if (func->inside_dbus_build_tests)
  1.2025 +        stats->n_functions_inside_dbus_build_tests += 1;
  1.2026 +      else
  1.2027 +        {
  1.2028 +          stats->n_functions += 1;
  1.2029 +
  1.2030 +          if (!func->unused)
  1.2031 +            stats->n_functions_executed += 1;
  1.2032 +          
  1.2033 +          if (func->partial)
  1.2034 +            stats->n_functions_partial += 1;
  1.2035 +        }
  1.2036 +
  1.2037 +      stats->n_blocks_inside_dbus_build_tests +=
  1.2038 +        func->n_test_blocks;
  1.2039 +      
  1.2040 +      stats->n_blocks_executed +=
  1.2041 +        func->n_nontest_blocks_executed;
  1.2042 +      
  1.2043 +      stats->n_blocks +=
  1.2044 +        func->n_nontest_blocks;
  1.2045 +
  1.2046 +      link = _dbus_list_get_next_link (&f->functions, link);
  1.2047 +    }
  1.2048 +}
  1.2049 +
  1.2050 +/* The output of this matches gcov exactly ("diff" shows no difference) */
  1.2051 +static void
  1.2052 +print_annotated_source_gcov_format (File *f)
  1.2053 +{
  1.2054 +  int i;
  1.2055 +  
  1.2056 +  i = 0;
  1.2057 +  while (i < f->n_lines)
  1.2058 +    {
  1.2059 +      Line *l = &f->lines[i];
  1.2060 +
  1.2061 +      if (l->blocks != NULL)
  1.2062 +        {
  1.2063 +          int exec_count;
  1.2064 +          
  1.2065 +          exec_count = line_exec_count (l);
  1.2066 +          
  1.2067 +          if (exec_count > 0)
  1.2068 +            printf ("%12d    %s\n",
  1.2069 +                    exec_count, l->text);
  1.2070 +          else
  1.2071 +            printf ("      ######    %s\n", l->text);
  1.2072 +        }
  1.2073 +      else
  1.2074 +        {
  1.2075 +          printf ("\t\t%s\n", l->text);
  1.2076 +        }
  1.2077 +          
  1.2078 +      ++i;
  1.2079 +    }
  1.2080 +}
  1.2081 +
  1.2082 +static void
  1.2083 +print_annotated_source (File *f)
  1.2084 +{
  1.2085 +  int i;
  1.2086 +  
  1.2087 +  i = 0;
  1.2088 +  while (i < f->n_lines)
  1.2089 +    {
  1.2090 +      Line *l = &f->lines[i];
  1.2091 +
  1.2092 +      if (l->inside_dbus_build_tests)
  1.2093 +        printf ("*");
  1.2094 +      else
  1.2095 +        printf (" ");
  1.2096 +      
  1.2097 +      if (l->blocks != NULL)
  1.2098 +        {
  1.2099 +          int exec_count;
  1.2100 +          
  1.2101 +          exec_count = line_exec_count (l);
  1.2102 +          
  1.2103 +          if (exec_count > 0)
  1.2104 +            printf ("%12d    %s\n",
  1.2105 +                    exec_count, l->text);
  1.2106 +          else
  1.2107 +            printf ("      ######    %s\n", l->text);
  1.2108 +        }
  1.2109 +      else
  1.2110 +        {
  1.2111 +          printf ("\t\t%s\n", l->text);
  1.2112 +        }
  1.2113 +          
  1.2114 +      ++i;
  1.2115 +    }
  1.2116 +}
  1.2117 +
  1.2118 +static void
  1.2119 +print_block_superdetails (File *f)
  1.2120 +{
  1.2121 +  DBusList *link;
  1.2122 +  int i;
  1.2123 +  
  1.2124 +  link = _dbus_list_get_first_link (&f->functions);
  1.2125 +  while (link != NULL)
  1.2126 +    {
  1.2127 +      Function *func = link->data;
  1.2128 +
  1.2129 +      printf ("=== %s():\n", func->name);
  1.2130 +
  1.2131 +      i = 0;
  1.2132 +      while (i < func->n_blocks)
  1.2133 +        {
  1.2134 +          Block *b = &func->block_graph[i];
  1.2135 +          DBusList *l;
  1.2136 +          
  1.2137 +          printf ("  %5d executed %d times%s\n", i,
  1.2138 +                  (int) b->exec_count,
  1.2139 +                  b->inside_dbus_build_tests ?
  1.2140 +                  " [inside DBUS_BUILD_TESTS]" : "");
  1.2141 +                  
  1.2142 +          l = _dbus_list_get_first_link (&b->lines);
  1.2143 +          while (l != NULL)
  1.2144 +            {
  1.2145 +              Line *line = l->data;
  1.2146 +
  1.2147 +              printf ("4%d\t%s\n", line->number, line->text);
  1.2148 +
  1.2149 +              l = _dbus_list_get_next_link (&b->lines, l);
  1.2150 +            }
  1.2151 +          
  1.2152 +          ++i;
  1.2153 +        }
  1.2154 +      
  1.2155 +      link = _dbus_list_get_next_link (&f->functions, link);
  1.2156 +    }
  1.2157 +}
  1.2158 +
  1.2159 +static void
  1.2160 +print_one_file (const DBusString *filename)
  1.2161 +{
  1.2162 +  if (_dbus_string_ends_with_c_str (filename, ".bb"))
  1.2163 +    {
  1.2164 +      DBusString contents;
  1.2165 +      DBusError error;
  1.2166 +      
  1.2167 +      if (!_dbus_string_init (&contents))
  1.2168 +        die ("no memory\n");
  1.2169 +      
  1.2170 +      dbus_error_init (&error);
  1.2171 +
  1.2172 +      if (!_dbus_file_get_contents (&contents, filename,
  1.2173 +                                    &error))
  1.2174 +        {
  1.2175 +          fprintf (stderr, "Could not open file: %s\n",
  1.2176 +                   error.message);
  1.2177 +          dbus_error_free (&error);
  1.2178 +          exit (1);
  1.2179 +        }
  1.2180 +      
  1.2181 +      dump_bb_file (&contents);
  1.2182 +
  1.2183 +      _dbus_string_free (&contents);
  1.2184 +    }
  1.2185 +  else if (_dbus_string_ends_with_c_str (filename, ".bbg"))
  1.2186 +    {
  1.2187 +      DBusString contents;
  1.2188 +      DBusError error;
  1.2189 +      
  1.2190 +      if (!_dbus_string_init (&contents))
  1.2191 +        die ("no memory\n");
  1.2192 +      
  1.2193 +      dbus_error_init (&error);
  1.2194 +
  1.2195 +      if (!_dbus_file_get_contents (&contents, filename,
  1.2196 +                                    &error))
  1.2197 +        {
  1.2198 +          fprintf (stderr, "Could not open file: %s\n",
  1.2199 +                   error.message);
  1.2200 +          dbus_error_free (&error);
  1.2201 +          exit (1);
  1.2202 +        }
  1.2203 +      
  1.2204 +      dump_bbg_file (&contents);
  1.2205 +
  1.2206 +      _dbus_string_free (&contents);
  1.2207 +    }
  1.2208 +  else if (_dbus_string_ends_with_c_str (filename, ".da"))
  1.2209 +    {
  1.2210 +      DBusString contents;
  1.2211 +      DBusError error;
  1.2212 +      
  1.2213 +      if (!_dbus_string_init (&contents))
  1.2214 +        die ("no memory\n");
  1.2215 +      
  1.2216 +      dbus_error_init (&error);
  1.2217 +
  1.2218 +      if (!_dbus_file_get_contents (&contents, filename,
  1.2219 +                                    &error))
  1.2220 +        {
  1.2221 +          fprintf (stderr, "Could not open file: %s\n",
  1.2222 +                   error.message);
  1.2223 +          dbus_error_free (&error);
  1.2224 +          exit (1);
  1.2225 +        }
  1.2226 +      
  1.2227 +      dump_da_file (&contents);
  1.2228 +
  1.2229 +      _dbus_string_free (&contents);
  1.2230 +    }
  1.2231 +  else if (_dbus_string_ends_with_c_str (filename, ".c"))
  1.2232 +    {
  1.2233 +      File *f;
  1.2234 +      
  1.2235 +      f = load_c_file (filename);
  1.2236 +
  1.2237 +      print_annotated_source (f);
  1.2238 +    }
  1.2239 +  else
  1.2240 +    {
  1.2241 +      fprintf (stderr, "Unknown file type %s\n",
  1.2242 +               _dbus_string_get_const_data (filename));
  1.2243 +      exit (1);
  1.2244 +    }
  1.2245 +}
  1.2246 +
  1.2247 +static void
  1.2248 +print_untested_functions (File *f)
  1.2249 +{
  1.2250 +  DBusList *link;
  1.2251 +  dbus_bool_t found;
  1.2252 +
  1.2253 +  found = FALSE;
  1.2254 +  link = _dbus_list_get_first_link (&f->functions);
  1.2255 +  while (link != NULL)
  1.2256 +    {
  1.2257 +      Function *func = link->data;
  1.2258 +
  1.2259 +      if (func->unused &&
  1.2260 +          !func->inside_dbus_build_tests)
  1.2261 +        found = TRUE;
  1.2262 +      
  1.2263 +      link = _dbus_list_get_next_link (&f->functions, link);
  1.2264 +    }
  1.2265 +
  1.2266 +  if (!found)
  1.2267 +    return;
  1.2268 +  
  1.2269 +  printf ("Untested functions in %s\n", f->name);
  1.2270 +  printf ("=======\n");
  1.2271 +  
  1.2272 +  link = _dbus_list_get_first_link (&f->functions);
  1.2273 +  while (link != NULL)
  1.2274 +    {
  1.2275 +      Function *func = link->data;
  1.2276 +
  1.2277 +      if (func->unused &&
  1.2278 +          !func->inside_dbus_build_tests)
  1.2279 +        printf ("  %s\n", func->name);
  1.2280 +      
  1.2281 +      link = _dbus_list_get_next_link (&f->functions, link);
  1.2282 +    }
  1.2283 +
  1.2284 +  printf ("\n");
  1.2285 +}
  1.2286 +
  1.2287 +static void
  1.2288 +print_poorly_tested_functions (File  *f,
  1.2289 +                               Stats *stats)
  1.2290 +{
  1.2291 +  DBusList *link;
  1.2292 +  dbus_bool_t found;
  1.2293 +
  1.2294 +#define TEST_FRACTION(function) ((function)->n_nontest_blocks_executed / (double) (function)->n_nontest_blocks)
  1.2295 +
  1.2296 +#define AVERAGE_COVERAGE ((stats)->n_blocks_executed / (double) (stats)->n_blocks)
  1.2297 +  
  1.2298 +#define POORLY_TESTED(function) (!(function)->unused &&                 \
  1.2299 +                                 (function)->n_nontest_blocks > 0 &&    \
  1.2300 +                                 TEST_FRACTION (function) < AVERAGE_COVERAGE)
  1.2301 +  
  1.2302 +  found = FALSE;
  1.2303 +  link = _dbus_list_get_first_link (&f->functions);
  1.2304 +  while (link != NULL)
  1.2305 +    {
  1.2306 +      Function *func = link->data;
  1.2307 +
  1.2308 +      if (POORLY_TESTED (func))
  1.2309 +        found = TRUE;
  1.2310 +      
  1.2311 +      link = _dbus_list_get_next_link (&f->functions, link);
  1.2312 +    }
  1.2313 +
  1.2314 +  if (!found)
  1.2315 +    return;
  1.2316 +
  1.2317 +  printf ("Below average functions in %s\n", f->name);
  1.2318 +  printf ("=======\n");
  1.2319 +  
  1.2320 +  link = _dbus_list_get_first_link (&f->functions);
  1.2321 +  while (link != NULL)
  1.2322 +    {
  1.2323 +      Function *func = link->data;
  1.2324 +
  1.2325 +      if (POORLY_TESTED (func))
  1.2326 +        printf ("  %s (%d%%)\n", func->name,
  1.2327 +                (int) (TEST_FRACTION (func) * 100));
  1.2328 +      
  1.2329 +      link = _dbus_list_get_next_link (&f->functions, link);
  1.2330 +    }
  1.2331 +
  1.2332 +  printf ("\n");
  1.2333 +}
  1.2334 +
  1.2335 +static int
  1.2336 +func_cmp (const void *a,
  1.2337 +          const void *b)
  1.2338 +{
  1.2339 +  Function *af = *(Function**) a;
  1.2340 +  Function *bf = *(Function**) b;
  1.2341 +  int a_untested = af->n_nontest_blocks - af->n_nontest_blocks_executed;
  1.2342 +  int b_untested = bf->n_nontest_blocks - bf->n_nontest_blocks_executed;
  1.2343 +  
  1.2344 +  /* Sort by number of untested blocks */
  1.2345 +  return b_untested - a_untested;
  1.2346 +}
  1.2347 +
  1.2348 +static void
  1.2349 +print_n_untested_blocks_by_function (File  *f,
  1.2350 +                                     Stats *stats)
  1.2351 +{
  1.2352 +  DBusList *link;
  1.2353 +  Function **funcs;
  1.2354 +  int n_found;
  1.2355 +  int i;
  1.2356 +  
  1.2357 +  n_found = 0;
  1.2358 +  link = _dbus_list_get_first_link (&f->functions);
  1.2359 +  while (link != NULL)
  1.2360 +    {
  1.2361 +      Function *func = link->data;
  1.2362 +
  1.2363 +      if (func->n_nontest_blocks_executed <
  1.2364 +          func->n_nontest_blocks)
  1.2365 +        n_found += 1;
  1.2366 +      
  1.2367 +      link = _dbus_list_get_next_link (&f->functions, link);
  1.2368 +    }
  1.2369 +
  1.2370 +  if (n_found == 0)
  1.2371 +    return;
  1.2372 +
  1.2373 +  /* make an array so we can use qsort */
  1.2374 +  
  1.2375 +  funcs = dbus_new (Function*, n_found);
  1.2376 +  if (funcs == NULL)
  1.2377 +    return;
  1.2378 +  
  1.2379 +  i = 0;
  1.2380 +  link = _dbus_list_get_first_link (&f->functions);
  1.2381 +  while (link != NULL)
  1.2382 +    {
  1.2383 +      Function *func = link->data;
  1.2384 +
  1.2385 +      if (func->n_nontest_blocks_executed <
  1.2386 +          func->n_nontest_blocks)
  1.2387 +        {
  1.2388 +          funcs[i] = func;
  1.2389 +          ++i;
  1.2390 +        }
  1.2391 +
  1.2392 +      link = _dbus_list_get_next_link (&f->functions, link);
  1.2393 +    }
  1.2394 +
  1.2395 +  _dbus_assert (i == n_found);
  1.2396 +  
  1.2397 +  qsort (funcs, n_found, sizeof (Function*),
  1.2398 +         func_cmp);
  1.2399 +  
  1.2400 +  printf ("Incomplete functions in %s\n", f->name);
  1.2401 +  printf ("=======\n");
  1.2402 +
  1.2403 +  i = 0;
  1.2404 +  while (i < n_found)
  1.2405 +    {
  1.2406 +      Function *func = funcs[i];
  1.2407 +
  1.2408 +      printf ("  %s (%d/%d untested blocks)\n",
  1.2409 +              func->name,
  1.2410 +              func->n_nontest_blocks - func->n_nontest_blocks_executed,
  1.2411 +              func->n_nontest_blocks);
  1.2412 +      
  1.2413 +      ++i;
  1.2414 +    }
  1.2415 +
  1.2416 +  dbus_free (funcs);
  1.2417 +
  1.2418 +  printf ("\n");
  1.2419 +}
  1.2420 +
  1.2421 +static void
  1.2422 +print_stats (Stats      *stats,
  1.2423 +             const char *of_what)
  1.2424 +{
  1.2425 +  int completely;
  1.2426 +  
  1.2427 +  printf ("Summary (%s)\n", of_what);
  1.2428 +  printf ("=======\n");
  1.2429 +  printf ("  %g%% blocks executed (%d of %d)\n",
  1.2430 +          (stats->n_blocks_executed / (double) stats->n_blocks) * 100.0,
  1.2431 +          stats->n_blocks_executed,
  1.2432 +          stats->n_blocks);
  1.2433 +
  1.2434 +  printf ("     (ignored %d blocks of test-only/debug-only code)\n",
  1.2435 +          stats->n_blocks_inside_dbus_build_tests);
  1.2436 +      
  1.2437 +  printf ("  %g%% functions executed (%d of %d)\n",
  1.2438 +          (stats->n_functions_executed / (double) stats->n_functions) * 100.0,
  1.2439 +          stats->n_functions_executed,
  1.2440 +          stats->n_functions);
  1.2441 +
  1.2442 +  completely = stats->n_functions_executed - stats->n_functions_partial;
  1.2443 +  printf ("  %g%% functions completely executed (%d of %d)\n",
  1.2444 +          (completely / (double) stats->n_functions) * 100.0,
  1.2445 +          completely,
  1.2446 +          stats->n_functions);
  1.2447 +
  1.2448 +  printf ("     (ignored %d functions of test-only/debug-only code)\n",
  1.2449 +          stats->n_functions_inside_dbus_build_tests);
  1.2450 +      
  1.2451 +  printf ("  %g%% lines executed (%d of %d)\n",
  1.2452 +          (stats->n_lines_executed / (double) stats->n_lines) * 100.0,
  1.2453 +          stats->n_lines_executed,
  1.2454 +          stats->n_lines);
  1.2455 +
  1.2456 +  completely = stats->n_lines_executed - stats->n_lines_partial;
  1.2457 +  printf ("  %g%% lines completely executed (%d of %d)\n",
  1.2458 +          (completely / (double) stats->n_lines) * 100.0,
  1.2459 +          completely,
  1.2460 +          stats->n_lines);
  1.2461 +
  1.2462 +  printf ("     (ignored %d lines of test-only/debug-only code)\n",
  1.2463 +          stats->n_lines_inside_dbus_build_tests);
  1.2464 +
  1.2465 +  printf ("\n");
  1.2466 +}
  1.2467 +
  1.2468 +typedef enum
  1.2469 +{
  1.2470 +  MODE_PRINT,
  1.2471 +  MODE_REPORT,
  1.2472 +  MODE_BLOCKS,
  1.2473 +  MODE_GCOV
  1.2474 +} Mode;
  1.2475 +
  1.2476 +int
  1.2477 +main (int argc, char **argv)
  1.2478 +{
  1.2479 +  DBusString filename;
  1.2480 +  int i;
  1.2481 +  Mode m;
  1.2482 +  
  1.2483 +  if (argc < 2)
  1.2484 +    {
  1.2485 +      fprintf (stderr, "Must specify files on command line\n");
  1.2486 +      return 1;
  1.2487 +    }
  1.2488 +
  1.2489 +  m = MODE_PRINT;
  1.2490 +  i = 1;
  1.2491 +
  1.2492 +  if (strcmp (argv[i], "--report") == 0)
  1.2493 +    {
  1.2494 +      m = MODE_REPORT;
  1.2495 +      ++i;
  1.2496 +    }
  1.2497 +  else if (strcmp (argv[i], "--blocks") == 0)
  1.2498 +    {
  1.2499 +      m = MODE_BLOCKS;
  1.2500 +      ++i;
  1.2501 +    }
  1.2502 +  else if (strcmp (argv[i], "--gcov") == 0)
  1.2503 +    {
  1.2504 +      m = MODE_GCOV;
  1.2505 +      ++i;
  1.2506 +    }
  1.2507 +
  1.2508 +  
  1.2509 +  if (i == argc)
  1.2510 +    {
  1.2511 +      fprintf (stderr, "Must specify files on command line\n");
  1.2512 +      return 1;
  1.2513 +    }
  1.2514 +
  1.2515 +  if (m == MODE_PRINT)
  1.2516 +    {
  1.2517 +      while (i < argc)
  1.2518 +        {
  1.2519 +          _dbus_string_init_const (&filename, argv[i]);
  1.2520 +          
  1.2521 +          print_one_file (&filename);
  1.2522 +          
  1.2523 +          ++i;
  1.2524 +        }
  1.2525 +    }
  1.2526 +  else if (m == MODE_BLOCKS || m == MODE_GCOV)
  1.2527 +    {
  1.2528 +      while (i < argc)
  1.2529 +        {
  1.2530 +          File *f;
  1.2531 +          
  1.2532 +          _dbus_string_init_const (&filename, argv[i]);
  1.2533 +      
  1.2534 +          f = load_c_file (&filename);
  1.2535 +
  1.2536 +          if (m == MODE_BLOCKS)
  1.2537 +            print_block_superdetails (f);
  1.2538 +          else if (m == MODE_GCOV)
  1.2539 +            print_annotated_source_gcov_format (f);
  1.2540 +          
  1.2541 +          ++i;
  1.2542 +        }
  1.2543 +    }
  1.2544 +  else if (m == MODE_REPORT)
  1.2545 +    {
  1.2546 +      Stats stats = { 0, };
  1.2547 +      DBusList *files;
  1.2548 +      DBusList *link;
  1.2549 +      DBusHashTable *stats_by_dir;
  1.2550 +      DBusHashIter iter;
  1.2551 +      
  1.2552 +      files = NULL;
  1.2553 +      while (i < argc)
  1.2554 +        {
  1.2555 +          _dbus_string_init_const (&filename, argv[i]);
  1.2556 +
  1.2557 +          if (_dbus_string_ends_with_c_str (&filename, ".c"))
  1.2558 +            {
  1.2559 +              File *f;
  1.2560 +              
  1.2561 +              f = load_c_file (&filename);
  1.2562 +              
  1.2563 +              if (!_dbus_list_append (&files, f))
  1.2564 +                die ("no memory\n");
  1.2565 +            }
  1.2566 +          else
  1.2567 +            {
  1.2568 +              fprintf (stderr, "Unknown file type %s\n",
  1.2569 +                       _dbus_string_get_const_data (&filename));
  1.2570 +              exit (1);
  1.2571 +            }
  1.2572 +          
  1.2573 +          ++i;
  1.2574 +        }
  1.2575 +
  1.2576 +      link = _dbus_list_get_first_link (&files);
  1.2577 +      while (link != NULL)
  1.2578 +        {
  1.2579 +          File *f = link->data;
  1.2580 +
  1.2581 +          merge_stats_for_file (&stats, f);
  1.2582 +          
  1.2583 +          link = _dbus_list_get_next_link (&files, link);
  1.2584 +        }
  1.2585 +
  1.2586 +      print_stats (&stats, "all files");
  1.2587 +
  1.2588 +      stats_by_dir = _dbus_hash_table_new (DBUS_HASH_STRING,
  1.2589 +                                           dbus_free, dbus_free);
  1.2590 +      
  1.2591 +      link = _dbus_list_get_first_link (&files);
  1.2592 +      while (link != NULL)
  1.2593 +        {
  1.2594 +          File *f = link->data;
  1.2595 +          DBusString dirname;
  1.2596 +          char *dirname_c;
  1.2597 +          Stats *dir_stats;
  1.2598 +          
  1.2599 +          _dbus_string_init_const (&filename, f->name);
  1.2600 +            
  1.2601 +          if (!_dbus_string_init (&dirname))
  1.2602 +            die ("no memory\n");
  1.2603 +
  1.2604 +          if (!_dbus_string_get_dirname (&filename, &dirname) ||
  1.2605 +              !_dbus_string_copy_data (&dirname, &dirname_c))
  1.2606 +            die ("no memory\n");
  1.2607 +
  1.2608 +          dir_stats = _dbus_hash_table_lookup_string (stats_by_dir,
  1.2609 +                                                      dirname_c);
  1.2610 +
  1.2611 +          if (dir_stats == NULL)
  1.2612 +            {
  1.2613 +              dir_stats = dbus_new0 (Stats, 1);
  1.2614 +              if (!_dbus_hash_table_insert_string (stats_by_dir, dirname_c,
  1.2615 +                                                   dir_stats))
  1.2616 +                die ("no memory\n");
  1.2617 +            }
  1.2618 +          else
  1.2619 +            dbus_free (dirname_c);
  1.2620 +          
  1.2621 +          merge_stats_for_file (dir_stats, f);
  1.2622 +          
  1.2623 +          link = _dbus_list_get_next_link (&files, link);
  1.2624 +        }
  1.2625 +
  1.2626 +      _dbus_hash_iter_init (stats_by_dir, &iter);
  1.2627 +      while (_dbus_hash_iter_next (&iter))
  1.2628 +        {
  1.2629 +          const char *dirname = _dbus_hash_iter_get_string_key (&iter);
  1.2630 +          Stats *dir_stats = _dbus_hash_iter_get_value (&iter);
  1.2631 +
  1.2632 +          print_stats (dir_stats, dirname);
  1.2633 +        }
  1.2634 +
  1.2635 +      _dbus_hash_table_unref (stats_by_dir);
  1.2636 +
  1.2637 +      link = _dbus_list_get_first_link (&files);
  1.2638 +      while (link != NULL)
  1.2639 +        {
  1.2640 +          File *f = link->data;
  1.2641 +
  1.2642 +          print_untested_functions (f);
  1.2643 +          
  1.2644 +          link = _dbus_list_get_next_link (&files, link);
  1.2645 +        }
  1.2646 +
  1.2647 +      link = _dbus_list_get_first_link (&files);
  1.2648 +      while (link != NULL)
  1.2649 +        {
  1.2650 +          File *f = link->data;
  1.2651 +
  1.2652 +          print_poorly_tested_functions (f, &stats);
  1.2653 +          
  1.2654 +          link = _dbus_list_get_next_link (&files, link);
  1.2655 +        }
  1.2656 +
  1.2657 +      link = _dbus_list_get_first_link (&files);
  1.2658 +      while (link != NULL)
  1.2659 +        {
  1.2660 +          File *f = link->data;
  1.2661 +          
  1.2662 +          print_n_untested_blocks_by_function (f, &stats);
  1.2663 +          
  1.2664 +          link = _dbus_list_get_next_link (&files, link);
  1.2665 +        }
  1.2666 +    }
  1.2667 +  
  1.2668 +  return 0;
  1.2669 +}