mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-26 12:53:13 +00:00
restyle remaining modules to match project style
For this change I decided to bundle the remaining modules that need to be resytyled because only two were large enough to warrant doing on their own. Reduces lint errors from 225 to 162 (-28%). Line count from 3073 to 2465 (-20%). Another step in resolving issue #2902.
This commit is contained in:
parent
ee44879d4d
commit
5c8763be0e
10 changed files with 1248 additions and 1856 deletions
80
src/util.cpp
80
src/util.cpp
|
@ -1,39 +1,32 @@
|
||||||
/** \file util.c
|
// Generic utilities library.
|
||||||
Generic utilities library.
|
//
|
||||||
|
// Contains data structures such as automatically growing array lists, priority queues, etc.
|
||||||
Contains datastructures such as automatically growing array lists, priority queues, etc.
|
#include <errno.h>
|
||||||
*/
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
#include <sys/types.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
#include "fallback.h" // IWYU pragma: keep
|
#include "fallback.h" // IWYU pragma: keep
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "common.h"
|
|
||||||
#include "wutil.h" // IWYU pragma: keep
|
#include "wutil.h" // IWYU pragma: keep
|
||||||
|
|
||||||
int wcsfilecmp(const wchar_t *a, const wchar_t *b)
|
int wcsfilecmp(const wchar_t *a, const wchar_t *b) {
|
||||||
{
|
|
||||||
CHECK(a, 0);
|
CHECK(a, 0);
|
||||||
CHECK(b, 0);
|
CHECK(b, 0);
|
||||||
|
|
||||||
if (*a==0)
|
if (*a == 0) {
|
||||||
{
|
if (*b == 0) return 0;
|
||||||
if (*b==0)
|
|
||||||
return 0;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (*b==0)
|
if (*b == 0) {
|
||||||
{
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
long secondary_diff=0;
|
long secondary_diff = 0;
|
||||||
if (iswdigit(*a) && iswdigit(*b))
|
if (iswdigit(*a) && iswdigit(*b)) {
|
||||||
{
|
|
||||||
wchar_t *aend, *bend;
|
wchar_t *aend, *bend;
|
||||||
long al;
|
long al;
|
||||||
long bl;
|
long bl;
|
||||||
|
@ -43,53 +36,40 @@ int wcsfilecmp(const wchar_t *a, const wchar_t *b)
|
||||||
al = wcstol(a, &aend, 10);
|
al = wcstol(a, &aend, 10);
|
||||||
bl = wcstol(b, &bend, 10);
|
bl = wcstol(b, &bend, 10);
|
||||||
|
|
||||||
if (errno)
|
if (errno) {
|
||||||
{
|
// Huge numbers - fall back to regular string comparison.
|
||||||
/*
|
|
||||||
Huuuuuuuuge numbers - fall back to regular string comparison
|
|
||||||
*/
|
|
||||||
return wcscmp(a, b);
|
return wcscmp(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
diff = al - bl;
|
diff = al - bl;
|
||||||
if (diff)
|
if (diff) return diff > 0 ? 2 : -2;
|
||||||
return diff > 0 ? 2 : -2;
|
|
||||||
|
|
||||||
secondary_diff = (aend-a) - (bend-b);
|
secondary_diff = (aend - a) - (bend - b);
|
||||||
|
|
||||||
a=aend-1;
|
a = aend - 1;
|
||||||
b=bend-1;
|
b = bend - 1;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
int diff = towlower(*a) - towlower(*b);
|
int diff = towlower(*a) - towlower(*b);
|
||||||
if (diff != 0)
|
if (diff != 0) return (diff > 0) ? 2 : -2;
|
||||||
return (diff>0)?2:-2;
|
|
||||||
|
|
||||||
secondary_diff = *a-*b;
|
secondary_diff = *a - *b;
|
||||||
}
|
}
|
||||||
|
|
||||||
int res = wcsfilecmp(a+1, b+1);
|
int res = wcsfilecmp(a + 1, b + 1);
|
||||||
|
|
||||||
if (abs(res) < 2)
|
if (abs(res) < 2) {
|
||||||
{
|
// No primary difference in rest of string. Use secondary difference on this element if
|
||||||
/*
|
// found.
|
||||||
No primary difference in rest of string.
|
if (secondary_diff) {
|
||||||
Use secondary difference on this element if found.
|
return secondary_diff > 0 ? 1 : -1;
|
||||||
*/
|
|
||||||
if (secondary_diff)
|
|
||||||
{
|
|
||||||
return secondary_diff > 0 ? 1 :-1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
long long get_time()
|
long long get_time() {
|
||||||
{
|
|
||||||
struct timeval time_struct;
|
struct timeval time_struct;
|
||||||
gettimeofday(&time_struct, 0);
|
gettimeofday(&time_struct, 0);
|
||||||
return 1000000ll*time_struct.tv_sec+time_struct.tv_usec;
|
return 1000000ll * time_struct.tv_sec + time_struct.tv_usec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
92
src/util.h
92
src/util.h
|
@ -1,67 +1,49 @@
|
||||||
/** \file util.h
|
// Generic utilities library.
|
||||||
Generic utilities library.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef FISH_UTIL_H
|
#ifndef FISH_UTIL_H
|
||||||
#define FISH_UTIL_H
|
#define FISH_UTIL_H
|
||||||
|
|
||||||
/**
|
/// Returns the larger of two ints.
|
||||||
Returns the larger of two ints
|
template <typename T>
|
||||||
*/
|
inline T maxi(T a, T b) {
|
||||||
template<typename T>
|
return a > b ? a : b;
|
||||||
inline T maxi(T a, T b)
|
|
||||||
{
|
|
||||||
return a>b?a:b;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/// Returns the smaller of two ints.
|
||||||
Returns the smaller of two ints
|
template <typename T>
|
||||||
*/
|
inline T mini(T a, T b) {
|
||||||
template<typename T>
|
return a < b ? a : b;
|
||||||
inline T mini(T a, T b)
|
|
||||||
{
|
|
||||||
return a<b?a:b;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/// Compares two wide character strings with an (arguably) intuitive ordering. This function tries
|
||||||
Compares two wide character strings with an (arguably) intuitive
|
/// to order strings in a way which is intuitive to humans with regards to sorting strings
|
||||||
ordering.
|
/// containing numbers.
|
||||||
|
///
|
||||||
This function tries to order strings in a way which is intuitive to
|
/// Most sorting functions would sort the strings 'file1.txt' 'file5.txt' and 'file12.txt' as:
|
||||||
humans with regards to sorting strings containing numbers.
|
///
|
||||||
|
/// file1.txt
|
||||||
Most sorting functions would sort the strings 'file1.txt'
|
/// file12.txt
|
||||||
'file5.txt' and 'file12.txt' as:
|
/// file5.txt
|
||||||
|
///
|
||||||
file1.txt
|
/// This function regards any sequence of digits as a single entity when performing comparisons, so
|
||||||
file12.txt
|
/// the output is instead:
|
||||||
file5.txt
|
///
|
||||||
|
/// file1.txt
|
||||||
This function regards any sequence of digits as a single entity
|
/// file5.txt
|
||||||
when performing comparisons, so the output is instead:
|
/// file12.txt
|
||||||
|
///
|
||||||
file1.txt
|
/// Which most people would find more intuitive.
|
||||||
file5.txt
|
///
|
||||||
file12.txt
|
/// This won't return the optimum results for numbers in bases higher than ten, such as hexadecimal,
|
||||||
|
/// but at least a stable sort order will result.
|
||||||
Which most people would find more intuitive.
|
///
|
||||||
|
/// This function performs a two-tiered sort, where difference in case and in number of leading
|
||||||
This won't return the optimum results for numbers in bases higher
|
/// zeroes in numbers only have effect if no other differences between strings are found. This way,
|
||||||
than ten, such as hexadecimal, but at least a stable sort order
|
/// a 'file1' and 'File1' will not be considered identical, and hence their internal sort order is
|
||||||
will result.
|
/// not arbitrary, but the names 'file1', 'File2' and 'file3' will still be sorted in the order
|
||||||
|
/// given above.
|
||||||
This function performs a two-tiered sort, where difference in case
|
|
||||||
and in number of leading zeroes in numbers only have effect if no
|
|
||||||
other differences between strings are found. This way, a 'file1'
|
|
||||||
and 'File1' will not be considered identical, and hence their
|
|
||||||
internal sort order is not arbitrary, but the names 'file1',
|
|
||||||
'File2' and 'file3' will still be sorted in the order given above.
|
|
||||||
*/
|
|
||||||
int wcsfilecmp(const wchar_t *a, const wchar_t *b);
|
int wcsfilecmp(const wchar_t *a, const wchar_t *b);
|
||||||
|
|
||||||
/**
|
/// Get the current time in microseconds since Jan 1, 1970.
|
||||||
Get the current time in microseconds since Jan 1, 1970
|
|
||||||
*/
|
|
||||||
long long get_time();
|
long long get_time();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,24 +1,18 @@
|
||||||
/** \file wcstringutil.cpp
|
// Helper functions for working with wcstring.
|
||||||
|
|
||||||
Helper functions for working with wcstring
|
|
||||||
*/
|
|
||||||
#include "common.h"
|
|
||||||
#include "wcstringutil.h"
|
#include "wcstringutil.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
typedef wcstring::size_type size_type;
|
typedef wcstring::size_type size_type;
|
||||||
|
|
||||||
wcstring_range wcstring_tok(wcstring& str, const wcstring &needle, wcstring_range last)
|
wcstring_range wcstring_tok(wcstring& str, const wcstring& needle, wcstring_range last) {
|
||||||
{
|
|
||||||
size_type pos = last.second == wcstring::npos ? wcstring::npos : last.first;
|
size_type pos = last.second == wcstring::npos ? wcstring::npos : last.first;
|
||||||
if (pos != wcstring::npos && last.second != wcstring::npos) pos += last.second;
|
if (pos != wcstring::npos && last.second != wcstring::npos) pos += last.second;
|
||||||
if (pos != wcstring::npos && pos != 0) ++pos;
|
if (pos != wcstring::npos && pos != 0) ++pos;
|
||||||
if (pos == wcstring::npos || pos >= str.size())
|
if (pos == wcstring::npos || pos >= str.size()) {
|
||||||
{
|
|
||||||
return std::make_pair(wcstring::npos, wcstring::npos);
|
return std::make_pair(wcstring::npos, wcstring::npos);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needle.empty())
|
if (needle.empty()) {
|
||||||
{
|
|
||||||
return std::make_pair(pos, wcstring::npos);
|
return std::make_pair(pos, wcstring::npos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,12 +20,9 @@ wcstring_range wcstring_tok(wcstring& str, const wcstring &needle, wcstring_rang
|
||||||
if (pos == wcstring::npos) return std::make_pair(wcstring::npos, wcstring::npos);
|
if (pos == wcstring::npos) return std::make_pair(wcstring::npos, wcstring::npos);
|
||||||
|
|
||||||
size_type next_pos = str.find_first_of(needle, pos);
|
size_type next_pos = str.find_first_of(needle, pos);
|
||||||
if (next_pos == wcstring::npos)
|
if (next_pos == wcstring::npos) {
|
||||||
{
|
|
||||||
return std::make_pair(pos, wcstring::npos);
|
return std::make_pair(pos, wcstring::npos);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
str[next_pos] = L'\0';
|
str[next_pos] = L'\0';
|
||||||
return std::make_pair(pos, next_pos - pos);
|
return std::make_pair(pos, next_pos - pos);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
/** \file wcstringutil.h
|
// Helper functions for working with wcstring.
|
||||||
|
|
||||||
Helper functions for working with wcstring
|
|
||||||
*/
|
|
||||||
#ifndef FISH_WCSTRINGUTIL_H
|
#ifndef FISH_WCSTRINGUTIL_H
|
||||||
#define FISH_WCSTRINGUTIL_H
|
#define FISH_WCSTRINGUTIL_H
|
||||||
|
|
||||||
|
@ -10,21 +7,19 @@ Helper functions for working with wcstring
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
/**
|
/// Typedef that represents a range in a wcstring. The first element is the location, the second is
|
||||||
typedef that represents a range in a wcstring.
|
/// the count.
|
||||||
The first element is the location, the second is the count.
|
|
||||||
*/
|
|
||||||
typedef std::pair<wcstring::size_type, wcstring::size_type> wcstring_range;
|
typedef std::pair<wcstring::size_type, wcstring::size_type> wcstring_range;
|
||||||
|
|
||||||
/**
|
/// wcstring equivalent of wcstok(). Supports NUL. For convenience and wcstok() compatibility, the
|
||||||
wcstring equivalent of wcstok(). Supports NUL.
|
/// first character of each token separator is replaced with NUL.
|
||||||
For convenience and wcstok() compatibility, the first character of each
|
///
|
||||||
token separator is replaced with NUL.
|
/// Returns a pair of (pos, count).
|
||||||
Returns a pair of (pos, count).
|
/// Returns (npos, npos) when it's done.
|
||||||
Returns (npos, npos) when it's done.
|
/// Returns (pos, npos) when the token is already known to be the final token.
|
||||||
Returns (pos, npos) when the token is already known to be the final token.
|
///
|
||||||
Note that the final token may not necessarily return (pos, npos).
|
/// Note that the final token may not necessarily return (pos, npos).
|
||||||
*/
|
wcstring_range wcstring_tok(wcstring& str, const wcstring& needle,
|
||||||
wcstring_range wcstring_tok(wcstring& str, const wcstring &needle, wcstring_range last = wcstring_range(0,0));
|
wcstring_range last = wcstring_range(0, 0));
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
630
src/wgetopt.cpp
630
src/wgetopt.cpp
|
@ -1,85 +1,68 @@
|
||||||
/** \file wgetopt.c
|
// A version of the getopt library for use with wide character strings.
|
||||||
A version of the getopt library for use with wide character strings.
|
//
|
||||||
|
// This is simply the gnu getopt library, but converted for use with wchar_t instead of char. This
|
||||||
This is simply the gnu getopt library, but converted for use with
|
// is not usually useful since the argv array is always defined to be of type char**, but in fish,
|
||||||
wchar_t instead of char. This is not usually useful since the argv
|
// all internal commands use wide characters and hence this library is useful.
|
||||||
array is always defined to be of type char**, but in fish, all
|
//
|
||||||
internal commands use wide characters and hence this library is
|
// If you want to use this version of getopt in your program, download the fish sourcecode,
|
||||||
useful.
|
// available at <a href='http://fishshell.com'>the fish homepage</a>. Extract the sourcode, copy
|
||||||
|
// wgetopt.c and wgetopt.h into your program directory, include wgetopt.h in your program, and use
|
||||||
If you want to use this version of getopt in your program,
|
// all the regular getopt functions, prefixing every function, global variable and structure with a
|
||||||
download the fish sourcecode, available at <a
|
// 'w', and use only wide character strings. There are no other functional changes in this version
|
||||||
href='http://fishshell.com'>the fish homepage</a>. Extract
|
// of getopt besides using wide character strings.
|
||||||
the sourcode, copy wgetopt.c and wgetopt.h into your program
|
//
|
||||||
directory, include wgetopt.h in your program, and use all the
|
// For examples of how to use wgetopt, see the fish builtin functions, many of which are defined in
|
||||||
regular getopt functions, prefixing every function, global
|
// builtin.c.
|
||||||
variable and structure with a 'w', and use only wide character
|
|
||||||
strings. There are no other functional changes in this version of
|
|
||||||
getopt besides using wide character strings.
|
|
||||||
|
|
||||||
For examples of how to use wgetopt, see the fish builtin
|
|
||||||
functions, many of which are defined in builtin.c.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/* Getopt for GNU.
|
|
||||||
NOTE: getopt is now part of the C library, so if you don't know what
|
|
||||||
"Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
|
|
||||||
before changing it!
|
|
||||||
|
|
||||||
Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94
|
|
||||||
Free Software Foundation, Inc.
|
|
||||||
|
|
||||||
This file is part of the GNU C Library. Its master source is NOT part of
|
|
||||||
the C library, however. The master source lives in /gd/gnu/lib.
|
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Library General Public License as
|
|
||||||
published by the Free Software Foundation; either version 2 of the
|
|
||||||
License, or (at your option) any later version.
|
|
||||||
|
|
||||||
The GNU C Library 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
|
|
||||||
Library General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public
|
|
||||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
|
||||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
|
||||||
Cambridge, MA 02139, USA. */
|
|
||||||
|
|
||||||
|
// Getopt for GNU.
|
||||||
|
//
|
||||||
|
// NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space
|
||||||
|
// clean" means, talk to roland@gnu.ai.mit.edu before changing it!
|
||||||
|
//
|
||||||
|
// Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94
|
||||||
|
// Free Software Foundation, Inc.
|
||||||
|
//
|
||||||
|
// This file is part of the GNU C Library. Its master source is NOT part of the C library, however.
|
||||||
|
// The master source lives in /gd/gnu/lib.
|
||||||
|
//
|
||||||
|
// The GNU C Library is free software; you can redistribute it and/or modify it under the terms of
|
||||||
|
// the GNU Library General Public License as published by the Free Software Foundation; either
|
||||||
|
// version 2 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The GNU C Library 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 Library General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Library General Public License along with the GNU C
|
||||||
|
// Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 675 Mass
|
||||||
|
// Ave, Cambridge, MA 02139, USA.
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
/* This needs to come after some library #include
|
// This needs to come after some library #include to get __GNU_LIBRARY__ defined.
|
||||||
to get __GNU_LIBRARY__ defined. */
|
#ifdef __GNU_LIBRARY__
|
||||||
#ifdef __GNU_LIBRARY__
|
// Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting
|
||||||
/* Don't include stdlib.h for non-GNU C libraries because some of them
|
// prototypes for getopt.
|
||||||
contain conflicting prototypes for getopt. */
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#endif /* GNU C library. */
|
#endif // GNU C library.
|
||||||
|
|
||||||
/* This version of `getopt' appears to the caller like standard Unix `getopt'
|
|
||||||
but it behaves differently for the user, since it allows the user
|
|
||||||
to intersperse the options with the other arguments.
|
|
||||||
|
|
||||||
As `getopt' works, it permutes the elements of ARGV so that,
|
|
||||||
when it is done, all the options precede everything else. Thus
|
|
||||||
all application programs are extended to handle flexible argument order.
|
|
||||||
|
|
||||||
GNU application programs can use a third alternative mode in which
|
|
||||||
they can distinguish the relative order of options and other arguments. */
|
|
||||||
|
|
||||||
|
// This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves
|
||||||
|
// differently for the user, since it allows the user to intersperse the options with the other
|
||||||
|
// arguments.
|
||||||
|
//
|
||||||
|
// As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options
|
||||||
|
// precede everything else. Thus all application programs are extended to handle flexible argument
|
||||||
|
// order.
|
||||||
|
//
|
||||||
|
// GNU application programs can use a third alternative mode in which they can distinguish the
|
||||||
|
// relative order of options and other arguments.
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "fallback.h" // IWYU pragma: keep
|
||||||
#include "wgetopt.h"
|
#include "wgetopt.h"
|
||||||
#include "wutil.h" // IWYU pragma: keep
|
#include "wutil.h" // IWYU pragma: keep
|
||||||
#include "fallback.h" // IWYU pragma: keep
|
|
||||||
|
|
||||||
/**
|
// Use translation functions if available.
|
||||||
Use translation functions if available
|
|
||||||
*/
|
|
||||||
#ifdef _
|
#ifdef _
|
||||||
#undef _
|
#undef _
|
||||||
#endif
|
#endif
|
||||||
|
@ -94,229 +77,178 @@
|
||||||
#define _(wstr) wstr
|
#define _(wstr) wstr
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __GNU_LIBRARY__
|
#ifdef __GNU_LIBRARY__
|
||||||
/* We want to avoid inclusion of string.h with non-GNU libraries
|
// We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can
|
||||||
because there are many ways it can cause trouble.
|
// cause trouble. On some systems, it contains special magic macros that don't work in GCC.
|
||||||
On some systems, it contains special magic macros that don't work
|
#include <string.h> // IWYU pragma: keep
|
||||||
in GCC. */
|
#define my_index wcschr
|
||||||
#include <string.h> // IWYU pragma: keep
|
|
||||||
#define my_index wcschr
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
/* Avoid depending on library functions or files
|
// Avoid depending on library functions or files whose names are inconsistent.
|
||||||
whose names are inconsistent. */
|
|
||||||
|
|
||||||
char *getenv();
|
char *getenv();
|
||||||
|
|
||||||
static wchar_t *
|
static wchar_t *my_index(const wchar_t *str, int chr) {
|
||||||
my_index(const wchar_t *str, int chr)
|
while (*str) {
|
||||||
{
|
if (*str == chr) return (wchar_t *)str;
|
||||||
while (*str)
|
|
||||||
{
|
|
||||||
if (*str == chr)
|
|
||||||
return (wchar_t *) str;
|
|
||||||
str++;
|
str++;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If using GCC, we can safely declare strlen this way.
|
// If using GCC, we can safely declare strlen this way. If not using GCC, it is ok not to declare
|
||||||
If not using GCC, it is ok not to declare it. */
|
// it.
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
|
// Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. That was relevant to code that
|
||||||
That was relevant to code that was here before. */
|
// was here before.
|
||||||
#if !defined (__STDC__) || !__STDC__
|
#if !defined(__STDC__) || !__STDC__
|
||||||
/* gcc with -traditional declares the built-in strlen to return int,
|
// gcc with -traditional declares the built-in strlen to return int, and has done so at least since
|
||||||
and has done so at least since version 2.4.5. -- rms. */
|
// version 2.4.5. -- rms.
|
||||||
extern int wcslen(const wchar_t *);
|
extern int wcslen(const wchar_t *);
|
||||||
#endif /* not __STDC__ */
|
#endif // not __STDC__
|
||||||
#endif /* __GNUC__ */
|
#endif // __GNUC__
|
||||||
|
|
||||||
#endif /* not __GNU_LIBRARY__ */
|
#endif // not __GNU_LIBRARY__
|
||||||
|
|
||||||
|
// Exchange two adjacent subsequences of ARGV. One subsequence is elements
|
||||||
/* Exchange two adjacent subsequences of ARGV.
|
// [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The
|
||||||
One subsequence is elements [first_nonopt,last_nonopt)
|
// other is elements [last_nonopt,woptind), which contains all the options processed since those
|
||||||
which contains all the non-options that have been skipped so far.
|
// non-options were skipped.
|
||||||
The other is elements [last_nonopt,woptind), which contains all
|
//
|
||||||
the options processed since those non-options were skipped.
|
// `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the
|
||||||
|
// non-options in ARGV after they are moved.
|
||||||
`first_nonopt' and `last_nonopt' are relocated so that they describe
|
void wgetopter_t::exchange(wchar_t **argv) {
|
||||||
the new indices of the non-options in ARGV after they are moved. */
|
|
||||||
|
|
||||||
void wgetopter_t::exchange(wchar_t **argv)
|
|
||||||
{
|
|
||||||
int bottom = first_nonopt;
|
int bottom = first_nonopt;
|
||||||
int middle = last_nonopt;
|
int middle = last_nonopt;
|
||||||
int top = woptind;
|
int top = woptind;
|
||||||
wchar_t *tem;
|
wchar_t *tem;
|
||||||
|
|
||||||
/* Exchange the shorter segment with the far end of the longer segment.
|
// Exchange the shorter segment with the far end of the longer segment. That puts the shorter
|
||||||
That puts the shorter segment into the right place.
|
// segment into the right place. It leaves the longer segment in the right place overall, but it
|
||||||
It leaves the longer segment in the right place overall,
|
// consists of two parts that need to be swapped next.
|
||||||
but it consists of two parts that need to be swapped next. */
|
|
||||||
|
|
||||||
while (top > middle && middle > bottom)
|
while (top > middle && middle > bottom) {
|
||||||
{
|
if (top - middle > middle - bottom) {
|
||||||
if (top - middle > middle - bottom)
|
// Bottom segment is the short one.
|
||||||
{
|
|
||||||
/* Bottom segment is the short one. */
|
|
||||||
int len = middle - bottom;
|
int len = middle - bottom;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Swap it with the top part of the top segment. */
|
// Swap it with the top part of the top segment.
|
||||||
for (i = 0; i < len; i++)
|
for (i = 0; i < len; i++) {
|
||||||
{
|
|
||||||
tem = argv[bottom + i];
|
tem = argv[bottom + i];
|
||||||
argv[bottom + i] = argv[top - (middle - bottom) + i];
|
argv[bottom + i] = argv[top - (middle - bottom) + i];
|
||||||
argv[top - (middle - bottom) + i] = tem;
|
argv[top - (middle - bottom) + i] = tem;
|
||||||
}
|
}
|
||||||
/* Exclude the moved bottom segment from further swapping. */
|
// Exclude the moved bottom segment from further swapping.
|
||||||
top -= len;
|
top -= len;
|
||||||
}
|
} else {
|
||||||
else
|
// Top segment is the short one.
|
||||||
{
|
|
||||||
/* Top segment is the short one. */
|
|
||||||
int len = top - middle;
|
int len = top - middle;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Swap it with the bottom part of the bottom segment. */
|
// Swap it with the bottom part of the bottom segment.
|
||||||
for (i = 0; i < len; i++)
|
for (i = 0; i < len; i++) {
|
||||||
{
|
|
||||||
tem = argv[bottom + i];
|
tem = argv[bottom + i];
|
||||||
argv[bottom + i] = argv[middle + i];
|
argv[bottom + i] = argv[middle + i];
|
||||||
argv[middle + i] = tem;
|
argv[middle + i] = tem;
|
||||||
}
|
}
|
||||||
/* Exclude the moved top segment from further swapping. */
|
// Exclude the moved top segment from further swapping.
|
||||||
bottom += len;
|
bottom += len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update records for the slots the non-options now occupy. */
|
// Update records for the slots the non-options now occupy.
|
||||||
|
|
||||||
first_nonopt += (woptind - last_nonopt);
|
first_nonopt += (woptind - last_nonopt);
|
||||||
last_nonopt = woptind;
|
last_nonopt = woptind;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the internal data when the first call is made. */
|
// Initialize the internal data when the first call is made.
|
||||||
|
const wchar_t *wgetopter_t::_wgetopt_initialize(const wchar_t *optstring) {
|
||||||
const wchar_t * wgetopter_t::_wgetopt_initialize(const wchar_t *optstring)
|
// Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the
|
||||||
{
|
// sequence of previously skipped non-option ARGV-elements is empty.
|
||||||
/* Start processing options with ARGV-element 1 (since ARGV-element 0
|
|
||||||
is the program name); the sequence of previously skipped
|
|
||||||
non-option ARGV-elements is empty. */
|
|
||||||
|
|
||||||
first_nonopt = last_nonopt = woptind = 1;
|
first_nonopt = last_nonopt = woptind = 1;
|
||||||
|
|
||||||
nextchar = NULL;
|
nextchar = NULL;
|
||||||
|
|
||||||
/* Determine how to handle the ordering of options and nonoptions. */
|
// Determine how to handle the ordering of options and nonoptions.
|
||||||
|
if (optstring[0] == '-') {
|
||||||
if (optstring[0] == '-')
|
|
||||||
{
|
|
||||||
ordering = RETURN_IN_ORDER;
|
ordering = RETURN_IN_ORDER;
|
||||||
++optstring;
|
++optstring;
|
||||||
}
|
} else if (optstring[0] == '+') {
|
||||||
else if (optstring[0] == '+')
|
|
||||||
{
|
|
||||||
ordering = REQUIRE_ORDER;
|
ordering = REQUIRE_ORDER;
|
||||||
++optstring;
|
++optstring;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
ordering = PERMUTE;
|
ordering = PERMUTE;
|
||||||
|
|
||||||
return optstring;
|
return optstring;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scan elements of ARGV (whose length is ARGC) for option characters
|
// Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING.
|
||||||
given in OPTSTRING.
|
//
|
||||||
|
// If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option
|
||||||
If an element of ARGV starts with '-', and is not exactly "-" or "--",
|
// element. The characters of this element (aside from the initial '-') are option characters. If
|
||||||
then it is an option element. The characters of this element
|
// `getopt' is called repeatedly, it returns successively each of the option characters from each of
|
||||||
(aside from the initial '-') are option characters. If `getopt'
|
// the option elements.
|
||||||
is called repeatedly, it returns successively each of the option characters
|
//
|
||||||
from each of the option elements.
|
// If `getopt' finds another option character, it returns that character, updating `woptind' and
|
||||||
|
// `nextchar' so that the next call to `getopt' can resume the scan with the following option
|
||||||
If `getopt' finds another option character, it returns that character,
|
// character or ARGV-element.
|
||||||
updating `woptind' and `nextchar' so that the next call to `getopt' can
|
//
|
||||||
resume the scan with the following option character or ARGV-element.
|
// If there are no more option characters, `getopt' returns `EOF'. Then `woptind' is the index in
|
||||||
|
// ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so
|
||||||
If there are no more option characters, `getopt' returns `EOF'.
|
// that those that are not options now come last.)
|
||||||
Then `woptind' is the index in ARGV of the first ARGV-element
|
//
|
||||||
that is not an option. (The ARGV-elements have been permuted
|
// OPTSTRING is a string containing the legitimate option characters. If an option character is seen
|
||||||
so that those that are not options now come last.)
|
// that is not listed in OPTSTRING, return '?' after printing an error message. If you set
|
||||||
|
// `wopterr' to zero, the error message is suppressed but we still return '?'.
|
||||||
OPTSTRING is a string containing the legitimate option characters.
|
//
|
||||||
If an option character is seen that is not listed in OPTSTRING,
|
// If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text
|
||||||
return '?' after printing an error message. If you set `wopterr' to
|
// in the same ARGV-element, or the text of the following ARGV-element, is returned in `optarg'.
|
||||||
zero, the error message is suppressed but we still return '?'.
|
// Two colons mean an option that wants an optional arg; if there is text in the current
|
||||||
|
// ARGV-element, it is returned in `w.woptarg', otherwise `w.woptarg' is set to zero.
|
||||||
If a char in OPTSTRING is followed by a colon, that means it wants an arg,
|
//
|
||||||
so the following text in the same ARGV-element, or the text of the following
|
// If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option
|
||||||
ARGV-element, is returned in `optarg'. Two colons mean an option that
|
// ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
|
||||||
wants an optional arg; if there is text in the current ARGV-element,
|
//
|
||||||
it is returned in `w.woptarg', otherwise `w.woptarg' is set to zero.
|
// Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the
|
||||||
|
// abbreviation is unique or is an exact match for some defined option. If they have an argument,
|
||||||
If OPTSTRING starts with `-' or `+', it requests different methods of
|
// it follows the option name in the same ARGV-element, separated from the option name by a `=', or
|
||||||
handling the non-option ARGV-elements.
|
// else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that
|
||||||
See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
|
// option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is
|
||||||
|
// zero.
|
||||||
Long-named options begin with `--' instead of `-'.
|
//
|
||||||
Their names may be abbreviated as long as the abbreviation is unique
|
// LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero.
|
||||||
or is an exact match for some defined option. If they have an
|
//
|
||||||
argument, it follows the option name in the same ARGV-element, separated
|
// LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a
|
||||||
from the option name by a `=', or else the in next ARGV-element.
|
// long-named option has been found by the most recent call.
|
||||||
When `getopt' finds a long-named option, it returns 0 if that option's
|
//
|
||||||
`flag' field is nonzero, the value of the option's `val' field
|
// If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options.
|
||||||
if the `flag' field is zero.
|
int wgetopter_t::_wgetopt_internal(int argc, wchar_t **argv, const wchar_t *optstring,
|
||||||
|
const struct woption *longopts, int *longind, int long_only) {
|
||||||
LONGOPTS is a vector of `struct option' terminated by an
|
|
||||||
element containing a name which is zero.
|
|
||||||
|
|
||||||
LONGIND returns the index in LONGOPT of the long-named option found.
|
|
||||||
It is only valid when a long-named option has been found by the most
|
|
||||||
recent call.
|
|
||||||
|
|
||||||
If LONG_ONLY is nonzero, '-' as well as '--' can introduce
|
|
||||||
long-named options. */
|
|
||||||
|
|
||||||
int wgetopter_t::_wgetopt_internal(int argc, wchar_t **argv, const wchar_t *optstring, const struct woption *longopts, int *longind, int long_only)
|
|
||||||
{
|
|
||||||
woptarg = NULL;
|
woptarg = NULL;
|
||||||
|
|
||||||
if (woptind == 0)
|
if (woptind == 0) optstring = _wgetopt_initialize(optstring);
|
||||||
optstring = _wgetopt_initialize(optstring);
|
|
||||||
|
|
||||||
if (nextchar == NULL || *nextchar == '\0')
|
|
||||||
{
|
|
||||||
/* Advance to the next ARGV-element. */
|
|
||||||
|
|
||||||
if (ordering == PERMUTE)
|
|
||||||
{
|
|
||||||
/* If we have just processed some options following some non-options,
|
|
||||||
exchange them so that the options come first. */
|
|
||||||
|
|
||||||
|
if (nextchar == NULL || *nextchar == '\0') {
|
||||||
|
// Advance to the next ARGV-element.
|
||||||
|
if (ordering == PERMUTE) {
|
||||||
|
// If we have just processed some options following some non-options, exchange them so
|
||||||
|
// that the options come first.
|
||||||
if (first_nonopt != last_nonopt && last_nonopt != woptind)
|
if (first_nonopt != last_nonopt && last_nonopt != woptind)
|
||||||
exchange(argv);
|
exchange(argv);
|
||||||
else if (last_nonopt != woptind)
|
else if (last_nonopt != woptind)
|
||||||
first_nonopt = woptind;
|
first_nonopt = woptind;
|
||||||
|
|
||||||
/* Skip any additional non-options
|
// Skip any additional non-options and extend the range of non-options previously
|
||||||
and extend the range of non-options previously skipped. */
|
// skipped.
|
||||||
|
while (woptind < argc && (argv[woptind][0] != '-' || argv[woptind][1] == '\0'))
|
||||||
while (woptind < argc
|
|
||||||
&& (argv[woptind][0] != '-' || argv[woptind][1] == '\0'))
|
|
||||||
woptind++;
|
woptind++;
|
||||||
last_nonopt = woptind;
|
last_nonopt = woptind;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The special ARGV-element `--' means premature end of options.
|
// The special ARGV-element `--' means premature end of options. Skip it like a null option,
|
||||||
Skip it like a null option,
|
// then exchange with previous non-options as if it were an option, then skip everything
|
||||||
then exchange with previous non-options as if it were an option,
|
// else like a non-option.
|
||||||
then skip everything else like a non-option. */
|
if (woptind != argc && !wcscmp(argv[woptind], L"--")) {
|
||||||
|
|
||||||
if (woptind != argc && !wcscmp(argv[woptind], L"--"))
|
|
||||||
{
|
|
||||||
woptind++;
|
woptind++;
|
||||||
|
|
||||||
if (first_nonopt != last_nonopt && last_nonopt != woptind)
|
if (first_nonopt != last_nonopt && last_nonopt != woptind)
|
||||||
|
@ -328,241 +260,187 @@ int wgetopter_t::_wgetopt_internal(int argc, wchar_t **argv, const wchar_t *opts
|
||||||
woptind = argc;
|
woptind = argc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we have done all the ARGV-elements, stop the scan
|
// If we have done all the ARGV-elements, stop the scan and back over any non-options that
|
||||||
and back over any non-options that we skipped and permuted. */
|
// we skipped and permuted.
|
||||||
|
|
||||||
if (woptind == argc)
|
if (woptind == argc) {
|
||||||
{
|
// Set the next-arg-index to point at the non-options that we previously skipped, so the
|
||||||
/* Set the next-arg-index to point at the non-options
|
// caller will digest them.
|
||||||
that we previously skipped, so the caller will digest them. */
|
if (first_nonopt != last_nonopt) woptind = first_nonopt;
|
||||||
if (first_nonopt != last_nonopt)
|
|
||||||
woptind = first_nonopt;
|
|
||||||
return EOF;
|
return EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we have come to a non-option and did not permute it,
|
// If we have come to a non-option and did not permute it, either stop the scan or describe
|
||||||
either stop the scan or describe it to the caller and pass it by. */
|
// it to the caller and pass it by.
|
||||||
|
if ((argv[woptind][0] != '-' || argv[woptind][1] == '\0')) {
|
||||||
if ((argv[woptind][0] != '-' || argv[woptind][1] == '\0'))
|
if (ordering == REQUIRE_ORDER) return EOF;
|
||||||
{
|
|
||||||
if (ordering == REQUIRE_ORDER)
|
|
||||||
return EOF;
|
|
||||||
woptarg = argv[woptind++];
|
woptarg = argv[woptind++];
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We have found another option-ARGV-element.
|
// We have found another option-ARGV-element. Skip the initial punctuation.
|
||||||
Skip the initial punctuation. */
|
nextchar = (argv[woptind] + 1 + (longopts != NULL && argv[woptind][1] == '-'));
|
||||||
|
|
||||||
nextchar = (argv[woptind] + 1
|
|
||||||
+ (longopts != NULL && argv[woptind][1] == '-'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Decode the current option-ARGV-element. */
|
// Decode the current option-ARGV-element.
|
||||||
|
|
||||||
/* Check whether the ARGV-element is a long option.
|
// Check whether the ARGV-element is a long option.
|
||||||
|
//
|
||||||
If long_only and the ARGV-element has the form "-f", where f is
|
// If long_only and the ARGV-element has the form "-f", where f is a valid short option, don't
|
||||||
a valid short option, don't consider it an abbreviated form of
|
// consider it an abbreviated form of a long option that starts with f. Otherwise there would
|
||||||
a long option that starts with f. Otherwise there would be no
|
// be no way to give the -f short option.
|
||||||
way to give the -f short option.
|
//
|
||||||
|
// On the other hand, if there's a long option "fubar" and the ARGV-element is "-fu", do
|
||||||
On the other hand, if there's a long option "fubar" and
|
// consider that an abbreviation of the long option, just like "--fu", and not "-f" with arg
|
||||||
the ARGV-element is "-fu", do consider that an abbreviation of
|
// "u".
|
||||||
the long option, just like "--fu", and not "-f" with arg "u".
|
//
|
||||||
|
// This distinction seems to be the most useful approach.
|
||||||
This distinction seems to be the most useful approach. */
|
if (longopts != NULL &&
|
||||||
|
(argv[woptind][1] == '-' ||
|
||||||
if (longopts != NULL
|
(long_only && (argv[woptind][2] || !my_index(optstring, argv[woptind][1]))))) {
|
||||||
&& (argv[woptind][1] == '-'
|
|
||||||
|| (long_only && (argv[woptind][2] || !my_index(optstring, argv[woptind][1])))))
|
|
||||||
{
|
|
||||||
wchar_t *nameend;
|
wchar_t *nameend;
|
||||||
const struct woption *p;
|
const struct woption *p;
|
||||||
const struct woption *pfound = NULL;
|
const struct woption *pfound = NULL;
|
||||||
int exact = 0;
|
int exact = 0;
|
||||||
int ambig = 0;
|
int ambig = 0;
|
||||||
int indfound = 0; /* set to zero by Anton */
|
int indfound = 0; // set to zero by Anton
|
||||||
int option_index;
|
int option_index;
|
||||||
|
|
||||||
for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
|
for (nameend = nextchar; *nameend && *nameend != '='; nameend++) /* Do nothing. */;
|
||||||
/* Do nothing. */ ;
|
|
||||||
|
|
||||||
/* Test all long options for either exact match
|
// Test all long options for either exact match or abbreviated matches.
|
||||||
or abbreviated matches. */
|
|
||||||
for (p = longopts, option_index = 0; p->name; p++, option_index++)
|
for (p = longopts, option_index = 0; p->name; p++, option_index++)
|
||||||
if (!wcsncmp(p->name, nextchar, nameend - nextchar))
|
if (!wcsncmp(p->name, nextchar, nameend - nextchar)) {
|
||||||
{
|
if ((unsigned int)(nameend - nextchar) == (unsigned int)wcslen(p->name)) {
|
||||||
if ((unsigned int)(nameend - nextchar) == (unsigned int)wcslen(p->name))
|
// Exact match found.
|
||||||
{
|
|
||||||
/* Exact match found. */
|
|
||||||
pfound = p;
|
pfound = p;
|
||||||
indfound = option_index;
|
indfound = option_index;
|
||||||
exact = 1;
|
exact = 1;
|
||||||
break;
|
break;
|
||||||
}
|
} else if (pfound == NULL) {
|
||||||
else if (pfound == NULL)
|
// First nonexact match found.
|
||||||
{
|
|
||||||
/* First nonexact match found. */
|
|
||||||
pfound = p;
|
pfound = p;
|
||||||
indfound = option_index;
|
indfound = option_index;
|
||||||
}
|
} else
|
||||||
else
|
// Second or later nonexact match found.
|
||||||
/* Second or later nonexact match found. */
|
|
||||||
ambig = 1;
|
ambig = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ambig && !exact)
|
if (ambig && !exact) {
|
||||||
{
|
|
||||||
if (wopterr)
|
if (wopterr)
|
||||||
fwprintf(stderr, _(L"%ls: Option '%ls' is ambiguous\n"),
|
fwprintf(stderr, _(L"%ls: Option '%ls' is ambiguous\n"), argv[0], argv[woptind]);
|
||||||
argv[0], argv[woptind]);
|
|
||||||
nextchar += wcslen(nextchar);
|
nextchar += wcslen(nextchar);
|
||||||
woptind++;
|
woptind++;
|
||||||
return '?';
|
return '?';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pfound != NULL)
|
if (pfound != NULL) {
|
||||||
{
|
|
||||||
option_index = indfound;
|
option_index = indfound;
|
||||||
woptind++;
|
woptind++;
|
||||||
if (*nameend)
|
if (*nameend) {
|
||||||
{
|
// Don't test has_arg with >, because some C compilers don't allow it to be used on
|
||||||
/* Don't test has_arg with >, because some C compilers don't
|
// enums.
|
||||||
allow it to be used on enums. */
|
|
||||||
if (pfound->has_arg)
|
if (pfound->has_arg)
|
||||||
woptarg = nameend + 1;
|
woptarg = nameend + 1;
|
||||||
else
|
else {
|
||||||
{
|
if (wopterr) {
|
||||||
if (wopterr)
|
if (argv[woptind - 1][1] == '-') // --option
|
||||||
{
|
fwprintf(stderr, _(L"%ls: Option '--%ls' doesn't allow an argument\n"),
|
||||||
if (argv[woptind - 1][1] == '-')
|
|
||||||
/* --option */
|
|
||||||
fwprintf(stderr,
|
|
||||||
_(L"%ls: Option '--%ls' doesn't allow an argument\n"),
|
|
||||||
argv[0], pfound->name);
|
argv[0], pfound->name);
|
||||||
else
|
else
|
||||||
/* +option or -option */
|
// +option or -option
|
||||||
fwprintf(stderr,
|
fwprintf(stderr, _(L"%ls: Option '%lc%ls' doesn't allow an argument\n"),
|
||||||
_(L"%ls: Option '%lc%ls' doesn't allow an argument\n"),
|
|
||||||
argv[0], argv[woptind - 1][0], pfound->name);
|
argv[0], argv[woptind - 1][0], pfound->name);
|
||||||
}
|
}
|
||||||
nextchar += wcslen(nextchar);
|
nextchar += wcslen(nextchar);
|
||||||
return '?';
|
return '?';
|
||||||
}
|
}
|
||||||
}
|
} else if (pfound->has_arg == 1) {
|
||||||
else if (pfound->has_arg == 1)
|
|
||||||
{
|
|
||||||
if (woptind < argc)
|
if (woptind < argc)
|
||||||
woptarg = argv[woptind++];
|
woptarg = argv[woptind++];
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
if (wopterr)
|
if (wopterr)
|
||||||
fwprintf(stderr, _(L"%ls: Option '%ls' requires an argument\n"),
|
fwprintf(stderr, _(L"%ls: Option '%ls' requires an argument\n"), argv[0],
|
||||||
argv[0], argv[woptind - 1]);
|
argv[woptind - 1]);
|
||||||
nextchar += wcslen(nextchar);
|
nextchar += wcslen(nextchar);
|
||||||
return optstring[0] == ':' ? ':' : '?';
|
return optstring[0] == ':' ? ':' : '?';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nextchar += wcslen(nextchar);
|
nextchar += wcslen(nextchar);
|
||||||
if (longind != NULL)
|
if (longind != NULL) *longind = option_index;
|
||||||
*longind = option_index;
|
if (pfound->flag) {
|
||||||
if (pfound->flag)
|
|
||||||
{
|
|
||||||
*(pfound->flag) = pfound->val;
|
*(pfound->flag) = pfound->val;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return pfound->val;
|
return pfound->val;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Can't find it as a long option. If this is not getopt_long_only,
|
// Can't find it as a long option. If this is not getopt_long_only, or the option starts
|
||||||
or the option starts with '--' or is not a valid short
|
// with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a
|
||||||
option, then it's an error.
|
// short option.
|
||||||
Otherwise interpret it as a short option. */
|
if (!long_only || argv[woptind][1] == '-' || my_index(optstring, *nextchar) == NULL) {
|
||||||
if (!long_only || argv[woptind][1] == '-'
|
if (wopterr) {
|
||||||
|| my_index(optstring, *nextchar) == NULL)
|
if (argv[woptind][1] == '-') // --option
|
||||||
{
|
fwprintf(stderr, _(L"%ls: Unrecognized option '--%ls'\n"), argv[0], nextchar);
|
||||||
if (wopterr)
|
|
||||||
{
|
|
||||||
if (argv[woptind][1] == '-')
|
|
||||||
/* --option */
|
|
||||||
fwprintf(stderr, _(L"%ls: Unrecognized option '--%ls'\n"),
|
|
||||||
argv[0], nextchar);
|
|
||||||
else
|
else
|
||||||
/* +option or -option */
|
// +option or -option
|
||||||
fwprintf(stderr, _(L"%ls: Unrecognized option '%lc%ls'\n"),
|
fwprintf(stderr, _(L"%ls: Unrecognized option '%lc%ls'\n"), argv[0],
|
||||||
argv[0], argv[woptind][0], nextchar);
|
argv[woptind][0], nextchar);
|
||||||
}
|
}
|
||||||
nextchar = (wchar_t *) L"";
|
nextchar = (wchar_t *)L"";
|
||||||
woptind++;
|
woptind++;
|
||||||
return '?';
|
return '?';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Look at and handle the next short option-character. */
|
// Look at and handle the next short option-character.
|
||||||
|
|
||||||
{
|
{
|
||||||
wchar_t c = *nextchar++;
|
wchar_t c = *nextchar++;
|
||||||
wchar_t *temp = const_cast<wchar_t*>(my_index(optstring, c));
|
wchar_t *temp = const_cast<wchar_t *>(my_index(optstring, c));
|
||||||
|
|
||||||
/* Increment `woptind' when we start to process its last character. */
|
// Increment `woptind' when we start to process its last character.
|
||||||
if (*nextchar == '\0')
|
if (*nextchar == '\0') ++woptind;
|
||||||
++woptind;
|
|
||||||
|
|
||||||
if (temp == NULL || c == ':')
|
if (temp == NULL || c == ':') {
|
||||||
{
|
if (wopterr) {
|
||||||
if (wopterr)
|
|
||||||
{
|
|
||||||
fwprintf(stderr, _(L"%ls: Invalid option -- %lc\n"), argv[0], (wint_t)c);
|
fwprintf(stderr, _(L"%ls: Invalid option -- %lc\n"), argv[0], (wint_t)c);
|
||||||
}
|
}
|
||||||
woptopt = c;
|
woptopt = c;
|
||||||
|
|
||||||
if (*nextchar != '\0')
|
if (*nextchar != '\0') woptind++;
|
||||||
woptind++;
|
|
||||||
|
|
||||||
return '?';
|
return '?';
|
||||||
}
|
}
|
||||||
if (temp[1] == ':')
|
if (temp[1] == ':') {
|
||||||
{
|
if (temp[2] == ':') {
|
||||||
if (temp[2] == ':')
|
// This is an option that accepts an argument optionally.
|
||||||
{
|
if (*nextchar != '\0') {
|
||||||
/* This is an option that accepts an argument optionally. */
|
|
||||||
if (*nextchar != '\0')
|
|
||||||
{
|
|
||||||
woptarg = nextchar;
|
woptarg = nextchar;
|
||||||
woptind++;
|
woptind++;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
woptarg = NULL;
|
woptarg = NULL;
|
||||||
nextchar = NULL;
|
nextchar = NULL;
|
||||||
}
|
} else {
|
||||||
else
|
// This is an option that requires an argument.
|
||||||
{
|
if (*nextchar != '\0') {
|
||||||
/* This is an option that requires an argument. */
|
|
||||||
if (*nextchar != '\0')
|
|
||||||
{
|
|
||||||
woptarg = nextchar;
|
woptarg = nextchar;
|
||||||
/* If we end this ARGV-element by taking the rest as an arg,
|
// If we end this ARGV-element by taking the rest as an arg, we must advance to
|
||||||
we must advance to the next element now. */
|
// the next element now.
|
||||||
woptind++;
|
woptind++;
|
||||||
}
|
} else if (woptind == argc) {
|
||||||
else if (woptind == argc)
|
if (wopterr) {
|
||||||
{
|
// 1003.2 specifies the format of this message.
|
||||||
if (wopterr)
|
fwprintf(stderr, _(L"%ls: Option requires an argument -- %lc\n"), argv[0],
|
||||||
{
|
(wint_t)c);
|
||||||
/* 1003.2 specifies the format of this message. */
|
|
||||||
fwprintf(stderr, _(L"%ls: Option requires an argument -- %lc\n"),
|
|
||||||
argv[0], (wint_t)c);
|
|
||||||
}
|
}
|
||||||
woptopt = c;
|
woptopt = c;
|
||||||
if (optstring[0] == ':')
|
if (optstring[0] == ':')
|
||||||
c = ':';
|
c = ':';
|
||||||
else
|
else
|
||||||
c = '?';
|
c = '?';
|
||||||
}
|
} else
|
||||||
else
|
// We already incremented `woptind' once; increment it again when taking next
|
||||||
/* We already incremented `woptind' once;
|
// ARGV-elt as argument.
|
||||||
increment it again when taking next ARGV-elt as argument. */
|
|
||||||
woptarg = argv[woptind++];
|
woptarg = argv[woptind++];
|
||||||
nextchar = NULL;
|
nextchar = NULL;
|
||||||
}
|
}
|
||||||
|
@ -571,12 +449,12 @@ int wgetopter_t::_wgetopt_internal(int argc, wchar_t **argv, const wchar_t *opts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int wgetopter_t::wgetopt_long(int argc, wchar_t **argv, const wchar_t *options, const struct woption *long_options, int *opt_index)
|
int wgetopter_t::wgetopt_long(int argc, wchar_t **argv, const wchar_t *options,
|
||||||
{
|
const struct woption *long_options, int *opt_index) {
|
||||||
return _wgetopt_internal(argc, argv, options, long_options, opt_index, 0);
|
return _wgetopt_internal(argc, argv, options, long_options, opt_index, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int wgetopter_t::wgetopt_long_only(int argc, wchar_t **argv, const wchar_t *options, const struct woption *long_options, int *opt_index)
|
int wgetopter_t::wgetopt_long_only(int argc, wchar_t **argv, const wchar_t *options,
|
||||||
{
|
const struct woption *long_options, int *opt_index) {
|
||||||
return _wgetopt_internal(argc, argv, options, long_options, opt_index, 1);
|
return _wgetopt_internal(argc, argv, options, long_options, opt_index, 1);
|
||||||
}
|
}
|
||||||
|
|
295
src/wgetopt.h
295
src/wgetopt.h
|
@ -1,27 +1,18 @@
|
||||||
/** \file wgetopt.h
|
// A version of the getopt library for use with wide character strings.
|
||||||
A version of the getopt library for use with wide character strings.
|
//
|
||||||
|
// This is simply the gnu getopt library, but converted for use with wchar_t instead of char. This
|
||||||
This is simply the gnu getopt library, but converted for use with
|
// is not usually useful since the argv array is always defined to be of type char**, but in fish,
|
||||||
wchar_t instead of char. This is not usually useful since the argv
|
// all internal commands use wide characters and hence this library is useful.
|
||||||
array is always defined to be of type char**, but in fish, all
|
//
|
||||||
internal commands use wide characters and hence this library is
|
// If you want to use this version of getopt in your program, download the fish sourcecode,
|
||||||
useful.
|
// available at <a href='http://fishshell.com'>the fish homepage</a>. Extract the sourcode, copy
|
||||||
|
// wgetopt.c and wgetopt.h into your program directory, include wgetopt.h in your program, and use
|
||||||
If you want to use this version of getopt in your program,
|
// all the regular getopt functions, prefixing every function, global variable and structure with a
|
||||||
download the fish sourcecode, available at <a
|
// 'w', and use only wide character strings. There are no other functional changes in this version
|
||||||
href='http://fishshell.com'>the fish homepage</a>. Extract
|
// of getopt besides using wide character strings.
|
||||||
the sourcode, copy wgetopt.c and wgetopt.h into your program
|
//
|
||||||
directory, include wgetopt.h in your program, and use all the
|
// For examples of how to use wgetopt, see the fish builtin functions, many of which are defined in
|
||||||
regular getopt functions, prefixing every function, global
|
// builtin.c.
|
||||||
variable and structure with a 'w', and use only wide character
|
|
||||||
strings. There are no other functional changes in this version of
|
|
||||||
getopt besides using wide character strings.
|
|
||||||
|
|
||||||
For examples of how to use wgetopt, see the fish builtin
|
|
||||||
functions, many of which are defined in builtin.c.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/* Declarations for getopt.
|
/* Declarations for getopt.
|
||||||
Copyright (C) 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc.
|
Copyright (C) 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc.
|
||||||
|
@ -49,169 +40,131 @@ Cambridge, MA 02139, USA. */
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
class wgetopter_t
|
class wgetopter_t {
|
||||||
{
|
private:
|
||||||
private:
|
|
||||||
void exchange(wchar_t **argv);
|
void exchange(wchar_t **argv);
|
||||||
const wchar_t * _wgetopt_initialize(const wchar_t *optstring);
|
const wchar_t *_wgetopt_initialize(const wchar_t *optstring);
|
||||||
int _wgetopt_internal(int argc, wchar_t **argv, const wchar_t *optstring, const struct woption *longopts, int *longind, int long_only);
|
int _wgetopt_internal(int argc, wchar_t **argv, const wchar_t *optstring,
|
||||||
|
const struct woption *longopts, int *longind, int long_only);
|
||||||
public:
|
|
||||||
/* For communication from `getopt' to the caller.
|
public:
|
||||||
When `getopt' finds an option that takes an argument,
|
// For communication from `getopt' to the caller. When `getopt' finds an option that takes an
|
||||||
the argument value is returned here.
|
// argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each
|
||||||
Also, when `ordering' is RETURN_IN_ORDER,
|
// non-option ARGV-element is returned here.
|
||||||
each non-option ARGV-element is returned here. */
|
|
||||||
|
|
||||||
wchar_t *woptarg;
|
wchar_t *woptarg;
|
||||||
|
|
||||||
/* Index in ARGV of the next element to be scanned.
|
// Index in ARGV of the next element to be scanned. This is used for communication to and from
|
||||||
This is used for communication to and from the caller
|
// the caller and for communication between successive calls to `getopt'.
|
||||||
and for communication between successive calls to `getopt'.
|
//
|
||||||
|
// On entry to `getopt', zero means this is the first call; initialize.
|
||||||
On entry to `getopt', zero means this is the first call; initialize.
|
//
|
||||||
|
// When `getopt' returns EOF, this is the index of the first of the non-option elements that the
|
||||||
When `getopt' returns EOF, this is the index of the first of the
|
// caller should itself scan.
|
||||||
non-option elements that the caller should itself scan.
|
//
|
||||||
|
// Otherwise, `woptind' communicates from one call to the next how much of ARGV has been scanned
|
||||||
Otherwise, `woptind' communicates from one call to the next
|
// so far.
|
||||||
how much of ARGV has been scanned so far. */
|
|
||||||
|
// XXX 1003.2 says this must be 1 before any call.
|
||||||
/* XXX 1003.2 says this must be 1 before any call. */
|
|
||||||
int woptind;
|
int woptind;
|
||||||
|
|
||||||
|
// The next char to be scanned in the option-element in which the last option character we
|
||||||
/* The next char to be scanned in the option-element
|
// returned was found. This allows us to pick up the scan where we left off.
|
||||||
in which the last option character we returned was found.
|
//
|
||||||
This allows us to pick up the scan where we left off.
|
// If this is zero, or a null string, it means resume the scan by advancing to the next
|
||||||
|
// ARGV-element.
|
||||||
If this is zero, or a null string, it means resume the scan
|
|
||||||
by advancing to the next ARGV-element. */
|
|
||||||
|
|
||||||
wchar_t *nextchar;
|
wchar_t *nextchar;
|
||||||
|
|
||||||
/* Callers store zero here to inhibit the error message
|
// Callers store zero here to inhibit the error message for unrecognized options.
|
||||||
for unrecognized options. */
|
|
||||||
|
|
||||||
int wopterr;
|
int wopterr;
|
||||||
|
|
||||||
/* Set to an option character which was unrecognized.
|
// Set to an option character which was unrecognized. This must be initialized on some systems
|
||||||
This must be initialized on some systems to avoid linking in the
|
// to avoid linking in the system's own getopt implementation.
|
||||||
system's own getopt implementation. */
|
|
||||||
|
|
||||||
int woptopt;
|
int woptopt;
|
||||||
|
|
||||||
/* Describe how to deal with options that follow non-option ARGV-elements.
|
// Describe how to deal with options that follow non-option ARGV-elements.
|
||||||
|
//
|
||||||
If the caller did not specify anything,
|
// If the caller did not specify anything, the default is PERMUTE.
|
||||||
the default is PERMUTE.
|
//
|
||||||
|
// REQUIRE_ORDER means don't recognize them as options; stop option processing when the first
|
||||||
REQUIRE_ORDER means don't recognize them as options;
|
// non-option is seen. This is what Unix does. This mode of operation is selected by using `+'
|
||||||
stop option processing when the first non-option is seen.
|
// as the first character of the list of option characters.
|
||||||
This is what Unix does.
|
//
|
||||||
This mode of operation is selected by using `+' as the first
|
// PERMUTE is the default. We permute the contents of ARGV as we scan, so that eventually all
|
||||||
character of the list of option characters.
|
// the non-options are at the end. This allows options to be given in any order, even with
|
||||||
|
// programs that were not written to expect this.
|
||||||
PERMUTE is the default. We permute the contents of ARGV as we scan,
|
//
|
||||||
so that eventually all the non-options are at the end. This allows options
|
// RETURN_IN_ORDER is an option available to programs that were written to expect options and
|
||||||
to be given in any order, even with programs that were not written to
|
// other ARGV-elements in any order and that care about the ordering of the two. We describe
|
||||||
expect this.
|
// each non-option ARGV-element as if it were the argument of an option with character code 1.
|
||||||
|
// Using `-' as the first character of the list of option characters selects this mode of
|
||||||
RETURN_IN_ORDER is an option available to programs that were written
|
// operation.
|
||||||
to expect options and other ARGV-elements in any order and that care about
|
//
|
||||||
the ordering of the two. We describe each non-option ARGV-element
|
// The special argument `--' forces an end of option-scanning regardless of the value of
|
||||||
as if it were the argument of an option with character code 1.
|
// `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return EOF with
|
||||||
Using `-' as the first character of the list of option characters
|
// `woptind' != ARGC.
|
||||||
selects this mode of operation.
|
enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering;
|
||||||
|
|
||||||
The special argument `--' forces an end of option-scanning regardless
|
// Handle permutation of arguments.
|
||||||
of the value of `ordering'. In the case of RETURN_IN_ORDER, only
|
|
||||||
`--' can cause `getopt' to return EOF with `woptind' != ARGC. */
|
// Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt'
|
||||||
|
// is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them.
|
||||||
enum
|
|
||||||
{
|
|
||||||
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
|
|
||||||
} ordering;
|
|
||||||
|
|
||||||
/* Handle permutation of arguments. */
|
|
||||||
|
|
||||||
/* Describe the part of ARGV that contains non-options that have
|
|
||||||
been skipped. `first_nonopt' is the index in ARGV of the first of them;
|
|
||||||
`last_nonopt' is the index after the last of them. */
|
|
||||||
|
|
||||||
int first_nonopt;
|
int first_nonopt;
|
||||||
int last_nonopt;
|
int last_nonopt;
|
||||||
|
|
||||||
|
wgetopter_t()
|
||||||
wgetopter_t() : woptarg(NULL), woptind(0), nextchar(0), wopterr(0), woptopt('?'), ordering(), first_nonopt(0), last_nonopt(0)
|
: woptarg(NULL),
|
||||||
{
|
woptind(0),
|
||||||
}
|
nextchar(0),
|
||||||
|
wopterr(0),
|
||||||
int wgetopt_long(int argc, wchar_t **argv, const wchar_t *options, const struct woption *long_options, int *opt_index);
|
woptopt('?'),
|
||||||
int wgetopt_long_only(int argc, wchar_t **argv, const wchar_t *options, const struct woption *long_options, int *opt_index);
|
ordering(),
|
||||||
|
first_nonopt(0),
|
||||||
|
last_nonopt(0) {}
|
||||||
|
|
||||||
|
int wgetopt_long(int argc, wchar_t **argv, const wchar_t *options,
|
||||||
|
const struct woption *long_options, int *opt_index);
|
||||||
|
int wgetopt_long_only(int argc, wchar_t **argv, const wchar_t *options,
|
||||||
|
const struct woption *long_options, int *opt_index);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Describe the long-named options requested by the application.
|
/// Describe the long-named options requested by the application. The LONG_OPTIONS argument to
|
||||||
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
|
/// getopt_long or getopt_long_only is a vector of `struct option' terminated by an element
|
||||||
of `struct option' terminated by an element containing a name which is
|
/// containing a name which is zero.
|
||||||
zero.
|
///
|
||||||
|
/// The field `has_arg' is:
|
||||||
The field `has_arg' is:
|
/// no_argument (or 0) if the option does not take an argument,
|
||||||
no_argument (or 0) if the option does not take an argument,
|
/// required_argument (or 1) if the option requires an argument,
|
||||||
required_argument (or 1) if the option requires an argument,
|
/// optional_argument (or 2) if the option takes an optional argument.
|
||||||
optional_argument (or 2) if the option takes an optional argument.
|
///
|
||||||
|
/// If the field `flag' is not NULL, it points to a variable that is set to the value given in the
|
||||||
If the field `flag' is not NULL, it points to a variable that is set
|
/// field `val' when the option is found, but left unchanged if the option is not found.
|
||||||
to the value given in the field `val' when the option is found, but
|
///
|
||||||
left unchanged if the option is not found.
|
/// To have a long-named option do something other than set an `int' to a compiled-in constant, such
|
||||||
|
/// as set a value from `optarg', set the option's `flag' field to zero and its `val' field to a
|
||||||
To have a long-named option do something other than set an `int' to
|
/// nonzero value (the equivalent single-letter option character, if there is one). For long
|
||||||
a compiled-in constant, such as set a value from `optarg', set the
|
/// options that have a zero `flag' field, `getopt' returns the contents of the `val' field.
|
||||||
option's `flag' field to zero and its `val' field to a nonzero
|
struct woption {
|
||||||
value (the equivalent single-letter option character, if there is
|
/// Long name for switch.
|
||||||
one). For long options that have a zero `flag' field, `getopt'
|
|
||||||
returns the contents of the `val' field. */
|
|
||||||
|
|
||||||
struct woption
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
long name for switch
|
|
||||||
*/
|
|
||||||
const wchar_t *name;
|
const wchar_t *name;
|
||||||
/**
|
/// Must be one of no_argument, required_argument and optional_argument.
|
||||||
Must be one of no_argument, required_argument and
|
///
|
||||||
optional_argument.
|
/// has_arg can't be an enum because some compilers complain about type mismatches in all the
|
||||||
|
/// code that assumes it is an int.
|
||||||
has_arg can't be an enum because some compilers complain about
|
|
||||||
type mismatches in all the code that assumes it is an int.
|
|
||||||
*/
|
|
||||||
int has_arg;
|
int has_arg;
|
||||||
|
/// If non-null, the flag whose value should be set if this switch is encountered.
|
||||||
/**
|
|
||||||
If non-null, the flag whose value should be set if this switch is encountered
|
|
||||||
*/
|
|
||||||
int *flag;
|
int *flag;
|
||||||
|
/// If \c flag is non-null, this is the value that flag will be set to. Otherwise, this is the
|
||||||
/**
|
/// return-value of the function call.
|
||||||
If \c flag is non-null, this is the value that flag will be set
|
|
||||||
to. Otherwise, this is the return-value of the function call.
|
|
||||||
*/
|
|
||||||
int val;
|
int val;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Names for the values of the `has_arg' field of `struct option'. */
|
// Names for the values of the `has_arg' field of `struct option'.
|
||||||
|
|
||||||
/**
|
/// Specifies that a switch does not accept an argument.
|
||||||
Specifies that a switch does not accept an argument
|
#define no_argument 0
|
||||||
*/
|
/// Specifies that a switch requires an argument.
|
||||||
#define no_argument 0
|
#define required_argument 1
|
||||||
/**
|
/// Specifies that a switch accepts an optional argument.
|
||||||
Specifies that a switch requires an argument
|
#define optional_argument 2
|
||||||
*/
|
|
||||||
#define required_argument 1
|
|
||||||
/**
|
|
||||||
Specifies that a switch accepts an optional argument
|
|
||||||
*/
|
|
||||||
#define optional_argument 2
|
|
||||||
|
|
||||||
#endif /* FISH_WGETOPT_H */
|
#endif /* FISH_WGETOPT_H */
|
||||||
|
|
1297
src/wildcard.cpp
1297
src/wildcard.cpp
File diff suppressed because it is too large
Load diff
111
src/wildcard.h
111
src/wildcard.h
|
@ -1,84 +1,69 @@
|
||||||
/** \file wildcard.h
|
// My own globbing implementation. Needed to implement this instead of using libs globbing to
|
||||||
|
// support tab-expansion of globbed paramaters.
|
||||||
My own globbing implementation. Needed to implement this instead
|
|
||||||
of using libs globbing to support tab-expansion of globbed
|
|
||||||
paramaters.
|
|
||||||
|
|
||||||
*/
|
|
||||||
#ifndef FISH_WILDCARD_H
|
#ifndef FISH_WILDCARD_H
|
||||||
#define FISH_WILDCARD_H
|
#define FISH_WILDCARD_H
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "expand.h"
|
|
||||||
#include "complete.h"
|
#include "complete.h"
|
||||||
|
#include "expand.h"
|
||||||
|
|
||||||
// Enumeration of all wildcard types
|
// Enumeration of all wildcard types.
|
||||||
enum
|
enum {
|
||||||
{
|
/// Character representing any character except '/' (slash).
|
||||||
// Character representing any character except '/' (slash).
|
|
||||||
ANY_CHAR = WILDCARD_RESERVED_BASE,
|
ANY_CHAR = WILDCARD_RESERVED_BASE,
|
||||||
// Character representing any character string not containing '/' (slash).
|
/// Character representing any character string not containing '/' (slash).
|
||||||
ANY_STRING,
|
ANY_STRING,
|
||||||
// Character representing any character string.
|
/// Character representing any character string.
|
||||||
ANY_STRING_RECURSIVE,
|
ANY_STRING_RECURSIVE,
|
||||||
// This is a special psuedo-char that is not used other than to mark the
|
/// This is a special psuedo-char that is not used other than to mark the
|
||||||
// end of the the special characters so we can sanity check the enum range.
|
/// end of the the special characters so we can sanity check the enum range.
|
||||||
ANY_SENTINAL
|
ANY_SENTINAL
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/// Expand the wildcard by matching against the filesystem.
|
||||||
Expand the wildcard by matching against the filesystem.
|
///
|
||||||
|
/// New strings are allocated using malloc and should be freed by the caller.
|
||||||
|
///
|
||||||
|
/// wildcard_expand works by dividing the wildcard into segments at each directory boundary. Each
|
||||||
|
/// segment is processed separatly. All except the last segment are handled by matching the wildcard
|
||||||
|
/// segment against all subdirectories of matching directories, and recursively calling
|
||||||
|
/// wildcard_expand for matches. On the last segment, matching is made to any file, and all matches
|
||||||
|
/// are inserted to the list.
|
||||||
|
///
|
||||||
|
/// If wildcard_expand encounters any errors (such as insufficient priviliges) during matching, no
|
||||||
|
/// error messages will be printed and wildcard_expand will continue the matching process.
|
||||||
|
///
|
||||||
|
/// \param wc The wildcard string
|
||||||
|
/// \param working_directory The working directory
|
||||||
|
/// \param flags flags for the search. Can be any combination of EXPAND_FOR_COMPLETIONS and
|
||||||
|
/// EXECUTABLES_ONLY
|
||||||
|
/// \param out The list in which to put the output
|
||||||
|
///
|
||||||
|
/// \return 1 if matches where found, 0 otherwise. Return -1 on abort (I.e. ^C was pressed).
|
||||||
|
int wildcard_expand_string(const wcstring &wc, const wcstring &working_directory,
|
||||||
|
expand_flags_t flags, std::vector<completion_t> *out);
|
||||||
|
|
||||||
New strings are allocated using malloc and should be freed by the caller.
|
/// Test whether the given wildcard matches the string. Does not perform any I/O.
|
||||||
|
///
|
||||||
|
/// \param str The string to test
|
||||||
|
/// \param wc The wildcard to test against
|
||||||
|
/// \param leading_dots_fail_to_match if set, strings with leading dots are assumed to be hidden
|
||||||
|
/// files and are not matched
|
||||||
|
///
|
||||||
|
/// \return true if the wildcard matched
|
||||||
|
bool wildcard_match(const wcstring &str, const wcstring &wc,
|
||||||
|
bool leading_dots_fail_to_match = false);
|
||||||
|
|
||||||
wildcard_expand works by dividing the wildcard into segments at
|
/// Check if the specified string contains wildcards.
|
||||||
each directory boundary. Each segment is processed separatly. All
|
|
||||||
except the last segment are handled by matching the wildcard
|
|
||||||
segment against all subdirectories of matching directories, and
|
|
||||||
recursively calling wildcard_expand for matches. On the last
|
|
||||||
segment, matching is made to any file, and all matches are
|
|
||||||
inserted to the list.
|
|
||||||
|
|
||||||
If wildcard_expand encounters any errors (such as insufficient
|
|
||||||
priviliges) during matching, no error messages will be printed and
|
|
||||||
wildcard_expand will continue the matching process.
|
|
||||||
|
|
||||||
\param wc The wildcard string
|
|
||||||
\param working_directory The working directory
|
|
||||||
\param flags flags for the search. Can be any combination of EXPAND_FOR_COMPLETIONS and EXECUTABLES_ONLY
|
|
||||||
\param out The list in which to put the output
|
|
||||||
|
|
||||||
\return 1 if matches where found, 0 otherwise. Return -1 on abort (I.e. ^C was pressed).
|
|
||||||
|
|
||||||
*/
|
|
||||||
int wildcard_expand_string(const wcstring &wc, const wcstring &working_directory, expand_flags_t flags, std::vector<completion_t> *out);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Test whether the given wildcard matches the string. Does not perform any I/O.
|
|
||||||
|
|
||||||
\param str The string to test
|
|
||||||
\param wc The wildcard to test against
|
|
||||||
\param leading_dots_fail_to_match if set, strings with leading dots are assumed to be hidden files and are not matched
|
|
||||||
\return true if the wildcard matched
|
|
||||||
*/
|
|
||||||
bool wildcard_match(const wcstring &str, const wcstring &wc, bool leading_dots_fail_to_match = false);
|
|
||||||
|
|
||||||
/** Check if the specified string contains wildcards */
|
|
||||||
bool wildcard_has(const wcstring &, bool internal);
|
bool wildcard_has(const wcstring &, bool internal);
|
||||||
bool wildcard_has(const wchar_t *, bool internal);
|
bool wildcard_has(const wchar_t *, bool internal);
|
||||||
|
|
||||||
/**
|
/// Test wildcard completion.
|
||||||
Test wildcard completion
|
bool wildcard_complete(const wcstring &str, const wchar_t *wc, const wchar_t *desc,
|
||||||
*/
|
wcstring (*desc_func)(const wcstring &), std::vector<completion_t> *out,
|
||||||
bool wildcard_complete(const wcstring &str,
|
expand_flags_t expand_flags, complete_flags_t flags);
|
||||||
const wchar_t *wc,
|
|
||||||
const wchar_t *desc,
|
|
||||||
wcstring(*desc_func)(const wcstring &),
|
|
||||||
std::vector<completion_t> *out,
|
|
||||||
expand_flags_t expand_flags,
|
|
||||||
complete_flags_t flags);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
406
src/wutil.cpp
406
src/wutil.cpp
|
@ -1,30 +1,27 @@
|
||||||
/** \file wutil.c
|
// Wide character equivalents of various standard unix functions.
|
||||||
Wide character equivalents of various standard unix
|
|
||||||
functions.
|
|
||||||
*/
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <dirent.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <wchar.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <assert.h>
|
#include <stdio.h>
|
||||||
#include <string>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <wchar.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "fallback.h" // IWYU pragma: keep
|
#include "fallback.h" // IWYU pragma: keep
|
||||||
#include "wutil.h" // IWYU pragma: keep
|
#include "wutil.h" // IWYU pragma: keep
|
||||||
|
|
||||||
typedef std::string cstring;
|
typedef std::string cstring;
|
||||||
|
|
||||||
|
@ -34,65 +31,53 @@ const file_id_t kInvalidFileID = {(dev_t)-1LL, (ino_t)-1LL, (uint64_t)-1LL, -1,
|
||||||
#ifdef MAXPATHLEN
|
#ifdef MAXPATHLEN
|
||||||
#define PATH_MAX MAXPATHLEN
|
#define PATH_MAX MAXPATHLEN
|
||||||
#else
|
#else
|
||||||
/**
|
/// Fallback length of MAXPATHLEN. Hopefully a sane value.
|
||||||
Fallback length of MAXPATHLEN. Just a hopefully sane value...
|
|
||||||
*/
|
|
||||||
#define PATH_MAX 4096
|
#define PATH_MAX 4096
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Lock to protect wgettext */
|
/// Lock to protect wgettext.
|
||||||
static pthread_mutex_t wgettext_lock;
|
static pthread_mutex_t wgettext_lock;
|
||||||
|
|
||||||
/* Map used as cache by wgettext. */
|
/// Map used as cache by wgettext.
|
||||||
typedef std::map<wcstring, wcstring> wgettext_map_t;
|
typedef std::map<wcstring, wcstring> wgettext_map_t;
|
||||||
static wgettext_map_t wgettext_map;
|
static wgettext_map_t wgettext_map;
|
||||||
|
|
||||||
bool wreaddir_resolving(DIR *dir, const std::wstring &dir_path, std::wstring &out_name, bool *out_is_dir)
|
bool wreaddir_resolving(DIR *dir, const std::wstring &dir_path, std::wstring &out_name,
|
||||||
{
|
bool *out_is_dir) {
|
||||||
struct dirent *d = readdir(dir);
|
struct dirent *d = readdir(dir);
|
||||||
if (!d) return false;
|
if (!d) return false;
|
||||||
|
|
||||||
out_name = str2wcstring(d->d_name);
|
out_name = str2wcstring(d->d_name);
|
||||||
if (out_is_dir)
|
if (out_is_dir) {
|
||||||
{
|
// The caller cares if this is a directory, so check.
|
||||||
/* The caller cares if this is a directory, so check */
|
|
||||||
bool is_dir = false;
|
bool is_dir = false;
|
||||||
|
|
||||||
/* We may be able to skip stat, if the readdir can tell us the file type directly */
|
// We may be able to skip stat, if the readdir can tell us the file type directly.
|
||||||
bool check_with_stat = true;
|
bool check_with_stat = true;
|
||||||
#ifdef HAVE_STRUCT_DIRENT_D_TYPE
|
#ifdef HAVE_STRUCT_DIRENT_D_TYPE
|
||||||
if (d->d_type == DT_DIR)
|
if (d->d_type == DT_DIR) {
|
||||||
{
|
// Known directory.
|
||||||
/* Known directory */
|
|
||||||
is_dir = true;
|
is_dir = true;
|
||||||
check_with_stat = false;
|
check_with_stat = false;
|
||||||
}
|
} else if (d->d_type == DT_LNK || d->d_type == DT_UNKNOWN) {
|
||||||
else if (d->d_type == DT_LNK || d->d_type == DT_UNKNOWN)
|
// We want to treat symlinks to directories as directories. Use stat to resolve it.
|
||||||
{
|
|
||||||
/* We want to treat symlinks to directories as directories. Use stat to resolve it. */
|
|
||||||
check_with_stat = true;
|
check_with_stat = true;
|
||||||
}
|
} else {
|
||||||
else
|
// Regular file.
|
||||||
{
|
|
||||||
/* Regular file */
|
|
||||||
is_dir = false;
|
is_dir = false;
|
||||||
check_with_stat = false;
|
check_with_stat = false;
|
||||||
}
|
}
|
||||||
#endif // HAVE_STRUCT_DIRENT_D_TYPE
|
#endif // HAVE_STRUCT_DIRENT_D_TYPE
|
||||||
if (check_with_stat)
|
if (check_with_stat) {
|
||||||
{
|
// We couldn't determine the file type from the dirent; check by stat'ing it.
|
||||||
/* We couldn't determine the file type from the dirent; check by stat'ing it */
|
|
||||||
cstring fullpath = wcs2string(dir_path);
|
cstring fullpath = wcs2string(dir_path);
|
||||||
fullpath.push_back('/');
|
fullpath.push_back('/');
|
||||||
fullpath.append(d->d_name);
|
fullpath.append(d->d_name);
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
if (stat(fullpath.c_str(), &buf) != 0)
|
if (stat(fullpath.c_str(), &buf) != 0) {
|
||||||
{
|
|
||||||
is_dir = false;
|
is_dir = false;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
is_dir = !!(S_ISDIR(buf.st_mode));
|
is_dir = !!(S_ISDIR(buf.st_mode));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,8 +86,7 @@ bool wreaddir_resolving(DIR *dir, const std::wstring &dir_path, std::wstring &ou
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wreaddir(DIR *dir, std::wstring &out_name)
|
bool wreaddir(DIR *dir, std::wstring &out_name) {
|
||||||
{
|
|
||||||
struct dirent *d = readdir(dir);
|
struct dirent *d = readdir(dir);
|
||||||
if (!d) return false;
|
if (!d) return false;
|
||||||
|
|
||||||
|
@ -110,53 +94,45 @@ bool wreaddir(DIR *dir, std::wstring &out_name)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wreaddir_for_dirs(DIR *dir, wcstring *out_name)
|
bool wreaddir_for_dirs(DIR *dir, wcstring *out_name) {
|
||||||
{
|
|
||||||
struct dirent *result = NULL;
|
struct dirent *result = NULL;
|
||||||
while (result == NULL)
|
while (result == NULL) {
|
||||||
{
|
|
||||||
struct dirent *d = readdir(dir);
|
struct dirent *d = readdir(dir);
|
||||||
if (!d) break;
|
if (!d) break;
|
||||||
|
|
||||||
#if HAVE_STRUCT_DIRENT_D_TYPE
|
#if HAVE_STRUCT_DIRENT_D_TYPE
|
||||||
switch (d->d_type)
|
switch (d->d_type) {
|
||||||
{
|
|
||||||
// These may be directories
|
|
||||||
case DT_DIR:
|
case DT_DIR:
|
||||||
case DT_LNK:
|
case DT_LNK:
|
||||||
case DT_UNKNOWN:
|
case DT_UNKNOWN: {
|
||||||
|
// These may be directories.
|
||||||
result = d;
|
result = d;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
// Nothing else can
|
default: {
|
||||||
default:
|
// Nothing else can.
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
/* We can't determine if it's a directory or not, so just return it */
|
// We can't determine if it's a directory or not, so just return it.
|
||||||
result = d;
|
result = d;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (result && out_name)
|
if (result && out_name) {
|
||||||
{
|
|
||||||
*out_name = str2wcstring(result->d_name);
|
*out_name = str2wcstring(result->d_name);
|
||||||
}
|
}
|
||||||
return result != NULL;
|
return result != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const wcstring wgetcwd() {
|
||||||
const wcstring wgetcwd()
|
|
||||||
{
|
|
||||||
wcstring retval;
|
wcstring retval;
|
||||||
|
|
||||||
char *res = getcwd(NULL, 0);
|
char *res = getcwd(NULL, 0);
|
||||||
if (res)
|
if (res) {
|
||||||
{
|
|
||||||
retval = str2wcstring(res);
|
retval = str2wcstring(res);
|
||||||
free(res);
|
free(res);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
debug(0, _(L"getcwd() failed with errno %d/%s"), errno, strerror(errno));
|
debug(0, _(L"getcwd() failed with errno %d/%s"), errno, strerror(errno));
|
||||||
retval = wcstring();
|
retval = wcstring();
|
||||||
}
|
}
|
||||||
|
@ -164,176 +140,147 @@ const wcstring wgetcwd()
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
int wchdir(const wcstring &dir)
|
int wchdir(const wcstring &dir) {
|
||||||
{
|
|
||||||
cstring tmp = wcs2string(dir);
|
cstring tmp = wcs2string(dir);
|
||||||
return chdir(tmp.c_str());
|
return chdir(tmp.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *wfopen(const wcstring &path, const char *mode)
|
FILE *wfopen(const wcstring &path, const char *mode) {
|
||||||
{
|
|
||||||
int permissions = 0, options = 0;
|
int permissions = 0, options = 0;
|
||||||
size_t idx = 0;
|
size_t idx = 0;
|
||||||
switch (mode[idx++])
|
switch (mode[idx++]) {
|
||||||
{
|
case 'r': {
|
||||||
case 'r':
|
|
||||||
permissions = O_RDONLY;
|
permissions = O_RDONLY;
|
||||||
break;
|
break;
|
||||||
case 'w':
|
}
|
||||||
|
case 'w': {
|
||||||
permissions = O_WRONLY;
|
permissions = O_WRONLY;
|
||||||
options = O_CREAT | O_TRUNC;
|
options = O_CREAT | O_TRUNC;
|
||||||
break;
|
break;
|
||||||
case 'a':
|
}
|
||||||
|
case 'a': {
|
||||||
permissions = O_WRONLY;
|
permissions = O_WRONLY;
|
||||||
options = O_CREAT | O_APPEND;
|
options = O_CREAT | O_APPEND;
|
||||||
break;
|
break;
|
||||||
default:
|
}
|
||||||
|
default: {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return NULL;
|
return NULL;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* Skip binary */
|
// Skip binary.
|
||||||
if (mode[idx] == 'b')
|
if (mode[idx] == 'b') idx++;
|
||||||
idx++;
|
|
||||||
|
|
||||||
/* Consider append option */
|
// Consider append option.
|
||||||
if (mode[idx] == '+')
|
if (mode[idx] == '+') permissions = O_RDWR;
|
||||||
permissions = O_RDWR;
|
|
||||||
|
|
||||||
int fd = wopen_cloexec(path, permissions | options, 0666);
|
int fd = wopen_cloexec(path, permissions | options, 0666);
|
||||||
if (fd < 0)
|
if (fd < 0) return NULL;
|
||||||
return NULL;
|
|
||||||
FILE *result = fdopen(fd, mode);
|
FILE *result = fdopen(fd, mode);
|
||||||
if (result == NULL)
|
if (result == NULL) close(fd);
|
||||||
close(fd);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool set_cloexec(int fd)
|
bool set_cloexec(int fd) {
|
||||||
{
|
|
||||||
int flags = fcntl(fd, F_GETFD, 0);
|
int flags = fcntl(fd, F_GETFD, 0);
|
||||||
if (flags < 0)
|
if (flags < 0) {
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
} else if (flags & FD_CLOEXEC) {
|
||||||
else if (flags & FD_CLOEXEC)
|
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return fcntl(fd, F_SETFD, flags | FD_CLOEXEC) >= 0;
|
return fcntl(fd, F_SETFD, flags | FD_CLOEXEC) >= 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int wopen_internal(const wcstring &pathname, int flags, mode_t mode, bool cloexec)
|
static int wopen_internal(const wcstring &pathname, int flags, mode_t mode, bool cloexec) {
|
||||||
{
|
|
||||||
ASSERT_IS_NOT_FORKED_CHILD();
|
ASSERT_IS_NOT_FORKED_CHILD();
|
||||||
cstring tmp = wcs2string(pathname);
|
cstring tmp = wcs2string(pathname);
|
||||||
/* Prefer to use O_CLOEXEC. It has to both be defined and nonzero. */
|
// Prefer to use O_CLOEXEC. It has to both be defined and nonzero.
|
||||||
#ifdef O_CLOEXEC
|
#ifdef O_CLOEXEC
|
||||||
if (cloexec && (O_CLOEXEC != 0))
|
if (cloexec && (O_CLOEXEC != 0)) {
|
||||||
{
|
|
||||||
flags |= O_CLOEXEC;
|
flags |= O_CLOEXEC;
|
||||||
cloexec = false;
|
cloexec = false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
int fd = ::open(tmp.c_str(), flags, mode);
|
int fd = ::open(tmp.c_str(), flags, mode);
|
||||||
if (cloexec && fd >= 0 && ! set_cloexec(fd))
|
if (cloexec && fd >= 0 && !set_cloexec(fd)) {
|
||||||
{
|
|
||||||
close(fd);
|
close(fd);
|
||||||
fd = -1;
|
fd = -1;
|
||||||
}
|
}
|
||||||
return fd;
|
return fd;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int wopen_cloexec(const wcstring &pathname, int flags, mode_t mode)
|
int wopen_cloexec(const wcstring &pathname, int flags, mode_t mode) {
|
||||||
{
|
|
||||||
return wopen_internal(pathname, flags, mode, true);
|
return wopen_internal(pathname, flags, mode, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
DIR *wopendir(const wcstring &name)
|
DIR *wopendir(const wcstring &name) {
|
||||||
{
|
|
||||||
const cstring tmp = wcs2string(name);
|
const cstring tmp = wcs2string(name);
|
||||||
return opendir(tmp.c_str());
|
return opendir(tmp.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
int wstat(const wcstring &file_name, struct stat *buf)
|
int wstat(const wcstring &file_name, struct stat *buf) {
|
||||||
{
|
|
||||||
const cstring tmp = wcs2string(file_name);
|
const cstring tmp = wcs2string(file_name);
|
||||||
return stat(tmp.c_str(), buf);
|
return stat(tmp.c_str(), buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
int lwstat(const wcstring &file_name, struct stat *buf)
|
int lwstat(const wcstring &file_name, struct stat *buf) {
|
||||||
{
|
|
||||||
const cstring tmp = wcs2string(file_name);
|
const cstring tmp = wcs2string(file_name);
|
||||||
return lstat(tmp.c_str(), buf);
|
return lstat(tmp.c_str(), buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
int waccess(const wcstring &file_name, int mode)
|
int waccess(const wcstring &file_name, int mode) {
|
||||||
{
|
|
||||||
const cstring tmp = wcs2string(file_name);
|
const cstring tmp = wcs2string(file_name);
|
||||||
return access(tmp.c_str(), mode);
|
return access(tmp.c_str(), mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
int wunlink(const wcstring &file_name)
|
int wunlink(const wcstring &file_name) {
|
||||||
{
|
|
||||||
const cstring tmp = wcs2string(file_name);
|
const cstring tmp = wcs2string(file_name);
|
||||||
return unlink(tmp.c_str());
|
return unlink(tmp.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void wperror(const wchar_t *s)
|
void wperror(const wchar_t *s) {
|
||||||
{
|
|
||||||
int e = errno;
|
int e = errno;
|
||||||
if (s[0] != L'\0')
|
if (s[0] != L'\0') {
|
||||||
{
|
|
||||||
fwprintf(stderr, L"%ls: ", s);
|
fwprintf(stderr, L"%ls: ", s);
|
||||||
}
|
}
|
||||||
fwprintf(stderr, L"%s\n", strerror(e));
|
fwprintf(stderr, L"%s\n", strerror(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
int make_fd_nonblocking(int fd)
|
int make_fd_nonblocking(int fd) {
|
||||||
{
|
|
||||||
int flags = fcntl(fd, F_GETFL, 0);
|
int flags = fcntl(fd, F_GETFL, 0);
|
||||||
int err = 0;
|
int err = 0;
|
||||||
if (!(flags & O_NONBLOCK))
|
if (!(flags & O_NONBLOCK)) {
|
||||||
{
|
|
||||||
err = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
err = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
||||||
}
|
}
|
||||||
return err == -1 ? errno : 0;
|
return err == -1 ? errno : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int make_fd_blocking(int fd)
|
int make_fd_blocking(int fd) {
|
||||||
{
|
|
||||||
int flags = fcntl(fd, F_GETFL, 0);
|
int flags = fcntl(fd, F_GETFL, 0);
|
||||||
int err = 0;
|
int err = 0;
|
||||||
if (flags & O_NONBLOCK)
|
if (flags & O_NONBLOCK) {
|
||||||
{
|
|
||||||
err = fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
|
err = fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
|
||||||
}
|
}
|
||||||
return err == -1 ? errno : 0;
|
return err == -1 ? errno : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void safe_append(char *buffer, const char *s, size_t buffsize)
|
static inline void safe_append(char *buffer, const char *s, size_t buffsize) {
|
||||||
{
|
|
||||||
strncat(buffer, s, buffsize - strlen(buffer) - 1);
|
strncat(buffer, s, buffsize - strlen(buffer) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// In general, strerror is not async-safe, and therefore we cannot use it directly
|
// In general, strerror is not async-safe, and therefore we cannot use it directly. So instead we
|
||||||
// So instead we have to grub through sys_nerr and sys_errlist directly
|
// have to grub through sys_nerr and sys_errlist directly On GNU toolchain, this will produce a
|
||||||
// On GNU toolchain, this will produce a deprecation warning from the linker (!!),
|
// deprecation warning from the linker (!!), which appears impossible to suppress!
|
||||||
// which appears impossible to suppress!
|
const char *safe_strerror(int err) {
|
||||||
const char *safe_strerror(int err)
|
|
||||||
{
|
|
||||||
#if defined(__UCLIBC__)
|
#if defined(__UCLIBC__)
|
||||||
// uClibc does not have sys_errlist, however, its strerror is believed to be async-safe
|
// uClibc does not have sys_errlist, however, its strerror is believed to be async-safe.
|
||||||
// See #808
|
// See issue #808.
|
||||||
return strerror(err);
|
return strerror(err);
|
||||||
#elif defined(HAVE__SYS__ERRS) || defined(HAVE_SYS_ERRLIST)
|
#elif defined(HAVE__SYS__ERRS) || defined(HAVE_SYS_ERRLIST)
|
||||||
#ifdef HAVE_SYS_ERRLIST
|
#ifdef HAVE_SYS_ERRLIST
|
||||||
if (err >= 0 && err < sys_nerr && sys_errlist[err] != NULL)
|
if (err >= 0 && err < sys_nerr && sys_errlist[err] != NULL) {
|
||||||
{
|
|
||||||
return sys_errlist[err];
|
return sys_errlist[err];
|
||||||
}
|
}
|
||||||
#elif defined(HAVE__SYS__ERRS)
|
#elif defined(HAVE__SYS__ERRS)
|
||||||
|
@ -342,15 +289,15 @@ const char *safe_strerror(int err)
|
||||||
extern int _sys_num_err;
|
extern int _sys_num_err;
|
||||||
|
|
||||||
if (err >= 0 && err < _sys_num_err) {
|
if (err >= 0 && err < _sys_num_err) {
|
||||||
return &_sys_errs[_sys_index[err]];
|
return &_sys_errs[_sys_index[err]];
|
||||||
}
|
}
|
||||||
#endif // either HAVE__SYS__ERRS or HAVE_SYS_ERRLIST
|
#endif // either HAVE__SYS__ERRS or HAVE_SYS_ERRLIST
|
||||||
else
|
else
|
||||||
#endif // defined(HAVE__SYS__ERRS) || defined(HAVE_SYS_ERRLIST)
|
#endif // defined(HAVE__SYS__ERRS) || defined(HAVE_SYS_ERRLIST)
|
||||||
{
|
{
|
||||||
int saved_err = errno;
|
int saved_err = errno;
|
||||||
|
|
||||||
/* Use a shared buffer for this case */
|
// Use a shared buffer for this case.
|
||||||
static char buff[384];
|
static char buff[384];
|
||||||
char errnum_buff[64];
|
char errnum_buff[64];
|
||||||
format_long_safe(errnum_buff, err);
|
format_long_safe(errnum_buff, err);
|
||||||
|
@ -365,16 +312,14 @@ const char *safe_strerror(int err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void safe_perror(const char *message)
|
void safe_perror(const char *message) {
|
||||||
{
|
// Note we cannot use strerror, because on Linux it uses gettext, which is not safe.
|
||||||
// Note we cannot use strerror, because on Linux it uses gettext, which is not safe
|
|
||||||
int err = errno;
|
int err = errno;
|
||||||
|
|
||||||
char buff[384];
|
char buff[384];
|
||||||
buff[0] = '\0';
|
buff[0] = '\0';
|
||||||
|
|
||||||
if (message)
|
if (message) {
|
||||||
{
|
|
||||||
safe_append(buff, message, sizeof buff);
|
safe_append(buff, message, sizeof buff);
|
||||||
safe_append(buff, ": ", sizeof buff);
|
safe_append(buff, ": ", sizeof buff);
|
||||||
}
|
}
|
||||||
|
@ -387,23 +332,18 @@ void safe_perror(const char *message)
|
||||||
|
|
||||||
#ifdef HAVE_REALPATH_NULL
|
#ifdef HAVE_REALPATH_NULL
|
||||||
|
|
||||||
wchar_t *wrealpath(const wcstring &pathname, wchar_t *resolved_path)
|
wchar_t *wrealpath(const wcstring &pathname, wchar_t *resolved_path) {
|
||||||
{
|
|
||||||
cstring narrow_path = wcs2string(pathname);
|
cstring narrow_path = wcs2string(pathname);
|
||||||
char *narrow_res = realpath(narrow_path.c_str(), NULL);
|
char *narrow_res = realpath(narrow_path.c_str(), NULL);
|
||||||
|
|
||||||
if (!narrow_res)
|
if (!narrow_res) return NULL;
|
||||||
return NULL;
|
|
||||||
|
|
||||||
wchar_t *res;
|
wchar_t *res;
|
||||||
wcstring wide_res = str2wcstring(narrow_res);
|
wcstring wide_res = str2wcstring(narrow_res);
|
||||||
if (resolved_path)
|
if (resolved_path) {
|
||||||
{
|
|
||||||
wcslcpy(resolved_path, wide_res.c_str(), PATH_MAX);
|
wcslcpy(resolved_path, wide_res.c_str(), PATH_MAX);
|
||||||
res = resolved_path;
|
res = resolved_path;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
res = wcsdup(wide_res.c_str());
|
res = wcsdup(wide_res.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -414,24 +354,19 @@ wchar_t *wrealpath(const wcstring &pathname, wchar_t *resolved_path)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
wchar_t *wrealpath(const wcstring &pathname, wchar_t *resolved_path)
|
wchar_t *wrealpath(const wcstring &pathname, wchar_t *resolved_path) {
|
||||||
{
|
|
||||||
cstring tmp = wcs2string(pathname);
|
cstring tmp = wcs2string(pathname);
|
||||||
char narrow_buff[PATH_MAX];
|
char narrow_buff[PATH_MAX];
|
||||||
char *narrow_res = realpath(tmp.c_str(), narrow_buff);
|
char *narrow_res = realpath(tmp.c_str(), narrow_buff);
|
||||||
wchar_t *res;
|
wchar_t *res;
|
||||||
|
|
||||||
if (!narrow_res)
|
if (!narrow_res) return 0;
|
||||||
return 0;
|
|
||||||
|
|
||||||
const wcstring wide_res = str2wcstring(narrow_res);
|
const wcstring wide_res = str2wcstring(narrow_res);
|
||||||
if (resolved_path)
|
if (resolved_path) {
|
||||||
{
|
|
||||||
wcslcpy(resolved_path, wide_res.c_str(), PATH_MAX);
|
wcslcpy(resolved_path, wide_res.c_str(), PATH_MAX);
|
||||||
res = resolved_path;
|
res = resolved_path;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
res = wcsdup(wide_res.c_str());
|
res = wcsdup(wide_res.c_str());
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
@ -439,9 +374,7 @@ wchar_t *wrealpath(const wcstring &pathname, wchar_t *resolved_path)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
wcstring wdirname(const wcstring &path) {
|
||||||
wcstring wdirname(const wcstring &path)
|
|
||||||
{
|
|
||||||
char *tmp = wcs2str(path.c_str());
|
char *tmp = wcs2str(path.c_str());
|
||||||
char *narrow_res = dirname(tmp);
|
char *narrow_res = dirname(tmp);
|
||||||
wcstring result = format_string(L"%s", narrow_res);
|
wcstring result = format_string(L"%s", narrow_res);
|
||||||
|
@ -449,8 +382,7 @@ wcstring wdirname(const wcstring &path)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
wcstring wbasename(const wcstring &path)
|
wcstring wbasename(const wcstring &path) {
|
||||||
{
|
|
||||||
char *tmp = wcs2str(path.c_str());
|
char *tmp = wcs2str(path.c_str());
|
||||||
char *narrow_res = basename(tmp);
|
char *narrow_res = basename(tmp);
|
||||||
wcstring result = format_string(L"%s", narrow_res);
|
wcstring result = format_string(L"%s", narrow_res);
|
||||||
|
@ -458,29 +390,24 @@ wcstring wbasename(const wcstring &path)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Really init wgettext */
|
// Really init wgettext.
|
||||||
static void wgettext_really_init()
|
static void wgettext_really_init() {
|
||||||
{
|
|
||||||
pthread_mutex_init(&wgettext_lock, NULL);
|
pthread_mutex_init(&wgettext_lock, NULL);
|
||||||
fish_bindtextdomain(PACKAGE_NAME, LOCALEDIR);
|
fish_bindtextdomain(PACKAGE_NAME, LOCALEDIR);
|
||||||
fish_textdomain(PACKAGE_NAME);
|
fish_textdomain(PACKAGE_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/// For wgettext: Internal init function. Automatically called when a translation is first
|
||||||
For wgettext: Internal init function. Automatically called when a translation is first requested.
|
/// requested.
|
||||||
*/
|
static void wgettext_init_if_necessary() {
|
||||||
static void wgettext_init_if_necessary()
|
|
||||||
{
|
|
||||||
static pthread_once_t once = PTHREAD_ONCE_INIT;
|
static pthread_once_t once = PTHREAD_ONCE_INIT;
|
||||||
pthread_once(&once, wgettext_really_init);
|
pthread_once(&once, wgettext_really_init);
|
||||||
}
|
}
|
||||||
|
|
||||||
const wchar_t *wgettext(const wchar_t *in)
|
const wchar_t *wgettext(const wchar_t *in) {
|
||||||
{
|
if (!in) return in;
|
||||||
if (!in)
|
|
||||||
return in;
|
|
||||||
|
|
||||||
// preserve errno across this since this is often used in printing error messages
|
// Preserve errno across this since this is often used in printing error messages.
|
||||||
int err = errno;
|
int err = errno;
|
||||||
|
|
||||||
wgettext_init_if_necessary();
|
wgettext_init_if_necessary();
|
||||||
|
@ -489,59 +416,51 @@ const wchar_t *wgettext(const wchar_t *in)
|
||||||
scoped_lock lock(wgettext_lock);
|
scoped_lock lock(wgettext_lock);
|
||||||
|
|
||||||
wcstring &val = wgettext_map[key];
|
wcstring &val = wgettext_map[key];
|
||||||
if (val.empty())
|
if (val.empty()) {
|
||||||
{
|
|
||||||
cstring mbs_in = wcs2string(key);
|
cstring mbs_in = wcs2string(key);
|
||||||
char *out = fish_gettext(mbs_in.c_str());
|
char *out = fish_gettext(mbs_in.c_str());
|
||||||
val = format_string(L"%s", out);
|
val = format_string(L"%s", out);
|
||||||
}
|
}
|
||||||
errno = err;
|
errno = err;
|
||||||
|
|
||||||
// The returned string is stored in the map
|
// The returned string is stored in the map.
|
||||||
// TODO: If we want to shrink the map, this would be a problem
|
// TODO: If we want to shrink the map, this would be a problem.
|
||||||
return val.c_str();
|
return val.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
int wmkdir(const wcstring &name, int mode)
|
int wmkdir(const wcstring &name, int mode) {
|
||||||
{
|
|
||||||
cstring name_narrow = wcs2string(name);
|
cstring name_narrow = wcs2string(name);
|
||||||
return mkdir(name_narrow.c_str(), mode);
|
return mkdir(name_narrow.c_str(), mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
int wrename(const wcstring &old, const wcstring &newv)
|
int wrename(const wcstring &old, const wcstring &newv) {
|
||||||
{
|
|
||||||
cstring old_narrow = wcs2string(old);
|
cstring old_narrow = wcs2string(old);
|
||||||
cstring new_narrow =wcs2string(newv);
|
cstring new_narrow = wcs2string(newv);
|
||||||
return rename(old_narrow.c_str(), new_narrow.c_str());
|
return rename(old_narrow.c_str(), new_narrow.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
int fish_wcstoi(const wchar_t *str, wchar_t ** endptr, int base)
|
int fish_wcstoi(const wchar_t *str, wchar_t **endptr, int base) {
|
||||||
{
|
|
||||||
long ret = wcstol(str, endptr, base);
|
long ret = wcstol(str, endptr, base);
|
||||||
if (ret > INT_MAX)
|
if (ret > INT_MAX) {
|
||||||
{
|
|
||||||
ret = INT_MAX;
|
ret = INT_MAX;
|
||||||
errno = ERANGE;
|
errno = ERANGE;
|
||||||
}
|
} else if (ret < INT_MIN) {
|
||||||
else if (ret < INT_MIN)
|
|
||||||
{
|
|
||||||
ret = INT_MIN;
|
ret = INT_MIN;
|
||||||
errno = ERANGE;
|
errno = ERANGE;
|
||||||
}
|
}
|
||||||
return (int)ret;
|
return (int)ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
file_id_t file_id_t::file_id_from_stat(const struct stat *buf)
|
file_id_t file_id_t::file_id_from_stat(const struct stat *buf) {
|
||||||
{
|
|
||||||
assert(buf != NULL);
|
assert(buf != NULL);
|
||||||
|
|
||||||
file_id_t result = {};
|
file_id_t result = {};
|
||||||
result.device = buf->st_dev;
|
result.device = buf->st_dev;
|
||||||
result.inode = buf->st_ino;
|
result.inode = buf->st_ino;
|
||||||
result.size = buf->st_size;
|
result.size = buf->st_size;
|
||||||
result.change_seconds = buf->st_ctime;
|
result.change_seconds = buf->st_ctime;
|
||||||
result.mod_seconds = buf->st_mtime;
|
result.mod_seconds = buf->st_mtime;
|
||||||
|
|
||||||
#if STAT_HAVE_NSEC
|
#if STAT_HAVE_NSEC
|
||||||
result.change_nanoseconds = buf->st_ctime_nsec;
|
result.change_nanoseconds = buf->st_ctime_nsec;
|
||||||
result.mod_nanoseconds = buf->st_mtime_nsec;
|
result.mod_nanoseconds = buf->st_mtime_nsec;
|
||||||
|
@ -555,74 +474,53 @@ file_id_t file_id_t::file_id_from_stat(const struct stat *buf)
|
||||||
result.change_nanoseconds = 0;
|
result.change_nanoseconds = 0;
|
||||||
result.mod_nanoseconds = 0;
|
result.mod_nanoseconds = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file_id_t file_id_for_fd(int fd) {
|
||||||
file_id_t file_id_for_fd(int fd)
|
|
||||||
{
|
|
||||||
file_id_t result = kInvalidFileID;
|
file_id_t result = kInvalidFileID;
|
||||||
struct stat buf = {};
|
struct stat buf = {};
|
||||||
if (0 == fstat(fd, &buf))
|
if (0 == fstat(fd, &buf)) {
|
||||||
{
|
|
||||||
result = file_id_t::file_id_from_stat(&buf);
|
result = file_id_t::file_id_from_stat(&buf);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
file_id_t file_id_for_path(const wcstring &path)
|
file_id_t file_id_for_path(const wcstring &path) {
|
||||||
{
|
|
||||||
file_id_t result = kInvalidFileID;
|
file_id_t result = kInvalidFileID;
|
||||||
struct stat buf = {};
|
struct stat buf = {};
|
||||||
if (0 == wstat(path, &buf))
|
if (0 == wstat(path, &buf)) {
|
||||||
{
|
|
||||||
result = file_id_t::file_id_from_stat(&buf);
|
result = file_id_t::file_id_from_stat(&buf);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool file_id_t::operator==(const file_id_t &rhs) const
|
bool file_id_t::operator==(const file_id_t &rhs) const { return this->compare_file_id(rhs) == 0; }
|
||||||
{
|
|
||||||
return this->compare_file_id(rhs) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_id_t::operator!=(const file_id_t &rhs) const
|
bool file_id_t::operator!=(const file_id_t &rhs) const { return !(*this == rhs); }
|
||||||
{
|
|
||||||
return ! (*this == rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
int compare(T a, T b)
|
int compare(T a, T b) {
|
||||||
{
|
if (a < b) {
|
||||||
if (a < b)
|
|
||||||
{
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
} else if (a > b) {
|
||||||
else if (a > b)
|
|
||||||
{
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int file_id_t::compare_file_id(const file_id_t &rhs) const
|
int file_id_t::compare_file_id(const file_id_t &rhs) const {
|
||||||
{
|
// Compare each field, stopping when we get to a non-equal field.
|
||||||
/* Compare each field, stopping when we get to a non-equal field */
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
if (! ret) ret = compare(device, rhs.device);
|
if (!ret) ret = compare(device, rhs.device);
|
||||||
if (! ret) ret = compare(inode, rhs.inode);
|
if (!ret) ret = compare(inode, rhs.inode);
|
||||||
if (! ret) ret = compare(size, rhs.size);
|
if (!ret) ret = compare(size, rhs.size);
|
||||||
if (! ret) ret = compare(change_seconds, rhs.change_seconds);
|
if (!ret) ret = compare(change_seconds, rhs.change_seconds);
|
||||||
if (! ret) ret = compare(change_nanoseconds, rhs.change_nanoseconds);
|
if (!ret) ret = compare(change_nanoseconds, rhs.change_nanoseconds);
|
||||||
if (! ret) ret = compare(mod_seconds, rhs.mod_seconds);
|
if (!ret) ret = compare(mod_seconds, rhs.mod_seconds);
|
||||||
if (! ret) ret = compare(mod_nanoseconds, rhs.mod_nanoseconds);
|
if (!ret) ret = compare(mod_nanoseconds, rhs.mod_nanoseconds);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool file_id_t::operator<(const file_id_t &rhs) const { return this->compare_file_id(rhs) < 0; }
|
||||||
bool file_id_t::operator<(const file_id_t &rhs) const
|
|
||||||
{
|
|
||||||
return this->compare_file_id(rhs) < 0;
|
|
||||||
}
|
|
||||||
|
|
139
src/wutil.h
139
src/wutil.h
|
@ -1,141 +1,105 @@
|
||||||
/** \file wutil.h
|
// Prototypes for wide character equivalents of various standard unix functions.
|
||||||
|
|
||||||
Prototypes for wide character equivalents of various standard unix
|
|
||||||
functions.
|
|
||||||
*/
|
|
||||||
#ifndef FISH_WUTIL_H
|
#ifndef FISH_WUTIL_H
|
||||||
#define FISH_WUTIL_H
|
#define FISH_WUTIL_H
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
/**
|
/// Wide character version of fopen(). This sets CLO_EXEC.
|
||||||
Wide character version of fopen(). This sets CLO_EXEC.
|
|
||||||
*/
|
|
||||||
FILE *wfopen(const wcstring &path, const char *mode);
|
FILE *wfopen(const wcstring &path, const char *mode);
|
||||||
|
|
||||||
/** Sets CLO_EXEC on a given fd */
|
/// Sets CLO_EXEC on a given fd.
|
||||||
bool set_cloexec(int fd);
|
bool set_cloexec(int fd);
|
||||||
|
|
||||||
/** Wide character version of open() that also sets the close-on-exec flag (atomically when possible). */
|
/// Wide character version of open() that also sets the close-on-exec flag (atomically when
|
||||||
|
/// possible).
|
||||||
int wopen_cloexec(const wcstring &pathname, int flags, mode_t mode = 0);
|
int wopen_cloexec(const wcstring &pathname, int flags, mode_t mode = 0);
|
||||||
|
|
||||||
/** Mark an fd as nonblocking; returns errno or 0 on success */
|
/// Mark an fd as nonblocking; returns errno or 0 on success.
|
||||||
int make_fd_nonblocking(int fd);
|
int make_fd_nonblocking(int fd);
|
||||||
|
|
||||||
/** Mark an fd as blocking; returns errno or 0 on success */
|
/// Mark an fd as blocking; returns errno or 0 on success.
|
||||||
int make_fd_blocking(int fd);
|
int make_fd_blocking(int fd);
|
||||||
|
|
||||||
/** Wide character version of opendir(). Note that opendir() is guaranteed to set close-on-exec by POSIX (hooray). */
|
/// Wide character version of opendir(). Note that opendir() is guaranteed to set close-on-exec by
|
||||||
|
/// POSIX (hooray).
|
||||||
DIR *wopendir(const wcstring &name);
|
DIR *wopendir(const wcstring &name);
|
||||||
|
|
||||||
/**
|
/// Wide character version of stat().
|
||||||
Wide character version of stat().
|
|
||||||
*/
|
|
||||||
int wstat(const wcstring &file_name, struct stat *buf);
|
int wstat(const wcstring &file_name, struct stat *buf);
|
||||||
|
|
||||||
/**
|
/// Wide character version of lstat().
|
||||||
Wide character version of lstat().
|
|
||||||
*/
|
|
||||||
int lwstat(const wcstring &file_name, struct stat *buf);
|
int lwstat(const wcstring &file_name, struct stat *buf);
|
||||||
|
|
||||||
/**
|
/// Wide character version of access().
|
||||||
Wide character version of access().
|
|
||||||
*/
|
|
||||||
int waccess(const wcstring &pathname, int mode);
|
int waccess(const wcstring &pathname, int mode);
|
||||||
|
|
||||||
/**
|
/// Wide character version of unlink().
|
||||||
Wide character version of unlink().
|
|
||||||
*/
|
|
||||||
int wunlink(const wcstring &pathname);
|
int wunlink(const wcstring &pathname);
|
||||||
|
|
||||||
/**
|
/// Wide character version of perror().
|
||||||
Wide character version of perror().
|
|
||||||
*/
|
|
||||||
void wperror(const wchar_t *s);
|
void wperror(const wchar_t *s);
|
||||||
|
|
||||||
/**
|
/// Async-safe version of perror().
|
||||||
Async-safe version of perror().
|
|
||||||
*/
|
|
||||||
void safe_perror(const char *message);
|
void safe_perror(const char *message);
|
||||||
|
|
||||||
/**
|
/// Async-safe version of strerror().
|
||||||
Async-safe version of strerror().
|
|
||||||
*/
|
|
||||||
const char *safe_strerror(int err);
|
const char *safe_strerror(int err);
|
||||||
|
|
||||||
// Wide character version of getcwd().
|
/// Wide character version of getcwd().
|
||||||
const wcstring wgetcwd();
|
const wcstring wgetcwd();
|
||||||
|
|
||||||
/**
|
/// Wide character version of chdir().
|
||||||
Wide character version of chdir()
|
|
||||||
*/
|
|
||||||
int wchdir(const wcstring &dir);
|
int wchdir(const wcstring &dir);
|
||||||
|
|
||||||
/**
|
/// Wide character version of realpath function. Just like the GNU version of realpath, wrealpath
|
||||||
Wide character version of realpath function. Just like the GNU
|
/// will accept 0 as the value for the second argument, in which case the result will be allocated
|
||||||
version of realpath, wrealpath will accept 0 as the value for the
|
/// using malloc, and must be free'd by the user.
|
||||||
second argument, in which case the result will be allocated using
|
|
||||||
malloc, and must be free'd by the user.
|
|
||||||
*/
|
|
||||||
wchar_t *wrealpath(const wcstring &pathname, wchar_t *resolved_path);
|
wchar_t *wrealpath(const wcstring &pathname, wchar_t *resolved_path);
|
||||||
|
|
||||||
/**
|
/// Wide character version of readdir().
|
||||||
Wide character version of readdir()
|
|
||||||
*/
|
|
||||||
bool wreaddir(DIR *dir, std::wstring &out_name);
|
bool wreaddir(DIR *dir, std::wstring &out_name);
|
||||||
bool wreaddir_resolving(DIR *dir, const std::wstring &dir_path, std::wstring &out_name, bool *out_is_dir);
|
bool wreaddir_resolving(DIR *dir, const std::wstring &dir_path, std::wstring &out_name,
|
||||||
|
bool *out_is_dir);
|
||||||
|
|
||||||
/**
|
/// Like wreaddir, but skip items that are known to not be directories. If this requires a stat
|
||||||
Like wreaddir, but skip items that are known to not be directories.
|
/// (i.e. the file is a symlink), then return it. Note that this does not guarantee that everything
|
||||||
If this requires a stat (i.e. the file is a symlink), then return it.
|
/// returned is a directory, it's just an optimization for cases where we would check for
|
||||||
Note that this does not guarantee that everything returned is a directory,
|
/// directories anyways.
|
||||||
it's just an optimization for cases where we would check for directories anyways.
|
|
||||||
*/
|
|
||||||
bool wreaddir_for_dirs(DIR *dir, wcstring *out_name);
|
bool wreaddir_for_dirs(DIR *dir, wcstring *out_name);
|
||||||
|
|
||||||
/**
|
/// Wide character version of dirname().
|
||||||
Wide character version of dirname()
|
|
||||||
*/
|
|
||||||
std::wstring wdirname(const std::wstring &path);
|
std::wstring wdirname(const std::wstring &path);
|
||||||
|
|
||||||
/**
|
/// Wide character version of basename().
|
||||||
Wide character version of basename()
|
|
||||||
*/
|
|
||||||
std::wstring wbasename(const std::wstring &path);
|
std::wstring wbasename(const std::wstring &path);
|
||||||
|
|
||||||
/**
|
/// Wide character wrapper around the gettext function. For historic reasons, unlike the real
|
||||||
Wide character wrapper around the gettext function. For historic
|
/// gettext function, wgettext takes care of setting the correct domain, etc. using the textdomain
|
||||||
reasons, unlike the real gettext function, wgettext takes care of
|
/// and bindtextdomain functions. This should probably be moved out of wgettext, so that wgettext
|
||||||
setting the correct domain, etc. using the textdomain and
|
/// will be nothing more than a wrapper around gettext, like all other functions in this file.
|
||||||
bindtextdomain functions. This should probably be moved out of
|
|
||||||
wgettext, so that wgettext will be nothing more than a wrapper
|
|
||||||
around gettext, like all other functions in this file.
|
|
||||||
*/
|
|
||||||
const wchar_t *wgettext(const wchar_t *in);
|
const wchar_t *wgettext(const wchar_t *in);
|
||||||
|
|
||||||
/**
|
/// Wide character version of mkdir.
|
||||||
Wide character version of mkdir
|
|
||||||
*/
|
|
||||||
int wmkdir(const wcstring &dir, int mode);
|
int wmkdir(const wcstring &dir, int mode);
|
||||||
|
|
||||||
/**
|
/// Wide character version of rename.
|
||||||
Wide character version of rename
|
|
||||||
*/
|
|
||||||
int wrename(const wcstring &oldName, const wcstring &newName);
|
int wrename(const wcstring &oldName, const wcstring &newName);
|
||||||
|
|
||||||
/** Like wcstol(), but fails on a value outside the range of an int */
|
/// Like wcstol(), but fails on a value outside the range of an int.
|
||||||
int fish_wcstoi(const wchar_t *str, wchar_t ** endptr, int base);
|
int fish_wcstoi(const wchar_t *str, wchar_t **endptr, int base);
|
||||||
|
|
||||||
/** Class for representing a file's inode. We use this to detect and avoid symlink loops, among other things. While an inode / dev pair is sufficient to distinguish co-existing files, Linux seems to aggressively re-use inodes, so it cannot determine if a file has been deleted (ABA problem). Therefore we include richer information. */
|
/// Class for representing a file's inode. We use this to detect and avoid symlink loops, among
|
||||||
struct file_id_t
|
/// other things. While an inode / dev pair is sufficient to distinguish co-existing files, Linux
|
||||||
{
|
/// seems to aggressively re-use inodes, so it cannot determine if a file has been deleted (ABA
|
||||||
|
/// problem). Therefore we include richer information.
|
||||||
|
struct file_id_t {
|
||||||
dev_t device;
|
dev_t device;
|
||||||
ino_t inode;
|
ino_t inode;
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
|
@ -143,16 +107,16 @@ struct file_id_t
|
||||||
long change_nanoseconds;
|
long change_nanoseconds;
|
||||||
time_t mod_seconds;
|
time_t mod_seconds;
|
||||||
long mod_nanoseconds;
|
long mod_nanoseconds;
|
||||||
|
|
||||||
bool operator==(const file_id_t &rhs) const;
|
bool operator==(const file_id_t &rhs) const;
|
||||||
bool operator!=(const file_id_t &rhs) const;
|
bool operator!=(const file_id_t &rhs) const;
|
||||||
|
|
||||||
// Used to permit these as keys in std::map
|
// Used to permit these as keys in std::map.
|
||||||
bool operator<(const file_id_t &rhs) const;
|
bool operator<(const file_id_t &rhs) const;
|
||||||
|
|
||||||
static file_id_t file_id_from_stat(const struct stat *buf);
|
static file_id_t file_id_from_stat(const struct stat *buf);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int compare_file_id(const file_id_t &rhs) const;
|
int compare_file_id(const file_id_t &rhs) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -161,5 +125,4 @@ file_id_t file_id_for_path(const wcstring &path);
|
||||||
|
|
||||||
extern const file_id_t kInvalidFileID;
|
extern const file_id_t kInvalidFileID;
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue