1160814Ssimon/*
2296341Sdelphij * $LP: LPlib/source/LPdir_unix.c,v 1.11 2004/09/23 22:07:22 _cvs_levitte Exp
3296341Sdelphij * $
4296341Sdelphij */
5296341Sdelphij/*
6160814Ssimon * Copyright (c) 2004, Richard Levitte <richard@levitte.org>
7160814Ssimon * All rights reserved.
8160814Ssimon *
9160814Ssimon * Redistribution and use in source and binary forms, with or without
10160814Ssimon * modification, are permitted provided that the following conditions
11160814Ssimon * are met:
12160814Ssimon * 1. Redistributions of source code must retain the above copyright
13160814Ssimon *    notice, this list of conditions and the following disclaimer.
14160814Ssimon * 2. Redistributions in binary form must reproduce the above copyright
15160814Ssimon *    notice, this list of conditions and the following disclaimer in the
16160814Ssimon *    documentation and/or other materials provided with the distribution.
17296341Sdelphij *
18160814Ssimon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19160814Ssimon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20160814Ssimon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21160814Ssimon * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22160814Ssimon * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23160814Ssimon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24160814Ssimon * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25160814Ssimon * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26160814Ssimon * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27160814Ssimon * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28160814Ssimon * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29160814Ssimon */
30160814Ssimon
31160814Ssimon#include <stddef.h>
32160814Ssimon#include <stdlib.h>
33160814Ssimon#include <limits.h>
34160814Ssimon#include <string.h>
35160814Ssimon#include <sys/types.h>
36160814Ssimon#include <dirent.h>
37160814Ssimon#include <errno.h>
38160814Ssimon#ifndef LPDIR_H
39296341Sdelphij# include "LPdir.h"
40160814Ssimon#endif
41160814Ssimon
42296341Sdelphij/*
43296341Sdelphij * The POSIXly macro for the maximum number of characters in a file path is
44296341Sdelphij * NAME_MAX.  However, some operating systems use PATH_MAX instead.
45296341Sdelphij * Therefore, it seems natural to first check for PATH_MAX and use that, and
46296341Sdelphij * if it doesn't exist, use NAME_MAX.
47296341Sdelphij */
48160814Ssimon#if defined(PATH_MAX)
49160814Ssimon# define LP_ENTRY_SIZE PATH_MAX
50160814Ssimon#elif defined(NAME_MAX)
51160814Ssimon# define LP_ENTRY_SIZE NAME_MAX
52160814Ssimon#endif
53160814Ssimon
54296341Sdelphij/*
55296341Sdelphij * Of course, there's the possibility that neither PATH_MAX nor NAME_MAX
56296341Sdelphij * exist.  It's also possible that NAME_MAX exists but is define to a very
57296341Sdelphij * small value (HP-UX offers 14), so we need to check if we got a result, and
58296341Sdelphij * if it meets a minimum standard, and create or change it if not.
59296341Sdelphij */
60160814Ssimon#if !defined(LP_ENTRY_SIZE) || LP_ENTRY_SIZE<255
61160814Ssimon# undef LP_ENTRY_SIZE
62160814Ssimon# define LP_ENTRY_SIZE 255
63160814Ssimon#endif
64160814Ssimon
65296341Sdelphijstruct LP_dir_context_st {
66296341Sdelphij    DIR *dir;
67296341Sdelphij    char entry_name[LP_ENTRY_SIZE + 1];
68160814Ssimon};
69160814Ssimon
70160814Ssimonconst char *LP_find_file(LP_DIR_CTX **ctx, const char *directory)
71160814Ssimon{
72296341Sdelphij    struct dirent *direntry = NULL;
73160814Ssimon
74296341Sdelphij    if (ctx == NULL || directory == NULL) {
75296341Sdelphij        errno = EINVAL;
76296341Sdelphij        return 0;
77160814Ssimon    }
78160814Ssimon
79296341Sdelphij    errno = 0;
80296341Sdelphij    if (*ctx == NULL) {
81296341Sdelphij        *ctx = (LP_DIR_CTX *)malloc(sizeof(LP_DIR_CTX));
82296341Sdelphij        if (*ctx == NULL) {
83296341Sdelphij            errno = ENOMEM;
84296341Sdelphij            return 0;
85296341Sdelphij        }
86296341Sdelphij        memset(*ctx, '\0', sizeof(LP_DIR_CTX));
87160814Ssimon
88296341Sdelphij        (*ctx)->dir = opendir(directory);
89296341Sdelphij        if ((*ctx)->dir == NULL) {
90296341Sdelphij            int save_errno = errno; /* Probably not needed, but I'm paranoid */
91296341Sdelphij            free(*ctx);
92296341Sdelphij            *ctx = NULL;
93296341Sdelphij            errno = save_errno;
94296341Sdelphij            return 0;
95296341Sdelphij        }
96160814Ssimon    }
97160814Ssimon
98296341Sdelphij    direntry = readdir((*ctx)->dir);
99296341Sdelphij    if (direntry == NULL) {
100296341Sdelphij        return 0;
101160814Ssimon    }
102160814Ssimon
103296341Sdelphij    strncpy((*ctx)->entry_name, direntry->d_name,
104296341Sdelphij            sizeof((*ctx)->entry_name) - 1);
105296341Sdelphij    (*ctx)->entry_name[sizeof((*ctx)->entry_name) - 1] = '\0';
106296341Sdelphij    return (*ctx)->entry_name;
107160814Ssimon}
108160814Ssimon
109160814Ssimonint LP_find_file_end(LP_DIR_CTX **ctx)
110160814Ssimon{
111296341Sdelphij    if (ctx != NULL && *ctx != NULL) {
112296341Sdelphij        int ret = closedir((*ctx)->dir);
113160814Ssimon
114296341Sdelphij        free(*ctx);
115296341Sdelphij        switch (ret) {
116296341Sdelphij        case 0:
117296341Sdelphij            return 1;
118296341Sdelphij        case -1:
119296341Sdelphij            return 0;
120296341Sdelphij        default:
121296341Sdelphij            break;
122296341Sdelphij        }
123160814Ssimon    }
124296341Sdelphij    errno = EINVAL;
125296341Sdelphij    return 0;
126160814Ssimon}
127