Sync usage with man page.
[netbsd-mini2440.git] / gnu / dist / gettext / gettext-tools / lib / xreadlink.c
blobff16b06f2bf0627b98410a88249471a9c13fa015
1 /* xreadlink.c -- readlink wrapper to return the link name in malloc'd storage
3 Copyright (C) 2001, 2003 Free Software Foundation, Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING.
17 If not, write to the Free Software Foundation,
18 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20 /* Written by Jim Meyering <jim@meyering.net>
21 and Bruno Haible <bruno@clisp.org>. */
23 #if HAVE_CONFIG_H
24 # include <config.h>
25 #endif
27 /* Specification. */
28 #include "xreadlink.h"
30 #include <stdio.h>
31 #include <string.h>
32 #include <errno.h>
33 #ifndef errno
34 extern int errno;
35 #endif
37 #include <limits.h>
38 #include <sys/types.h>
39 #if HAVE_STDLIB_H
40 # include <stdlib.h>
41 #endif
42 #if HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif
46 #ifndef SIZE_MAX
47 # define SIZE_MAX ((size_t) -1)
48 #endif
49 #ifndef SSIZE_MAX
50 # define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
51 #endif
53 #ifdef NO_XMALLOC
54 # define xmalloc malloc
55 #else
56 # include "xalloc.h"
57 #endif
59 /* Call readlink to get the symbolic link value of FILENAME.
60 Return a pointer to that NUL-terminated string in malloc'd storage.
61 If readlink fails, return NULL (caller may use errno to diagnose).
62 If realloc fails, or if the link value is longer than SIZE_MAX :-),
63 give a diagnostic and exit. */
65 char *
66 xreadlink (char const *filename)
68 /* The initial buffer size for the link value. A power of 2
69 detects arithmetic overflow earlier, but is not required. */
70 #define INITIAL_BUF_SIZE 1024
72 /* Allocate the initial buffer on the stack. This way, in the common
73 case of a symlink of small size, we get away with a single small malloc()
74 instead of a big malloc() followed by a shrinking realloc(). */
75 char initial_buf[INITIAL_BUF_SIZE];
77 char *buffer = initial_buf;
78 size_t buf_size = sizeof (initial_buf);
80 while (1)
82 /* Attempt to read the link into the current buffer. */
83 ssize_t link_length = readlink (filename, buffer, buf_size);
85 if (link_length < 0)
87 if (buffer != initial_buf)
89 int saved_errno = errno;
90 free (buffer);
91 errno = saved_errno;
93 return NULL;
96 if ((size_t) link_length < buf_size)
98 buffer[link_length++] = '\0';
100 /* Return it in a chunk of memory as small as possible. */
101 if (buffer == initial_buf)
103 buffer = (char *) xmalloc (link_length);
104 #ifdef NO_XMALLOC
105 if (buffer == NULL)
106 return NULL;
107 #endif
108 memcpy (buffer, initial_buf, link_length);
110 else
112 /* Shrink buffer before returning it. */
113 if ((size_t) link_length < buf_size)
115 char *smaller_buffer = (char *) realloc (buffer, link_length);
117 if (smaller_buffer != NULL)
118 buffer = smaller_buffer;
121 return buffer;
124 if (buffer != initial_buf)
125 free (buffer);
126 buf_size *= 2;
127 if (SSIZE_MAX < buf_size || (SIZE_MAX / 2 < SSIZE_MAX && buf_size == 0))
128 #ifdef NO_XMALLOC
129 return NULL;
130 #else
131 xalloc_die ();
132 #endif
133 buffer = (char *) xmalloc (buf_size);
134 #ifdef NO_XMALLOC
135 if (buffer == NULL)
136 return NULL;
137 #endif