1/*
2 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
3 *
4 * This file is part of Jam - see jam.c for Copyright information.
5 */
6
7/*
8 * timestamp.c - get the timestamp of a file or archive member
9 *
10 * 09/22/00 (seiwald) - downshift names on OS2, too
11 * 01/08/01 (seiwald) - closure param for file_dirscan/file_archscan
12 * 11/04/02 (seiwald) - const-ing for string literals
13 */
14
15# include "jam.h"
16# include "hash.h"
17# include "filesys.h"
18# include "pathsys.h"
19# include "timestamp.h"
20# include "newstr.h"
21
22/*
23 * BINDING - all known files
24 */
25
26typedef struct _binding BINDING;
27
28struct _binding {
29	const char	*name;
30	short		flags;
31
32# define BIND_SCANNED	0x01	/* if directory or arch, has been scanned */
33
34	short		progress;
35
36# define BIND_INIT	0	/* never seen */
37# define BIND_NOENTRY	1	/* timestamp requested but file never found */
38# define BIND_SPOTTED	2	/* file found but not timed yet */
39# define BIND_MISSING	3	/* file found but can't get timestamp */
40# define BIND_FOUND	4	/* file found and time stamped */
41
42	time_t		time;	/* update time - 0 if not exist */
43} ;
44
45static struct hash *bindhash = 0;
46static void time_enter( void *, const char *, int , time_t  );
47
48static const char *time_progress[] =
49{
50	"INIT",
51	"NOENTRY",
52	"SPOTTED",
53	"MISSING",
54	"FOUND"
55} ;
56
57
58/*
59 * timestamp() - return timestamp on a file, if present
60 */
61
62void
63timestamp(
64	char	*target,
65	time_t	*time )
66{
67	PATHNAME f1, f2;
68	BINDING	binding, *b = &binding;
69	char buf[ MAXJPATH ];
70
71# ifdef DOWNSHIFT_PATHS
72	char path[ MAXJPATH ];
73	char *p = path;
74
75	do *p++ = tolower( *target );
76	while( *target++ );
77
78	target = path;
79# endif
80
81	if( !bindhash )
82	    bindhash = hashinit( sizeof( BINDING ), "bindings" );
83
84	/* Quick path - is it there? */
85
86	b->name = target;
87	b->time = b->flags = 0;
88	b->progress = BIND_INIT;
89
90	if( hashenter( bindhash, (HASHDATA **)&b ) )
91	    b->name = newstr( target );		/* never freed */
92
93	if( b->progress != BIND_INIT )
94	    goto afterscanning;
95
96	b->progress = BIND_NOENTRY;
97
98	/* Not found - have to scan for it */
99
100	path_parse( target, &f1 );
101
102	/* Scan directory if not already done so */
103
104	{
105	    BINDING binding, *b = &binding;
106
107	    f2 = f1;
108	    f2.f_grist.len = 0;
109	    path_parent( &f2 );
110	    path_build( &f2, buf, 0 );
111
112	    b->name = buf;
113	    b->time = b->flags = 0;
114	    b->progress = BIND_INIT;
115
116	    if( hashenter( bindhash, (HASHDATA **)&b ) )
117		b->name = newstr( buf );	/* never freed */
118
119	    if( !( b->flags & BIND_SCANNED ) )
120	    {
121		file_dirscan( buf, time_enter, bindhash );
122		b->flags |= BIND_SCANNED;
123	    }
124	}
125
126	/* Scan archive if not already done so */
127
128	if( f1.f_member.len )
129	{
130	    BINDING binding, *b = &binding;
131
132	    f2 = f1;
133	    f2.f_grist.len = 0;
134	    f2.f_member.len = 0;
135	    path_build( &f2, buf, 0 );
136
137	    b->name = buf;
138	    b->time = b->flags = 0;
139	    b->progress = BIND_INIT;
140
141	    if( hashenter( bindhash, (HASHDATA **)&b ) )
142		b->name = newstr( buf );	/* never freed */
143
144	    if( !( b->flags & BIND_SCANNED ) )
145	    {
146		file_archscan( buf, time_enter, bindhash );
147		b->flags |= BIND_SCANNED;
148	    }
149	}
150
151    afterscanning:
152
153	if( b->progress == BIND_SPOTTED )
154	{
155	    if( file_time( b->name, &b->time ) < 0 )
156		b->progress = BIND_MISSING;
157	    else
158		b->progress = BIND_FOUND;
159	}
160
161	*time = b->progress == BIND_FOUND ? b->time : 0;
162}
163
164static void
165time_enter(
166	void		*closure,
167	const char	*target,
168	int		found,
169	time_t		time )
170{
171	BINDING	binding, *b = &binding;
172	struct hash *bindhash = (struct hash *)closure;
173
174# ifdef DOWNSHIFT_PATHS
175	char path[ MAXJPATH ];
176	char *p = path;
177
178	do *p++ = tolower( *target );
179	while( *target++ );
180
181	target = path;
182# endif
183
184	b->name = target;
185	b->flags = 0;
186
187	if( hashenter( bindhash, (HASHDATA **)&b ) )
188	    b->name = newstr( target );		/* never freed */
189
190	b->time = time;
191	b->progress = found ? BIND_FOUND : BIND_SPOTTED;
192
193	if( DEBUG_BINDSCAN )
194	    printf( "time ( %s ) : %s\n", target, time_progress[b->progress] );
195}
196
197/*
198 * donestamps() - free timestamp tables
199 */
200
201void
202donestamps()
203{
204	hashdone( bindhash );
205}
206