LCOV - code coverage report
Current view: top level - libreoffice/soltools/javadep - javadep.c (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 236 317 74.4 %
Date: 2012-12-27 Functions: 20 23 87.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : /* All Java Virtual Machine Specs are from
      21             :  * "The Java Virtual Machine Specification", T. Lindholm, F. Yellin
      22             :  * (JVMS)
      23             :  */
      24             : 
      25             : #include <stdlib.h>
      26             : #include <stdio.h>
      27             : #include <stdarg.h>
      28             : #include <string.h>
      29             : #include <errno.h>
      30             : #include <ctype.h>
      31             : #include <limits.h>
      32             : 
      33             : #if defined(UNX)
      34             : #include <unistd.h>
      35             : #include <netinet/in.h>     /* ntohl(), ntohs() */
      36             : #elif defined(WNT)
      37             : #include <io.h>
      38             : #define access      _access
      39             : #define vsnprintf   _vsnprintf
      40             : #define CDECL       _cdecl
      41             : #define F_OK        00
      42             : #define PATH_MAX    _MAX_PATH
      43             : #define ntohl(x)    ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >>  8) | \
      44             :                         (((x) & 0x0000ff00) <<  8) | (((x) & 0x000000ff) << 24))
      45             : 
      46             : #define ntohs(x)    ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))
      47             : #endif
      48             : 
      49             : /* max. length of line in response file */
      50             : #define RES_FILE_BUF    65536
      51             : 
      52             : struct file {
      53             :     char *pname;
      54             :     FILE *pfs;
      55             : };
      56             : 
      57             : struct growable {
      58             :     int     ncur;
      59             :     int     nmax;
      60             :     char    **parray;
      61             : };
      62             : 
      63             : typedef struct file     file_t;
      64             : typedef unsigned char   uint8;
      65             : typedef unsigned short  uint16;
      66             : typedef unsigned int    uint32;
      67             : 
      68             : struct utf8 {
      69             :     uint16  nlen;
      70             :     void    *pdata;
      71             : };
      72             : 
      73             : typedef struct utf8     utf8_t;
      74             : 
      75             : /* The contents of the Constant_pool is described in JVMS p. 93
      76             :  */
      77             : enum {
      78             :     CONSTANT_Class              = 7,
      79             :     CONSTANT_Fieldref           = 9,
      80             :     CONSTANT_Methodref          = 10,
      81             :     CONSTANT_InterfaceMethodref = 11,
      82             :     CONSTANT_String             = 8,
      83             :     CONSTANT_Integer            = 3,
      84             :     CONSTANT_Float              = 4,
      85             :     CONSTANT_Long               = 5,
      86             :     CONSTANT_Double             = 6,
      87             :     CONSTANT_NameAndType        = 12,
      88             :     CONSTANT_Utf8               = 1
      89             : };
      90             : 
      91             : enum { NGROW_INIT = 10, NGROW = 2 };
      92             : 
      93             : static char     *pprogname  = "javadep";
      94             : static char     csep        = ';';
      95             : #if defined (UNX)
      96             : #define CDECL
      97             : static char     cpathsep    = '/';
      98             : #elif defined (WNT)
      99             : static char     cpathsep    = '\\';
     100             : #endif
     101             : static FILE     *pfsout     = NULL;
     102             : static char     *pout_file  = NULL;
     103             : 
     104             : 
     105             : /* prototypes */
     106             : uint8   read_uint8(const file_t *pfile);
     107             : uint16  read_uint16(const file_t *pfile);
     108             : uint32  read_uint32(const file_t *pfile);
     109             : void    skip_bytes(const file_t *pfile, const long nnum);
     110             : char    *escape_slash(const char *pstr);
     111             : int     is_inner(const char *pstr);
     112             : void    print_dependencies(const struct growable *pdep,
     113             :                            const char* pclass_file);
     114             : void    process_class_file(const char *pfilenamem,
     115             :                            const struct growable *pfilt);
     116             : char    *utf8tolatin1(const utf8_t a_utf8);
     117             : void    *xmalloc(size_t size);
     118             : void    *xcalloc(size_t nmemb, size_t size);
     119             : void    *xrealloc(void *ptr, size_t size);
     120             : void    grow_if_needed (struct growable *pgrow);
     121             : int     append_to_growable(struct growable *, char *);
     122             : struct growable *allocate_growable(void);
     123             : void    free_growable(struct growable *pgrowvoid);
     124             : void    create_filters(struct growable *pfilt, const struct growable *pinc);
     125             : void    usage(void);
     126             : void    err_quit(const char *, ...);
     127             : void    silent_quit(void);
     128             : 
     129             : #ifdef WNT
     130             : /* poor man's getopt() */
     131             : int     simple_getopt(char *pargv[], const char *poptstring);
     132             : char    *optarg = NULL;
     133             : int     optind  = 1;
     134             : int     optopt  = 0;
     135             : int     opterr  = 0;
     136             : #endif
     137             : 
     138             : uint8
     139         874 : read_uint8(const file_t *pfile)
     140             : {
     141             :     /* read a byte from classfile */
     142             :     size_t nread;
     143             :     uint8 ndata;
     144         874 :     nread = fread(&ndata, sizeof(uint8), 1, pfile->pfs);
     145         874 :     if ( !nread ) {
     146           0 :         fclose(pfile->pfs);
     147           0 :         err_quit("%s: truncated class file", pfile->pname);
     148             :     }
     149         874 :     return ndata;
     150             : }
     151             : 
     152             : uint16
     153         503 : read_uint16(const file_t *pfile)
     154             : {
     155             :     /* read a short from classfile and convert it to host format */
     156             :     size_t nread;
     157             :     uint16 ndata;
     158         503 :     nread = fread(&ndata, sizeof(uint16), 1, pfile->pfs);
     159         503 :     if ( !nread ) {
     160           0 :         fclose(pfile->pfs);
     161           0 :         err_quit("%s: truncated class file", pfile->pname);
     162             :     }
     163         503 :     ndata = ntohs(ndata);
     164         503 :     return ndata;
     165             : }
     166             : 
     167             : uint32
     168           4 : read_uint32(const file_t *pfile)
     169             : {
     170             :     /* read an int from classfile and convert it to host format */
     171             :     size_t nread;
     172             :     uint32 ndata;
     173           4 :     nread = fread(&ndata, sizeof(uint32), 1, pfile->pfs);
     174           4 :     if ( !nread ) {
     175           0 :         fclose(pfile->pfs);
     176           0 :         err_quit("%s: truncated class file", pfile->pname);
     177             :     }
     178           4 :     ndata = ntohl(ndata);
     179           4 :     return ndata;
     180             : }
     181             : 
     182             : utf8_t
     183         408 : read_utf8(const file_t *pfile)
     184             : {
     185             :     /* Read a java utf-8-string with uint16 length prependend
     186             :      * from class file. Returns utf8 struct
     187             :      * with fresh allocated datablock,
     188             :      * caller is responsible for freeing.
     189             :      * Data is still in network byteorder
     190             :      */
     191             : 
     192             :     utf8_t  a_utf8;
     193             :     size_t  nread;
     194             : 
     195         408 :     a_utf8.pdata = NULL;
     196             : 
     197         408 :     a_utf8.nlen = read_uint16(pfile);
     198         408 :     if (a_utf8.nlen > 0) {
     199         407 :         a_utf8.pdata = xmalloc(a_utf8.nlen*sizeof(char));
     200         407 :         nread = fread(a_utf8.pdata, a_utf8.nlen*sizeof(char), 1, pfile->pfs);
     201         407 :         if ( !nread ) {
     202           0 :             fclose(pfile->pfs);
     203           0 :             err_quit("%s: truncated class file", pfile->pname);
     204             :         }
     205             :     }
     206             : 
     207         408 :     return a_utf8;
     208             : }
     209             : 
     210          83 : char *utf8tolatin1(const utf8_t a_utf8)
     211             : {
     212             :     /* function returns fresh allocated zero terminated string,
     213             :      * caller is responsible for freeing
     214             :      */
     215             : 
     216             :     /* JVMS p. 101: the null byte is encoded using a two byte format,
     217             :      * Java Virtual Machine Utf8 strings differ in this respect from
     218             :      * standard UTF-8 strings
     219             :      */
     220             : 
     221             :     /* Multibyte data is in network byte order */
     222             : 
     223             :     char *p;
     224             :     char *pp;
     225             :     char *pstr;
     226             : 
     227          83 :     pstr = pp = xmalloc((a_utf8.nlen+1) * sizeof(char));
     228             : 
     229        2141 :     for ( p = (char*)a_utf8.pdata;
     230        2058 :           p <  (char*)a_utf8.pdata+a_utf8.nlen;
     231        1975 :           p++ ) {
     232        1975 :         if ( *p & 0x80 ) {
     233           0 :             err_quit("sorry, real UTF8 decoding not yet implemented\n");
     234             :         } else {
     235        1975 :             *pp++ = *p;
     236             :         }
     237             :     }
     238          83 :     *pp = '\0';
     239             : 
     240          83 :     return pstr;
     241             : }
     242             : 
     243             : 
     244             : void
     245         383 : skip_bytes(const file_t *pfile, const long nnumber)
     246             : {
     247             :     /* skip a nnumber of bytes in classfile */
     248         383 :     if ( fseek(pfile->pfs, nnumber, SEEK_CUR) == -1 )
     249           0 :          err_quit("%s: %s", pfile->pname, strerror(errno));
     250         383 : }
     251             : 
     252             : void
     253          80 : add_to_dependencies(struct growable *pdep,
     254             :                     const struct growable *pfilt,
     255             :                     char *pdepstr,
     256             :                     const char *pclass_file)
     257             : {
     258             :     /* create dependencies */
     259             :     int i;
     260             :     size_t nlen_filt, nlen_str, nlen_pdepstr;
     261             :     char *pstr, *ptrunc;
     262             :     char path[PATH_MAX+1];
     263             :     char cnp_class_file[PATH_MAX+1];
     264             :     char cnp_str[PATH_MAX+1];
     265             : 
     266          80 :     nlen_pdepstr = strlen(pdepstr);
     267          80 :     pstr = xmalloc((nlen_pdepstr+6+1)*sizeof(char));
     268          80 :     memcpy(pstr, pdepstr, nlen_pdepstr+1);
     269          80 :     strncat(pstr, ".class", 6);
     270             : 
     271          80 :     if ( pfilt->ncur == 0 ) { /* no filters */
     272           0 :         if ( access(pstr, F_OK) == 0 ) {
     273           0 :             append_to_growable(pdep, strdup(pstr));
     274             :         }
     275             :     } else {
     276          80 :         nlen_str    = strlen(pstr);
     277          80 :         for ( i = 0; i < pfilt->ncur; i++ ) {
     278          80 :             nlen_filt   = strlen(pfilt->parray[i]);
     279          80 :             if ( nlen_filt + 1 + nlen_str > PATH_MAX )
     280           0 :                 err_quit("path to long");
     281          80 :             memcpy(path, pfilt->parray[i], nlen_filt);
     282          80 :             path[nlen_filt]     = '/';
     283          80 :             memcpy( path+nlen_filt+1, pstr, nlen_str+1);
     284             : 
     285          80 :             if ( access(path, F_OK) != 0 ) {
     286          72 :                 free(pstr);
     287          72 :                 pstr = NULL;
     288             :                 return; /* path doesn't represent a real file, don't bother */
     289             :             }
     290             : 
     291             :             /* get the canonical path */
     292             : #if defined (UNX)
     293          16 :             if ( !(realpath(pclass_file, cnp_class_file)
     294           8 :                 && realpath(path, cnp_str) ) ) {
     295           0 :                 err_quit("can't get the canonical path");
     296             :             }
     297             : #else
     298             :             if ( !(_fullpath(cnp_class_file, pclass_file, sizeof(cnp_class_file))
     299             :                 && _fullpath(cnp_str, path, sizeof(cnp_str)) ) ) {
     300             :                 err_quit("can't get the canonical path");
     301             :             }
     302             : #endif
     303             : 
     304             :             /* truncate so that only the package prefix remains */
     305           8 :             ptrunc = strrchr(cnp_str, cpathsep);
     306           8 :             *ptrunc = '\0';
     307           8 :             ptrunc = strrchr(cnp_class_file, cpathsep);
     308           8 :             *ptrunc = '\0';
     309             : 
     310           8 :             if ( !strcmp(cnp_str, cnp_class_file) ) {
     311           8 :                 free(pstr);
     312           8 :                 pstr = NULL;
     313             :                 return; /* identical, don't bother with this one */
     314             :             }
     315             : 
     316           0 :             append_to_growable(pdep, strdup(path));
     317             :         }
     318             :     }
     319           0 :     free(pstr);
     320             :     return;
     321             : }
     322             : 
     323             : char *
     324           4 : escape_slash(const char *pstr)
     325             : {
     326             :     /* returns a fresh allocated string with all cpathsep escaped exchanged
     327             :      * with "$/"
     328             :      *
     329             :      * caller is responsible for freeing
     330             :      */
     331             : 
     332           4 :     const char *pp = pstr;
     333             :     char *p, *pnp;
     334             :     char *pnew_str;
     335             :     size_t nlen_pnp, nlen_pp;
     336           4 :     int i = 0;
     337             : 
     338          60 :     while ( (p=strchr(pp, cpathsep)) != NULL ) {
     339          52 :         ++i;
     340          52 :         pp = ++p;
     341             :     }
     342             : 
     343           4 :     nlen_pnp = strlen(pstr) + i;
     344           4 :     pnp = pnew_str = xmalloc((nlen_pnp+1) * sizeof(char));
     345             : 
     346           4 :     pp = pstr;
     347             : 
     348           4 :     if ( i > 0 ) {
     349          60 :         while ( (p=strchr(pp, cpathsep)) != NULL ) {
     350          52 :             memcpy(pnp, pp, p-pp);
     351          52 :             pnp += p-pp;
     352          52 :             *pnp++ = '$';
     353          52 :             *pnp++ = '/';
     354          52 :             pp = ++p;
     355             :         }
     356             :     }
     357           4 :     nlen_pp = strlen(pp);
     358           4 :     memcpy(pnp, pp, nlen_pp+1);
     359             : 
     360           4 :     return pnew_str;
     361             : }
     362             : 
     363             : 
     364             : void
     365           4 : print_dependencies(const struct growable *pdep, const char* pclass_file)
     366             : {
     367             :     char *pstr;
     368             :     int i;
     369             : 
     370           4 :     pstr = escape_slash(pclass_file);
     371           4 :     fprintf(pfsout, "%s:", pstr);
     372           4 :     free(pstr);
     373             : 
     374           4 :     for( i=0; i<pdep->ncur; ++i) {
     375           0 :         fprintf(pfsout, "  \\\n");
     376           0 :         pstr=escape_slash(pdep->parray[i]);
     377           0 :         fprintf(pfsout, "\t%s", pstr);
     378           0 :         free(pstr);
     379             :     }
     380             : 
     381           4 :     fprintf(pfsout,"\n\n");
     382           4 :     return;
     383             : }
     384             : 
     385             : int
     386          83 : is_inner(const char *pstr)
     387             : {
     388             :     /* return true if character '$' is found in classname */
     389             : 
     390             :     /*
     391             :      * note that a '$' in a classname is not an exact indicator
     392             :      * for an inner class. Java identifier may legally contain
     393             :      * this chararcter, and so may classnames. In the context
     394             :      * of javadep this doesn't matter since the makefile system
     395             :      * can't cope with classfiles with '$'s in the filename
     396             :      * anyway.
     397             :      *
     398             :      */
     399             : 
     400          83 :     if ( strchr(pstr, '$') != NULL )
     401           3 :         return 1;
     402             : 
     403          80 :     return 0;
     404             : }
     405             : 
     406             : void
     407           5 : process_class_file(const char *pfilename, const struct growable *pfilt)
     408             : {
     409             :     /* read class file and extract object information
     410             :      * java class files are in bigendian data format
     411             :      * (JVMS, p. 83)
     412             :      */
     413             :     int     i;
     414             :     uint32  nmagic;
     415             :     uint16  nminor, nmajor;
     416             :     uint16  ncnt;
     417             :     uint16  nclass_cnt;
     418             :     utf8_t* pc_pool;
     419             :     uint16* pc_class;
     420             :     file_t  file;
     421             : 
     422             :     struct growable *pdepen;
     423             : 
     424           5 :     file.pname = (char*)pfilename;
     425             : 
     426           5 :     file.pfs = fopen(file.pname,"rb");
     427           5 :     if ( !file.pfs )
     428           1 :         silent_quit();
     429             : 
     430           4 :     nmagic = read_uint32(&file);
     431             : 
     432           4 :     if ( nmagic != 0xCAFEBABE ) {
     433           0 :         fclose(file.pfs);
     434           0 :         err_quit("%s: invalid magic", file.pname);
     435             :     }
     436             : 
     437           4 :     nminor = read_uint16(&file);
     438           4 :     nmajor = read_uint16(&file);
     439             : 
     440             :     /* get number of entries in constant pool */
     441           4 :     ncnt = read_uint16(&file);
     442             : 
     443             : #ifdef DEBUG
     444             :     printf("Magic: %x\n", nmagic);
     445             :     printf("Major %d, Minor %d\n", nmajor, nminor);
     446             :     printf("Const_pool_count %d\n", ncnt);
     447             : #else
     448             :     (void)nmajor;
     449             :     (void)nminor;
     450             : #endif
     451             : 
     452             :     /* There can be ncount entries in the constant_pool table
     453             :      * so at most ncount-1 of them can be of type CONSTANT_Class
     454             :      * (at leat one CONSTANT_Utf8 entry must exist).
     455             :      * Usually way less CONSTANT_Class entries exists, of course
     456             :      */
     457             : 
     458           4 :     pc_pool = xcalloc(ncnt,sizeof(utf8_t));
     459           4 :     pc_class = xmalloc((ncnt-1)*sizeof(uint16));
     460             : 
     461             :     /* pc_pool[0] is reserved to the java virtual machine and does
     462             :      * not exist in the class file
     463             :      */
     464             : 
     465           4 :     nclass_cnt = 0;
     466             : 
     467         878 :     for (i = 1; i < ncnt; i++) {
     468             :         uint8   ntag;
     469             :         uint16  nindex;
     470             :         utf8_t  a_utf8;
     471             : 
     472         874 :         ntag = read_uint8(&file);
     473             : 
     474             :         /* we are only interested in CONSTANT_Class entries and
     475             :          * Utf8 string entries, because they might belong to
     476             :          * CONSTANT_Class entries
     477             :          */
     478         874 :         switch(ntag) {
     479             :             case CONSTANT_Class:
     480          83 :                 nindex = read_uint16(&file);
     481          83 :                 pc_class[nclass_cnt++] = nindex;
     482          83 :                 break;
     483             :             case CONSTANT_Fieldref:
     484             :             case CONSTANT_Methodref:
     485             :             case CONSTANT_InterfaceMethodref:
     486         164 :                 skip_bytes(&file, 4L);
     487         164 :                 break;
     488             :             case CONSTANT_String:
     489          69 :                 skip_bytes(&file, 2L);
     490          69 :                 break;
     491             :             case CONSTANT_Integer:
     492             :             case CONSTANT_Float:
     493           1 :                 skip_bytes(&file, 4L);
     494           1 :                 break;
     495             :             case CONSTANT_Long:
     496             :             case CONSTANT_Double:
     497           0 :                 skip_bytes(&file, 8L);
     498             :                 /* Long and Doubles take 2(!)
     499             :                  * entries in constant_pool_table
     500             :                  */
     501           0 :                 i++;
     502           0 :                 break;
     503             :             case CONSTANT_NameAndType:
     504         149 :                 skip_bytes(&file, 4L);
     505         149 :                 break;
     506             :             case CONSTANT_Utf8:
     507         408 :                 a_utf8 = read_utf8(&file);
     508         408 :                 pc_pool[i] = a_utf8;
     509         408 :                 break;
     510             :             default:
     511             :                 /* Unknown Constant_pool entry, this means we are
     512             :                  * in trouble
     513             :                  */
     514           0 :                 err_quit("corrupted class file\n");
     515           0 :                 break;
     516             : 
     517             :         }
     518             :     }
     519             : 
     520           4 :     fclose(file.pfs);
     521             : 
     522           4 :     pdepen = allocate_growable();
     523             : 
     524          87 :     for (i = 0; i < nclass_cnt; i++) {
     525             :         char *pstr, *ptmpstr;
     526          83 :         pstr = ptmpstr = utf8tolatin1(pc_pool[pc_class[i]]);
     527             :         /* we are not interested in inner classes */
     528          83 :         if ( is_inner(pstr) ) {
     529           3 :             free(pstr);
     530           3 :             pstr = NULL;
     531           3 :             continue;
     532             :         }
     533             :         /* strip off evt. array indicators */
     534          80 :         if ( *ptmpstr == '[' ) {
     535          12 :             while ( *ptmpstr == '[' )
     536           4 :                 ptmpstr++;
     537             :             /* we only interested in obj. arrays, which are marked with 'L' */
     538           4 :             if ( *ptmpstr == 'L' ) {
     539           4 :                 char *p = pstr;
     540           4 :                 pstr = strdup(++ptmpstr);
     541             :                 /* remove final ';' from object array name */
     542           4 :                 pstr[strlen(pstr)-1] = '\0';
     543           4 :                 free(p);
     544             :             } else {
     545           0 :                 free(pstr);
     546           0 :                 pstr = NULL;
     547             :             }
     548             :         }
     549             : 
     550          80 :         if (pstr) {
     551          80 :             add_to_dependencies(pdepen, pfilt, pstr, file.pname);
     552          80 :             free(pstr);
     553             :         }
     554             :     }
     555             : 
     556           4 :     print_dependencies(pdepen, file.pname);
     557           4 :     free_growable(pdepen);
     558           4 :     pdepen = NULL;
     559             : 
     560         882 :     for (i = 0; i < ncnt; i++)
     561         878 :         free(pc_pool[i].pdata);
     562             : 
     563           4 :     free(pc_class);
     564           4 :     free(pc_pool);
     565           4 : }
     566             : 
     567             : void *
     568         602 : xmalloc(size_t size)
     569             : {
     570             :     void *ptr;
     571             : 
     572         602 :     ptr = malloc(size);
     573             : 
     574         602 :     if ( !ptr )
     575           0 :         err_quit("out of memory");
     576             : 
     577         602 :     return ptr;
     578             : }
     579             : 
     580             : 
     581             : void *
     582           4 : xcalloc(size_t nmemb, size_t size)
     583             : {
     584             :     void *ptr;
     585             : 
     586           4 :     ptr = calloc(nmemb, size);
     587             : 
     588           4 :     if ( !ptr )
     589           0 :         err_quit("out of memory");
     590             : 
     591           4 :     return ptr;
     592             : }
     593             : 
     594             : void *
     595           0 : xrealloc(void *ptr, size_t size)
     596             : {
     597           0 :     void *newptr = realloc(ptr, size);
     598             : 
     599           0 :     if (newptr)
     600           0 :         ptr = newptr;
     601             :     else
     602           0 :         err_quit("out of memory");
     603             : 
     604           0 :     return ptr;
     605             : }
     606             : 
     607             : void
     608           0 : err_quit(const char* fmt, ...)
     609             : {
     610             :     /* No dependency file must be generated for any error condition,
     611             :      * just print message and exit.
     612             :      */
     613             :     va_list args;
     614             :     char buffer[PATH_MAX];
     615             : 
     616           0 :     va_start(args, fmt);
     617             : 
     618           0 :     if ( pprogname )
     619           0 :         fprintf(stderr, "%s: ", pprogname);
     620           0 :     vsnprintf(buffer, sizeof(buffer), fmt, args);
     621           0 :     fputs(buffer, stderr);
     622           0 :     fputc('\n', stderr);
     623             : 
     624           0 :     va_end(args);
     625             : 
     626             :     /* clean up */
     627           0 :     if ( pfsout && pfsout != stdout ) {
     628           0 :         fclose(pfsout);
     629           0 :         unlink(pout_file);
     630             :     }
     631           0 :     exit(1);
     632             : }
     633             : 
     634             : void
     635           1 : silent_quit()
     636             : {
     637             :     /* In some cases we should just do a silent exit */
     638             : 
     639             :     /* clean up */
     640           1 :     if ( pfsout && pfsout != stdout ) {
     641           1 :         fclose(pfsout);
     642           1 :         unlink(pout_file);
     643             :     }
     644           1 :     exit(0);
     645             : }
     646             : 
     647          20 : int append_to_growable(struct growable *pgrow, char *pstr)
     648             : {
     649             :     /* append an element pstr to pgrow,
     650             :      * return new number of elements
     651             :      */
     652          20 :     grow_if_needed(pgrow);
     653          20 :     pgrow->parray[pgrow->ncur++] = pstr;
     654          20 :     return pgrow->ncur;
     655             : }
     656             : 
     657             : void
     658          20 : grow_if_needed(struct growable *pgrow)
     659             : {
     660             :     /* grow growable arrays */
     661             : 
     662          20 :     if ( pgrow->ncur >= pgrow->nmax ) {
     663           0 :         pgrow->parray = xrealloc(pgrow->parray,
     664           0 :                            (NGROW*pgrow->nmax)*sizeof(char*));
     665           0 :         pgrow->nmax *= NGROW;
     666             :     }
     667          20 :     return;
     668             : }
     669             : 
     670          10 : struct growable *allocate_growable(void)
     671             : {
     672             :     /* allocate an growable array,
     673             :      * initialize with NGROW_INIT elements
     674             :      */
     675             : 
     676             :     struct growable *pgrow;
     677             : 
     678          10 :     pgrow = xmalloc(sizeof(struct growable));
     679          10 :     pgrow->parray = xmalloc(NGROW_INIT*sizeof(char *));
     680          10 :     pgrow->nmax = NGROW_INIT;
     681          10 :     pgrow->ncur = 0;
     682          10 :     return pgrow;
     683             : }
     684             : 
     685             : void
     686           8 : free_growable(struct growable *pgrow)
     687             : {
     688             :     int i;
     689          19 :     for( i = 0; i < pgrow->ncur; i++ )
     690          11 :         free(pgrow->parray[i]);
     691           8 :     free(pgrow->parray);
     692           8 :     free(pgrow);
     693           8 : }
     694             : 
     695             : void
     696           2 : create_filters(struct growable *pfilt, const struct growable *pinc)
     697             : {
     698             :     char *p, *pp, *pstr;
     699             :     int i;
     700             :     size_t nlen, nlen_pstr;
     701             :     /* break up includes into filter list */
     702           4 :     for ( i = 0; i < pinc->ncur; i++ ) {
     703           2 :         pp = pinc->parray[i];
     704             : 
     705           4 :         while ( (p = strchr(pp, csep)) != NULL) {
     706           0 :             nlen = p - pp;
     707           0 :             pstr = xmalloc((nlen+1)*sizeof(char*));
     708           0 :             memcpy(pstr, pp, nlen);
     709           0 :             pstr[nlen] = '\0';
     710           0 :             append_to_growable(pfilt, pstr);
     711           0 :             pp = p + 1;
     712             :         }
     713           2 :         nlen_pstr = strlen(pp);
     714           2 :         pstr = xmalloc((nlen_pstr+1)*sizeof(char*));
     715           2 :         memcpy(pstr, pp, nlen_pstr+1);
     716           2 :         append_to_growable(pfilt, pstr);
     717             :     }
     718             : 
     719           2 : }
     720             : 
     721             : void
     722           0 : usage()
     723             : {
     724           0 :     fprintf(stderr,
     725             :             "usage: %s [-i|-I includepath ...  -s|-S seperator "
     726             :             "-o|-O outpath -v|-V -h|-H] <file> ....\n",
     727             :             pprogname);
     728           0 : }
     729             : 
     730             : #ifdef WNT
     731             : /* my very simple minded implementation of getopt()
     732             :  * it's to sad that getopt() is not available everywhere
     733             :  * note: this is not a full POSIX conforming getopt()
     734             :  */
     735             : int simple_getopt(char *pargv[], const char *poptstring)
     736             : {
     737             :     char *parg = pargv[optind];
     738             : 
     739             :     /* skip all response file arguments */
     740             :     if ( parg ) {
     741             :         while ( *parg == '@' )
     742             :             parg = pargv[++optind];
     743             : 
     744             :         if ( parg[0] == '-' && parg[1] != '\0' ) {
     745             :             char *popt;
     746             :             int c = parg[1];
     747             :             if ( (popt = strchr(poptstring, c)) == NULL ) {
     748             :                optopt = c;
     749             :                 if ( opterr )
     750             :                     fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
     751             :                 return '?';
     752             :             }
     753             :             if ( *(++popt) == ':') {
     754             :                 if ( parg[2] != '\0' ) {
     755             :                     optarg = ++parg;
     756             :                 } else {
     757             :                     optarg = pargv[++optind];
     758             :                 }
     759             :             } else {
     760             :                 optarg = NULL;
     761             :             }
     762             :             ++optind;
     763             :             return c;
     764             :         }
     765             :     }
     766             :     return -1;
     767             : }
     768             : #endif
     769             : 
     770             : int CDECL
     771           2 : main(int argc, char *argv[])
     772             : {
     773           2 :     int     bv_flag = 0;
     774             :     struct  growable *presp, *pincs, *pfilters;
     775             :     int     c, i, nall_argc;
     776             :     char    **pall_argv;
     777             : 
     778           2 :     presp = allocate_growable();
     779             : 
     780             :     /* FIXME: cleanup the option parsing */
     781             :     /* search for response file, read it */
     782           4 :     for ( i = 1; i < argc; i++ ) {
     783           2 :         char *parg = argv[i];
     784             :         char buffer[RES_FILE_BUF];
     785             : 
     786           2 :         if ( *parg == '@' ) {
     787           2 :             FILE *pfile = fopen(++parg, "r");
     788           2 :             if ( !pfile )
     789           0 :                 err_quit("%s: %s", parg, strerror(errno));
     790           8 :             while ( !feof(pfile) ) {
     791             :                 char *p, *token;
     792             : 
     793           4 :                 if ( fgets(buffer, RES_FILE_BUF, pfile) ) {;
     794           2 :                     p = buffer;
     795          20 :                     while ( (token = strtok(p, " \t\n")) != NULL ) {
     796          16 :                         p = NULL;
     797          16 :                         append_to_growable(presp, strdup(token));
     798             :                     }
     799             :                 }
     800             :             }
     801           2 :             fclose(pfile);
     802             :         }
     803             :     }
     804             : 
     805             :     /* copy all arguments incl. response file in one array
     806             :      * for parsing with getopt
     807             :      */
     808           2 :     nall_argc = argc + presp->ncur;
     809           2 :     pall_argv = xmalloc((nall_argc+1)*sizeof(char *));
     810           2 :     memcpy(pall_argv, argv, argc*sizeof(char *));
     811           2 :     memcpy(pall_argv+argc, presp->parray, presp->ncur*sizeof(char *));
     812           2 :     *(pall_argv+argc+presp->ncur) = '\0'; /* terminate */
     813             : 
     814           2 :     opterr = 0;
     815           2 :     pincs = allocate_growable();
     816             : 
     817             : #ifdef WNT
     818             :     while( (c = simple_getopt(pall_argv, ":i:I:s:S:o:OhHvV")) != -1 ) {
     819             : #else
     820           2 :     while( (c = getopt(nall_argc, pall_argv, ":i:I:s:S:o:OhHvV")) != -1 ) {
     821             : #endif
     822           4 :         switch(c) {
     823             :             case 'i':
     824             :             case 'I':
     825           2 :                 append_to_growable(pincs, strdup(optarg));
     826           2 :                 break;
     827             :             case 's':
     828             :             case 'S':
     829           0 :                 csep = optarg[0];
     830           0 :                 break;
     831             :             case 'o':
     832             :             case 'O':
     833           2 :                 pout_file = optarg;
     834           2 :                 break;
     835             :             case 'h':
     836             :             case 'H':
     837           0 :                 usage();
     838           0 :                 return 0;
     839             :                 break;
     840             :             case 'v':
     841             :             case 'V':
     842           0 :                 bv_flag = 1;
     843           0 :                 break;
     844             :             case '?':
     845           0 :                 if (isprint (optopt))
     846           0 :                     fprintf (stderr,
     847             :                              "Unknown option `-%c'.\n", optopt);
     848             :                 else
     849           0 :                     fprintf (stderr,
     850             :                              "Unknown option character `\\x%x'.\n",
     851             :                              optopt);
     852           0 :                 usage();
     853           0 :                 return 1;
     854             :                 break;
     855             :             case ':':
     856           0 :                 fprintf(stderr, "Missing parameter.\n");
     857           0 :                 usage();
     858           0 :                 return 1;
     859             :                 break;
     860             :             default:
     861           0 :                 usage();
     862           0 :                 return 1;
     863             :                 break;
     864             :         }
     865             :     }
     866             : 
     867           2 :     pfilters = allocate_growable();
     868           2 :     create_filters(pfilters, pincs);
     869           2 :     free_growable(pincs);
     870           2 :     pincs = NULL;
     871             : 
     872           2 :     if ( pout_file ) {
     873           2 :         pfsout = fopen(pout_file, "w");
     874           2 :         if ( !pfsout )
     875           0 :             err_quit("%s: %s", pout_file, strerror(errno));
     876             :     } else {
     877           0 :         pfsout = stdout;
     878             :     }
     879             : 
     880             :     /* the remaining arguments are either class file
     881             :      * names or response files, ignore response file
     882             :      * since they have already been included
     883             :      */
     884           8 :     for ( i = optind; i < nall_argc; i++ ) {
     885           7 :         char *parg = pall_argv[i];
     886           7 :         if ( *parg != '@' ) {
     887           5 :             process_class_file(parg, pfilters);
     888           4 :             if ( pfsout != stdout ) {
     889           4 :                 if ( bv_flag )
     890           0 :                     printf("Processed %s ...\n", parg);
     891             :             }
     892             :         }
     893             :     }
     894             : 
     895           1 :     free_growable(pfilters);
     896           1 :     pfilters = NULL;
     897           1 :     free(pall_argv);
     898           1 :     pall_argv = NULL;
     899           1 :     free_growable(presp);
     900           1 :     presp = NULL;
     901             : 
     902           1 :     fclose(pfsout);
     903           1 :     exit(0);
     904             : }
     905             : 
     906             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10