File: directory.c

package info (click to toggle)
swish++ 6.1.5-2
  • links: PTS
  • area: main
  • in suites: squeeze
  • size: 2,256 kB
  • ctags: 1,759
  • sloc: ansic: 11,931; lisp: 804; sh: 629; perl: 366; makefile: 80
file content (250 lines) | stat: -rw-r--r-- 7,606 bytes parent folder | download | duplicates (6)
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
/*
**      SWISH++
**      directory.c
**
**      Copyright (C) 1998  Paul J. Lucas
**
**      This program is free software; you can redistribute it and/or modify
**      it under the terms of the GNU General Public License as published by
**      the Free Software Foundation; either version 2 of the License, or
**      (at your option) any later version.
**
**      This program is distributed in the hope that it will be useful,
**      but WITHOUT ANY WARRANTY; without even the implied warranty of
**      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**      GNU General Public License for more details.
**
**      You should have received a copy of the GNU General Public License
**      along with this program; if not, write to the Free Software
**      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/*
**      Note that this file is #include'd into index.c and extract.c because
**      it generates different code depending on which one it's compiled into.
*/

// standard
#include <cstring>
#include <iostream>
#include <queue>
#include <sys/types.h>                  /* needed by dirent.h */
#include <dirent.h>

// local
#include "directory.h"
#include "my_set.h"
#include "platform.h"
#include "RecurseSubdirs.h"
#include "util.h"
#include "Verbosity.h"

using namespace PJL;
using namespace std;

extern void     do_file( char const *file_name, int dir_index );

#ifdef  __CYGWIN__
//
// The directory separator character ('/' for Unix) is apparantly transformed
// into '\' for Windows by the intermediate Windows port of POSIX functions.
// However, in the case where '/' is inserted into a string and that string is
// printed, the mere printing won't do the transformation.  Hence, this file
// contains the one place in all of the SWISH++ code where we need to use '\'
// explicitly when compiling under Windows.
//
char const      Dir_Sep_Char = '\\';
#else
char const      Dir_Sep_Char = '/';
#endif  /* __CYGWIN__ */

#ifdef  INDEX
dir_set_type    dir_set;
#endif

#ifndef PJL_NO_SYMBOLIC_LINKS
#include "FollowLinks.h"
FollowLinks     follow_symbolic_links;
#endif

#ifdef  INDEX
//*****************************************************************************
//
// SYNOPSIS
//
        int check_add_directory( char const *dir_path )
//
// DESCRIPTION
//
//      Check to see if the given directory has been added to the list of
//      directories encountered: if not, add it.
//
// PARAMETERS
//
//      dir_path    The full path of a directory.  The string must point to
//                  storage that will last for the duration of the program.
//
// RETURN VALUE
//
//      Returns the index number of the directory.
//
//*****************************************************************************
{
    pair< dir_set_type::iterator, bool > const
        p = dir_set.insert( dir_set_type::value_type( dir_path, 0 ) );
    if ( p.second ) {
        //
        // We really did insert a new directory: set the index to the actual
        // value.
        //
        p.first->second = dir_set.size() - 1;
    }
    return p.first->second;
}

//*****************************************************************************
//
// SYNOPSIS
//
        void do_check_add_file( char const *file_name )
//
// SYNOPSIS
//
//      In the cases where a file is indexed directly from either the command
//      line or via standard input, its directory has to be added to dir_set.
//
//*****************************************************************************
{
    char *const dir_path = new_strdup( file_name );
    char *const slash = ::strrchr( dir_path, Dir_Sep_Char );
    int dir_index;
    //
    // Check for the case of "./file": the directory "." doesn't need to be
    // added since it's automatically added.
    //
    if ( slash && (slash > dir_path + 1 || *dir_path != '.' ) ) {
        *slash = '\0';
        dir_index = check_add_directory( dir_path );
    } else {
        delete[] dir_path;
        dir_index = 0;
    }
    do_file( file_name, dir_index );
}
#endif  /* INDEX */

//*****************************************************************************
//
// SYNOPSIS
//
        void do_directory( char const *dir_path )
//
// DESCRIPTION
//
//      Call do_file() for every file in the given directory; it will queue
//      subdirectories encountered and call do_directory() on them.  It will
//      not follow symbolic links unless explicitly told to do so.
//
//      This function uses a queue and recurses only once so as not to have too
//      many directories open concurrently.  This has the side-effect of
//      indexing in a breadth-first order rather than depth-first.
//
// PARAMETERS
//
//      dir_path    The full path of the directory of the files and
//                  subdirectories to index.  The string must point to storage
//                  that will last for the duration of the program.
//
//*****************************************************************************
{
    typedef queue<char const*> dir_queue_type;
    static dir_queue_type dir_queue;
    static int recursion;

    if ( verbosity > 1 ) {
        if ( verbosity > 2 ) cout << '\n';
        cout << dir_path << flush;
    }

#ifndef PJL_NO_SYMBOLIC_LINKS
    if ( is_symbolic_link( dir_path ) && !follow_symbolic_links ) {
        if ( verbosity > 3 )
            cout << " (skipped: symbolic link)";
        if ( verbosity > 1 )
            cout << '\n';
        return;
    }
#endif

    DIR *const dir_p = ::opendir( dir_path );
    if ( !dir_p ) {
        if ( verbosity > 3 )
            cout << " (skipped: can not open)";
        if ( verbosity > 1 )
            cout << '\n';
        return;
    }

    if ( verbosity > 1 ) {
        if ( verbosity > 2 ) cout << ':';
        cout << '\n';
    }

#ifdef  INDEX
    int const dir_index = check_add_directory( dir_path );
#endif
    //
    // Have a buffer for the full path to a file in a directory.  For each
    // file, simply strcpy() the file name into place one character past the
    // '/'.
    //
    char path[ PATH_MAX + 1 ];
    ::strcpy( path, dir_path );
    char *file = path + ::strlen( path );
    *file++ = Dir_Sep_Char;

    struct dirent const *dir_ent;
    while ( dir_ent = ::readdir( dir_p ) ) {
        //
        // See if the name is "." or "..": if so, skip it.
        //
        if ( dir_ent->d_name[0] == '.' ) {
            if ( !dir_ent->d_name[1] )
                continue;
            if ( dir_ent->d_name[1] == '.' && !dir_ent->d_name[2] )
                continue;
        }
        ::strcpy( file, dir_ent->d_name );
        if ( is_directory( path ) && recurse_subdirectories )
            dir_queue.push( new_strdup( path ) );
        else {
            //
            // Note that do_file() is called in the case where 'path' is a
            // directory and recurse_subdirectories is false.  This is OK since
            // do_file() checks for and only does plain files.  It's also
            // desirable to call do_file() so we don't have to repeat the code
            // to print verbose information for 'path'.
            //
#ifdef  INDEX
            do_file( path, dir_index );
#else
            do_file( path );
#endif
        }
    }

    ::closedir( dir_p );
    if ( recursion )
        return;

    ////////// Do all subdirectories //////////////////////////////////////////

    while ( !dir_queue.empty() ) {
        char const *const dir_path = dir_queue.front();
        dir_queue.pop();
        ++recursion;
        do_directory( dir_path );
        --recursion;
    }
}
/* vim:set et sw=4 ts=4: */