summaryrefslogtreecommitdiff
path: root/dmake/stat.c
blob: 4bd4db810af162c3d372480ac736b98c674130be (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
/* RCS  $Id: stat.c,v 1.3 2007-10-15 15:41:38 ihi Exp $
--
-- SYNOPSIS
--      Bind a target name to a file.
--
-- DESCRIPTION
--  This file contains the code to go and stat a target.  The stat rules
--  follow a predefined order defined in the comment for Stat_target.
--
-- AUTHOR
--      Dennis Vadura, dvadura@dmake.wticorp.com
--
-- WWW
--      http://dmake.wticorp.com/
--
-- COPYRIGHT
--      Copyright (c) 1996,1997 by WTI Corp.  All rights reserved.
--
--      This program is NOT free software; you can redistribute it and/or
--      modify it under the terms of the Software License Agreement Provided
--      in the file <distribution-root>/readme/license.txt.
--
-- LOG
--      Use cvs log to obtain detailed change logs.
*/

#include "extern.h"


static  int _check_dir_list ANSI((CELLPTR, CELLPTR, int, int));

#ifdef DBUG
   /* Just a little ditty for debugging this thing */
   static time_t
   _do_stat( name, lib, sym, force )
   char *name;
   char *lib;
   char **sym;
   int  force;
   {
      time_t res;
      DB_ENTER( "_do_stat" );

      res = Do_stat(name, lib, sym, force);
      DB_PRINT( "stat", ("Statted [%s,%s,%d,%ld]", name, lib, sym, res) );

      DB_RETURN( res );
   }
#define DO_STAT(A,B,C,D)  _do_stat(A,B,C,D)
#else
#define DO_STAT(A,B,C,D)  Do_stat(A,B,C,D)
#endif

static char *_first;    /* If set this variable saves the first pathname that was
             * used to stat the target in, if subsequently a match is
             * found it is overridden by the matched path name. */

PUBLIC void
Stat_target( cp, setfname, force )/*
====================================
    Stat a target.  When doing so follow the following rules, suppose
    that cp->CE_NAME points at a target called fred.o:
    (See also man page: BINDING TARGETS)

        0.      If A_SYMBOL attribute set look into the library
            then do the steps 1 thru 4 on the resulting name.
        1.  Try path's obtained by prepending any dirs found as
            prerequisites for .SOURCE.o.
        2.  If not found, do same as 2 but use .SOURCE
            The predefined '.SOURCE  : .NULL' targets takes care
            of local/absolute paths.
        3.  If not found and .LIBRARYM attribute for the target is
            set then look for it in the corresponding library.
            4.  If found in step 0 thru 3, then ce_fname points at
            file name associate with target, else ce_fname points
            at a file name built by the first .SOURCE* dir that
            applied.
    If setfname is != 0 this tells _check_dir_list() to set the static
    _first variable. setfname also controls the use of _first.
    If it is -1 ce_fname (the file name associated with target) is only
    set if a matching file was found and statted, if it is 1 ce_fname
    is set to _first even if target doesn't exist yet.

    If force is TRUE really stat the target. Do not use the directory
    cache but update the files entry if it's enabled. */

CELLPTR cp;
int     setfname;
int     force;
{
   register HASHPTR hp;
   static   HASHPTR srchp = NIL(HASH);
   char         *name;
   char         *tmp;
   int          res = 0;

   DB_ENTER( "Stat_target" );

   name = cp->CE_NAME;
   DB_PRINT( "stat", ("called on [%s]", name) );

   if( srchp == NIL(HASH) ) srchp = Get_name(".SOURCE",Defs,FALSE);

   /* Look for a symbol of the form lib((symbol)) the name of the symbol
    * as entered in the hash table is (symbol) so pull out symbol and try
    * to find it's module.  If successful DO_STAT will return the module
    * as well as the archive member name (pointed at by tmp).  We then
    * replace the symbol name with the archive member name so that we
    * have the proper name for any future refrences. */

   if( cp->ce_attr & A_SYMBOL ) {
      DB_PRINT( "stat", ("Binding lib symbol [%s]", name) );

      cp->ce_time = DO_STAT( name, cp->ce_lib, &tmp, force );

      if( cp->ce_time != (time_t) 0L ) {
     /* stat the new member name below  note tmp must point at a string
      * returned by MALLOC... ie. the Do_stat code should use DmStrDup */

     if( Verbose & V_MAKE )
        printf( "%s:  Mapped ((%s)) to %s(%s)\n", Pname,
             name, cp->ce_lib, tmp );

         FREE( name );
     name = cp->CE_NAME = tmp;
     cp->ce_attr &= ~(A_FFNAME | A_SYMBOL);
      }
      else
         { DB_VOID_RETURN; }
   }

   _first = NIL(char);
   tmp = DmStrJoin( ".SOURCE", Get_suffix(name), -1, FALSE);

   /* Check .SOURCE.xxx target */
   if( (hp = Get_name(tmp, Defs, FALSE)) != NIL(HASH) )
      res = _check_dir_list( cp, hp->CP_OWNR, setfname, force );

   /* Check just .SOURCE */
   if( !res && (srchp != NIL(HASH)) )
      res = _check_dir_list( cp, srchp->CP_OWNR, setfname, force );

   /* If libmember and we haven't found it check the library */
   if( !res && (cp->ce_attr & A_LIBRARYM) ) {
      cp->ce_time = DO_STAT(name, cp->ce_lib, NIL(char *), force);

      if( !cp->ce_time && Tmd && *Tmd && cp->ce_lib ) {
     char *tmplib;
     tmplib=DmStrDup(Build_path(Tmd,cp->ce_lib));

     if ((cp->ce_time = DO_STAT(name, tmplib, NIL(char *),force)) != (time_t)0L){
        cp->ce_lib=DmStrDup(tmplib);
     }
      }

      if( Verbose & V_MAKE )
     printf( "%s:  Checking library '%s' for member [%s], time %ld\n",
         Pname, cp->ce_lib, name, cp->ce_time );
   }

   FREE( tmp );

   if( setfname == 1 || (setfname == -1 && cp->ce_time != (time_t)0L) ) {
      int setlib = (cp->ce_lib == cp->ce_fname);

      if( (cp->ce_attr & A_FFNAME) && (cp->ce_fname != NIL(char)) )
     FREE( cp->ce_fname );

      if( _first != NIL(char) ) {
     cp->ce_fname = _first;
     cp->ce_attr |= A_FFNAME;
      }
      else {
     cp->ce_fname = cp->CE_NAME;
     cp->ce_attr &= ~A_FFNAME;
      }

      if ( setlib ) cp->ce_lib = cp->ce_fname;
   }
   else if( _first )
      FREE( _first );

   /* set it as stated only if successful, this way, we shall try again
    * later. */
   if( cp->ce_time != (time_t)0L ) {
      cp->ce_flag |= F_STAT;

      /* If it is a whatif this changed scenario then return the current
       * time, but do so only if the stat was successful. */
      if ( (cp->ce_attr & A_WHATIF) && !(cp->ce_flag & F_MADE) ) {
     cp->ce_time = Do_time();
      }
   }

   DB_VOID_RETURN;
}


static int
_check_dir_list( cp, sp, setfname, force )/*
============================================
    Check the list of dir's given by the prerequisite list of sp, for a
    file pointed at by cp.  Returns 0 if path not bound, else returns
    1 and replaces old name for cell with new cell name. */

CELLPTR cp;
CELLPTR sp;
int     setfname;
int     force;
{
   /* FIXME: BCC 5.0 BUG??? If lp is assigned to a register variable then
    *        BCC 5.0 corrupts a field of the member structure when DO_STAT
    *        calls the native win95 stat system call. Blech!!!
    *
    *        Making this a static variable forces it out of a register and
    *        seems to avoid the problem. */
   static LINKPTR lp;
   char *dir;
   char *path;
   char *name;
   int  res  = 0;
   int  fset = 0;

   DB_ENTER( "_check_dir_list" );
   DB_PRINT( "mem", ("%s:-> mem %ld", cp->CE_NAME, (long) coreleft()) );

   if( sp->ce_prq != NIL(LINK) )    /* check prerequisites if any */
   {
      /* Use the real name instead of basename, this prevents silly
       * loops in inference code, and is consistent with man page */
      name = cp->CE_NAME;

      /* Here we loop through each directory on the list, and try to stat
       * the target.  We always save the first pathname we try to stat in
       * _first.  If we subsequently get a match we then replace the value of
       * _first by the matched path name.  */

      for( lp=sp->CE_PRQ; lp != NIL(LINK) && !res; lp=lp->cl_next ) {
     int  nodup = 0;
     dir  = lp->cl_prq->CE_NAME;

     if( strchr( dir, '$' ) ) dir = Expand(dir);
     if( strcmp( dir, ".NULL" ) == 0 ) {
        nodup = 1;
        path = cp->CE_NAME;
     }   else {
        path = DmStrDup(Build_path(dir,name));
     }

     res = ((cp->ce_time=DO_STAT(path,NIL(char),NIL(char *),force))!=(time_t)0L);

     /* Have to use DmStrDup to set _first since Build_path, builds it's
      * path names inside a static buffer. */
     if( setfname )
        if( (_first == NIL(char) && !fset) || res ) {
           if( _first != NIL(char) ) FREE( _first );
           if (nodup)
          _first = NIL(char);
           else {
          _first = path;
          path = NIL(char);
           }
           fset = 1;
        }

     DB_PRINT( "stat", ("_first [%s], path [%s]", _first, path) );
     if( dir != lp->cl_prq->CE_NAME )  FREE(dir);
     if( path && path != cp->CE_NAME ) FREE(path);
      }
   }

   DB_PRINT( "mem", ("%s:-< mem %ld", cp->CE_NAME, (long) coreleft()) );
   DB_RETURN( res );
}