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.
|
||||
|
||||
Contains datastructures such as automatically growing array lists, priority queues, etc.
|
||||
*/
|
||||
// Generic utilities library.
|
||||
//
|
||||
// Contains data structures such as automatically growing array lists, priority queues, etc.
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <wchar.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 "util.h"
|
||||
#include "common.h"
|
||||
#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(b, 0);
|
||||
|
||||
if (*a==0)
|
||||
{
|
||||
if (*b==0)
|
||||
return 0;
|
||||
if (*a == 0) {
|
||||
if (*b == 0) return 0;
|
||||
return -1;
|
||||
}
|
||||
if (*b==0)
|
||||
{
|
||||
if (*b == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
long secondary_diff=0;
|
||||
if (iswdigit(*a) && iswdigit(*b))
|
||||
{
|
||||
long secondary_diff = 0;
|
||||
if (iswdigit(*a) && iswdigit(*b)) {
|
||||
wchar_t *aend, *bend;
|
||||
long al;
|
||||
long bl;
|
||||
|
@ -43,53 +36,40 @@ int wcsfilecmp(const wchar_t *a, const wchar_t *b)
|
|||
al = wcstol(a, &aend, 10);
|
||||
bl = wcstol(b, &bend, 10);
|
||||
|
||||
if (errno)
|
||||
{
|
||||
/*
|
||||
Huuuuuuuuge numbers - fall back to regular string comparison
|
||||
*/
|
||||
if (errno) {
|
||||
// Huge numbers - fall back to regular string comparison.
|
||||
return wcscmp(a, b);
|
||||
}
|
||||
|
||||
diff = al - bl;
|
||||
if (diff)
|
||||
return diff > 0 ? 2 : -2;
|
||||
if (diff) return diff > 0 ? 2 : -2;
|
||||
|
||||
secondary_diff = (aend-a) - (bend-b);
|
||||
secondary_diff = (aend - a) - (bend - b);
|
||||
|
||||
a=aend-1;
|
||||
b=bend-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
a = aend - 1;
|
||||
b = bend - 1;
|
||||
} else {
|
||||
int diff = towlower(*a) - towlower(*b);
|
||||
if (diff != 0)
|
||||
return (diff>0)?2:-2;
|
||||
if (diff != 0) 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)
|
||||
{
|
||||
/*
|
||||
No primary difference in rest of string.
|
||||
Use secondary difference on this element if found.
|
||||
*/
|
||||
if (secondary_diff)
|
||||
{
|
||||
return secondary_diff > 0 ? 1 :-1;
|
||||
if (abs(res) < 2) {
|
||||
// No primary difference in rest of string. Use secondary difference on this element if
|
||||
// found.
|
||||
if (secondary_diff) {
|
||||
return secondary_diff > 0 ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
long long get_time()
|
||||
{
|
||||
long long get_time() {
|
||||
struct timeval time_struct;
|
||||
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
|
||||
#define FISH_UTIL_H
|
||||
|
||||
/**
|
||||
Returns the larger of two ints
|
||||
*/
|
||||
template<typename T>
|
||||
inline T maxi(T a, T b)
|
||||
{
|
||||
return a>b?a:b;
|
||||
/// Returns the larger of two ints.
|
||||
template <typename T>
|
||||
inline T maxi(T a, T b) {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the smaller of two ints
|
||||
*/
|
||||
template<typename T>
|
||||
inline T mini(T a, T b)
|
||||
{
|
||||
return a<b?a:b;
|
||||
/// Returns the smaller of two ints.
|
||||
template <typename T>
|
||||
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 to order strings in a way which is intuitive to
|
||||
humans with regards to sorting strings containing numbers.
|
||||
|
||||
Most sorting functions would sort the strings 'file1.txt'
|
||||
'file5.txt' and 'file12.txt' as:
|
||||
|
||||
file1.txt
|
||||
file12.txt
|
||||
file5.txt
|
||||
|
||||
This function regards any sequence of digits as a single entity
|
||||
when performing comparisons, so the output is instead:
|
||||
|
||||
file1.txt
|
||||
file5.txt
|
||||
file12.txt
|
||||
|
||||
Which most people would find more intuitive.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
*/
|
||||
/// Compares two wide character strings with an (arguably) intuitive ordering. This function tries
|
||||
/// to order strings in a way which is intuitive to humans with regards to sorting strings
|
||||
/// containing numbers.
|
||||
///
|
||||
/// Most sorting functions would sort the strings 'file1.txt' 'file5.txt' and 'file12.txt' as:
|
||||
///
|
||||
/// file1.txt
|
||||
/// file12.txt
|
||||
/// file5.txt
|
||||
///
|
||||
/// This function regards any sequence of digits as a single entity when performing comparisons, so
|
||||
/// the output is instead:
|
||||
///
|
||||
/// file1.txt
|
||||
/// file5.txt
|
||||
/// file12.txt
|
||||
///
|
||||
/// Which most people would find more intuitive.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// 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);
|
||||
|
||||
/**
|
||||
Get the current time in microseconds since Jan 1, 1970
|
||||
*/
|
||||
/// Get the current time in microseconds since Jan 1, 1970.
|
||||
long long get_time();
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,24 +1,18 @@
|
|||
/** \file wcstringutil.cpp
|
||||
|
||||
Helper functions for working with wcstring
|
||||
*/
|
||||
#include "common.h"
|
||||
// Helper functions for working with wcstring.
|
||||
#include "wcstringutil.h"
|
||||
#include "common.h"
|
||||
|
||||
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;
|
||||
if (pos != wcstring::npos && last.second != wcstring::npos) pos += last.second;
|
||||
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);
|
||||
}
|
||||
|
||||
if (needle.empty())
|
||||
{
|
||||
if (needle.empty()) {
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
str[next_pos] = L'\0';
|
||||
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
|
||||
#define FISH_WCSTRINGUTIL_H
|
||||
|
||||
|
@ -10,21 +7,19 @@ Helper functions for working with wcstring
|
|||
|
||||
#include "common.h"
|
||||
|
||||
/**
|
||||
typedef that represents a range in a wcstring.
|
||||
The first element is the location, the second is the count.
|
||||
*/
|
||||
/// Typedef that represents a range in a wcstring. The first element is the location, the second is
|
||||
/// the count.
|
||||
typedef std::pair<wcstring::size_type, wcstring::size_type> wcstring_range;
|
||||
|
||||
/**
|
||||
wcstring equivalent of wcstok(). Supports NUL.
|
||||
For convenience and wcstok() compatibility, the first character of each
|
||||
token separator is replaced with NUL.
|
||||
Returns a pair of (pos, count).
|
||||
Returns (npos, npos) when it's done.
|
||||
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).
|
||||
*/
|
||||
wcstring_range wcstring_tok(wcstring& str, const wcstring &needle, wcstring_range last = wcstring_range(0,0));
|
||||
/// wcstring equivalent of wcstok(). Supports NUL. For convenience and wcstok() compatibility, the
|
||||
/// first character of each token separator is replaced with NUL.
|
||||
///
|
||||
/// Returns a pair of (pos, count).
|
||||
/// Returns (npos, npos) when it's done.
|
||||
/// 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).
|
||||
wcstring_range wcstring_tok(wcstring& str, const wcstring& needle,
|
||||
wcstring_range last = wcstring_range(0, 0));
|
||||
|
||||
#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.
|
||||
|
||||
This is simply the gnu getopt library, but converted for use with
|
||||
wchar_t instead of char. This is not usually useful since the argv
|
||||
array is always defined to be of type char**, but in fish, all
|
||||
internal commands use wide characters and hence this library is
|
||||
useful.
|
||||
|
||||
If you want to use this version of getopt in your program,
|
||||
download the fish sourcecode, 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 all the
|
||||
regular getopt functions, prefixing every function, global
|
||||
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. */
|
||||
// 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
|
||||
// is not usually useful since the argv array is always defined to be of type char**, but in fish,
|
||||
// all internal commands use wide characters and hence this library is useful.
|
||||
//
|
||||
// If you want to use this version of getopt in your program, download the fish sourcecode,
|
||||
// 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
|
||||
// all the regular getopt functions, prefixing every function, global 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.
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
/* This needs to come after some library #include
|
||||
to get __GNU_LIBRARY__ defined. */
|
||||
#ifdef __GNU_LIBRARY__
|
||||
/* Don't include stdlib.h for non-GNU C libraries because some of them
|
||||
contain conflicting prototypes for getopt. */
|
||||
// This needs to come after some library #include to get __GNU_LIBRARY__ defined.
|
||||
#ifdef __GNU_LIBRARY__
|
||||
// Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting
|
||||
// prototypes for getopt.
|
||||
#include <stdlib.h>
|
||||
#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. */
|
||||
#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.
|
||||
#include "common.h"
|
||||
#include "fallback.h" // IWYU pragma: keep
|
||||
#include "wgetopt.h"
|
||||
#include "wutil.h" // IWYU pragma: keep
|
||||
#include "fallback.h" // IWYU pragma: keep
|
||||
|
||||
/**
|
||||
Use translation functions if available
|
||||
*/
|
||||
// Use translation functions if available.
|
||||
#ifdef _
|
||||
#undef _
|
||||
#endif
|
||||
|
@ -94,229 +77,178 @@
|
|||
#define _(wstr) wstr
|
||||
#endif
|
||||
|
||||
#ifdef __GNU_LIBRARY__
|
||||
/* We want to avoid inclusion of string.h with non-GNU libraries
|
||||
because there are many ways it can cause trouble.
|
||||
On some systems, it contains special magic macros that don't work
|
||||
in GCC. */
|
||||
#include <string.h> // IWYU pragma: keep
|
||||
#define my_index wcschr
|
||||
#ifdef __GNU_LIBRARY__
|
||||
// We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can
|
||||
// cause trouble. On some systems, it contains special magic macros that don't work in GCC.
|
||||
#include <string.h> // IWYU pragma: keep
|
||||
#define my_index wcschr
|
||||
#else
|
||||
|
||||
/* Avoid depending on library functions or files
|
||||
whose names are inconsistent. */
|
||||
// Avoid depending on library functions or files whose names are inconsistent.
|
||||
|
||||
char *getenv();
|
||||
|
||||
static wchar_t *
|
||||
my_index(const wchar_t *str, int chr)
|
||||
{
|
||||
while (*str)
|
||||
{
|
||||
if (*str == chr)
|
||||
return (wchar_t *) str;
|
||||
static wchar_t *my_index(const wchar_t *str, int chr) {
|
||||
while (*str) {
|
||||
if (*str == chr) return (wchar_t *)str;
|
||||
str++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If using GCC, we can safely declare strlen this way.
|
||||
If not using GCC, it is ok not to declare it. */
|
||||
// If using GCC, we can safely declare strlen this way. If not using GCC, it is ok not to declare
|
||||
// it.
|
||||
#ifdef __GNUC__
|
||||
/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
|
||||
That was relevant to code that was here before. */
|
||||
#if !defined (__STDC__) || !__STDC__
|
||||
/* gcc with -traditional declares the built-in strlen to return int,
|
||||
and has done so at least since version 2.4.5. -- rms. */
|
||||
// Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. That was relevant to code that
|
||||
// was here before.
|
||||
#if !defined(__STDC__) || !__STDC__
|
||||
// gcc with -traditional declares the built-in strlen to return int, and has done so at least since
|
||||
// version 2.4.5. -- rms.
|
||||
extern int wcslen(const wchar_t *);
|
||||
#endif /* not __STDC__ */
|
||||
#endif /* __GNUC__ */
|
||||
#endif // not __STDC__
|
||||
#endif // __GNUC__
|
||||
|
||||
#endif /* not __GNU_LIBRARY__ */
|
||||
#endif // not __GNU_LIBRARY__
|
||||
|
||||
|
||||
/* Exchange two adjacent subsequences of ARGV.
|
||||
One subsequence is elements [first_nonopt,last_nonopt)
|
||||
which contains all the non-options that have been skipped so far.
|
||||
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. */
|
||||
|
||||
void wgetopter_t::exchange(wchar_t **argv)
|
||||
{
|
||||
// Exchange two adjacent subsequences of ARGV. One subsequence is elements
|
||||
// [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. 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.
|
||||
void wgetopter_t::exchange(wchar_t **argv) {
|
||||
int bottom = first_nonopt;
|
||||
int middle = last_nonopt;
|
||||
int top = woptind;
|
||||
wchar_t *tem;
|
||||
|
||||
/* Exchange the shorter segment with the far end of the longer segment.
|
||||
That puts the shorter segment into the right place.
|
||||
It leaves the longer segment in the right place overall,
|
||||
but it consists of two parts that need to be swapped next. */
|
||||
// Exchange the shorter segment with the far end of the longer segment. That puts the shorter
|
||||
// segment into the right place. It leaves the longer segment in the right place overall, but it
|
||||
// consists of two parts that need to be swapped next.
|
||||
|
||||
while (top > middle && middle > bottom)
|
||||
{
|
||||
if (top - middle > middle - bottom)
|
||||
{
|
||||
/* Bottom segment is the short one. */
|
||||
while (top > middle && middle > bottom) {
|
||||
if (top - middle > middle - bottom) {
|
||||
// Bottom segment is the short one.
|
||||
int len = middle - bottom;
|
||||
int i;
|
||||
|
||||
/* Swap it with the top part of the top segment. */
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
// Swap it with the top part of the top segment.
|
||||
for (i = 0; i < len; i++) {
|
||||
tem = argv[bottom + i];
|
||||
argv[bottom + i] = argv[top - (middle - bottom) + i];
|
||||
argv[top - (middle - bottom) + i] = tem;
|
||||
}
|
||||
/* Exclude the moved bottom segment from further swapping. */
|
||||
// Exclude the moved bottom segment from further swapping.
|
||||
top -= len;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Top segment is the short one. */
|
||||
} else {
|
||||
// Top segment is the short one.
|
||||
int len = top - middle;
|
||||
int i;
|
||||
|
||||
/* Swap it with the bottom part of the bottom segment. */
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
// Swap it with the bottom part of the bottom segment.
|
||||
for (i = 0; i < len; i++) {
|
||||
tem = argv[bottom + i];
|
||||
argv[bottom + i] = argv[middle + i];
|
||||
argv[middle + i] = tem;
|
||||
}
|
||||
/* Exclude the moved top segment from further swapping. */
|
||||
// Exclude the moved top segment from further swapping.
|
||||
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);
|
||||
last_nonopt = woptind;
|
||||
}
|
||||
|
||||
/* Initialize the internal data when the first call is made. */
|
||||
|
||||
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. */
|
||||
|
||||
// Initialize the internal data when the first call is made.
|
||||
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.
|
||||
first_nonopt = last_nonopt = woptind = 1;
|
||||
|
||||
nextchar = NULL;
|
||||
|
||||
/* Determine how to handle the ordering of options and nonoptions. */
|
||||
|
||||
if (optstring[0] == '-')
|
||||
{
|
||||
// Determine how to handle the ordering of options and nonoptions.
|
||||
if (optstring[0] == '-') {
|
||||
ordering = RETURN_IN_ORDER;
|
||||
++optstring;
|
||||
}
|
||||
else if (optstring[0] == '+')
|
||||
{
|
||||
} else if (optstring[0] == '+') {
|
||||
ordering = REQUIRE_ORDER;
|
||||
++optstring;
|
||||
}
|
||||
else
|
||||
} else
|
||||
ordering = PERMUTE;
|
||||
|
||||
return optstring;
|
||||
}
|
||||
|
||||
/* Scan elements of ARGV (whose length is ARGC) for option characters
|
||||
given in OPTSTRING.
|
||||
|
||||
If an element of ARGV starts with '-', and is not exactly "-" or "--",
|
||||
then it is an option element. The characters of this element
|
||||
(aside from the initial '-') are option characters. If `getopt'
|
||||
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 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 that those that are not options now come last.)
|
||||
|
||||
OPTSTRING is a string containing the legitimate option characters.
|
||||
If an option character is seen 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 '?'.
|
||||
|
||||
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
|
||||
ARGV-element, is returned in `optarg'. 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 OPTSTRING starts with `-' or `+', it requests different methods of
|
||||
handling the non-option ARGV-elements.
|
||||
See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
|
||||
|
||||
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, it follows the option name in the same ARGV-element, separated
|
||||
from the option name by a `=', or else the in next ARGV-element.
|
||||
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 the `flag' field is zero.
|
||||
|
||||
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)
|
||||
{
|
||||
// Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING.
|
||||
//
|
||||
// If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option
|
||||
// element. The characters of this element (aside from the initial '-') are option characters. If
|
||||
// `getopt' 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
|
||||
// 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
|
||||
// that those that are not options now come last.)
|
||||
//
|
||||
// OPTSTRING is a string containing the legitimate option characters. If an option character is seen
|
||||
// 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 '?'.
|
||||
//
|
||||
// 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 ARGV-element, is returned in `optarg'.
|
||||
// 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 OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option
|
||||
// ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
|
||||
//
|
||||
// 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,
|
||||
// it follows the option name in the same ARGV-element, separated from the option name by a `=', or
|
||||
// else the in next ARGV-element. 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 the `flag' field is
|
||||
// zero.
|
||||
//
|
||||
// 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;
|
||||
|
||||
if (woptind == 0)
|
||||
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 (woptind == 0) 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 (first_nonopt != last_nonopt && last_nonopt != woptind)
|
||||
exchange(argv);
|
||||
else if (last_nonopt != woptind)
|
||||
first_nonopt = woptind;
|
||||
|
||||
/* Skip any additional non-options
|
||||
and extend the range of non-options previously skipped. */
|
||||
|
||||
while (woptind < argc
|
||||
&& (argv[woptind][0] != '-' || argv[woptind][1] == '\0'))
|
||||
// Skip any additional non-options and extend the range of non-options previously
|
||||
// skipped.
|
||||
while (woptind < argc && (argv[woptind][0] != '-' || argv[woptind][1] == '\0'))
|
||||
woptind++;
|
||||
last_nonopt = woptind;
|
||||
}
|
||||
|
||||
/* The special ARGV-element `--' means premature end of options.
|
||||
Skip it like a null option,
|
||||
then exchange with previous non-options as if it were an option,
|
||||
then skip everything else like a non-option. */
|
||||
|
||||
if (woptind != argc && !wcscmp(argv[woptind], L"--"))
|
||||
{
|
||||
// The special ARGV-element `--' means premature end of options. Skip it like a null option,
|
||||
// then exchange with previous non-options as if it were an option, then skip everything
|
||||
// else like a non-option.
|
||||
if (woptind != argc && !wcscmp(argv[woptind], L"--")) {
|
||||
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;
|
||||
}
|
||||
|
||||
/* If we have done all the ARGV-elements, stop the scan
|
||||
and back over any non-options that we skipped and permuted. */
|
||||
// If we have done all the ARGV-elements, stop the scan and back over any non-options that
|
||||
// we skipped and permuted.
|
||||
|
||||
if (woptind == argc)
|
||||
{
|
||||
/* Set the next-arg-index to point at the non-options
|
||||
that we previously skipped, so the caller will digest them. */
|
||||
if (first_nonopt != last_nonopt)
|
||||
woptind = first_nonopt;
|
||||
if (woptind == argc) {
|
||||
// Set the next-arg-index to point at the non-options that we previously skipped, so the
|
||||
// caller will digest them.
|
||||
if (first_nonopt != last_nonopt) woptind = first_nonopt;
|
||||
return EOF;
|
||||
}
|
||||
|
||||
/* If we have come to a non-option and did not permute it,
|
||||
either stop the scan or describe it to the caller and pass it by. */
|
||||
|
||||
if ((argv[woptind][0] != '-' || argv[woptind][1] == '\0'))
|
||||
{
|
||||
if (ordering == REQUIRE_ORDER)
|
||||
return EOF;
|
||||
// If we have come to a non-option and did not permute it, either stop the scan or describe
|
||||
// it to the caller and pass it by.
|
||||
if ((argv[woptind][0] != '-' || argv[woptind][1] == '\0')) {
|
||||
if (ordering == REQUIRE_ORDER) return EOF;
|
||||
woptarg = argv[woptind++];
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* We have found another option-ARGV-element.
|
||||
Skip the initial punctuation. */
|
||||
|
||||
nextchar = (argv[woptind] + 1
|
||||
+ (longopts != NULL && argv[woptind][1] == '-'));
|
||||
// We have found another option-ARGV-element. Skip the initial punctuation.
|
||||
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.
|
||||
|
||||
If long_only and the ARGV-element has the form "-f", where f is
|
||||
a valid short option, don't consider it an abbreviated form of
|
||||
a long option that starts with f. Otherwise there would be no
|
||||
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 consider that an abbreviation of
|
||||
the long option, just like "--fu", and not "-f" with arg "u".
|
||||
|
||||
This distinction seems to be the most useful approach. */
|
||||
|
||||
if (longopts != NULL
|
||||
&& (argv[woptind][1] == '-'
|
||||
|| (long_only && (argv[woptind][2] || !my_index(optstring, argv[woptind][1])))))
|
||||
{
|
||||
// Check whether the ARGV-element is a long option.
|
||||
//
|
||||
// If long_only and the ARGV-element has the form "-f", where f is a valid short option, don't
|
||||
// consider it an abbreviated form of a long option that starts with f. Otherwise there would
|
||||
// be no 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
|
||||
// consider that an abbreviation of the long option, just like "--fu", and not "-f" with arg
|
||||
// "u".
|
||||
//
|
||||
// This distinction seems to be the most useful approach.
|
||||
if (longopts != NULL &&
|
||||
(argv[woptind][1] == '-' ||
|
||||
(long_only && (argv[woptind][2] || !my_index(optstring, argv[woptind][1]))))) {
|
||||
wchar_t *nameend;
|
||||
const struct woption *p;
|
||||
const struct woption *pfound = NULL;
|
||||
int exact = 0;
|
||||
int ambig = 0;
|
||||
int indfound = 0; /* set to zero by Anton */
|
||||
int indfound = 0; // set to zero by Anton
|
||||
int option_index;
|
||||
|
||||
for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
|
||||
/* Do nothing. */ ;
|
||||
for (nameend = nextchar; *nameend && *nameend != '='; nameend++) /* Do nothing. */;
|
||||
|
||||
/* Test all long options for either exact match
|
||||
or abbreviated matches. */
|
||||
// Test all long options for either exact match or abbreviated matches.
|
||||
for (p = longopts, option_index = 0; p->name; p++, option_index++)
|
||||
if (!wcsncmp(p->name, nextchar, nameend - nextchar))
|
||||
{
|
||||
if ((unsigned int)(nameend - nextchar) == (unsigned int)wcslen(p->name))
|
||||
{
|
||||
/* Exact match found. */
|
||||
if (!wcsncmp(p->name, nextchar, nameend - nextchar)) {
|
||||
if ((unsigned int)(nameend - nextchar) == (unsigned int)wcslen(p->name)) {
|
||||
// Exact match found.
|
||||
pfound = p;
|
||||
indfound = option_index;
|
||||
exact = 1;
|
||||
break;
|
||||
}
|
||||
else if (pfound == NULL)
|
||||
{
|
||||
/* First nonexact match found. */
|
||||
} else if (pfound == NULL) {
|
||||
// First nonexact match found.
|
||||
pfound = p;
|
||||
indfound = option_index;
|
||||
}
|
||||
else
|
||||
/* Second or later nonexact match found. */
|
||||
} else
|
||||
// Second or later nonexact match found.
|
||||
ambig = 1;
|
||||
}
|
||||
|
||||
if (ambig && !exact)
|
||||
{
|
||||
if (ambig && !exact) {
|
||||
if (wopterr)
|
||||
fwprintf(stderr, _(L"%ls: Option '%ls' is ambiguous\n"),
|
||||
argv[0], argv[woptind]);
|
||||
fwprintf(stderr, _(L"%ls: Option '%ls' is ambiguous\n"), argv[0], argv[woptind]);
|
||||
nextchar += wcslen(nextchar);
|
||||
woptind++;
|
||||
return '?';
|
||||
}
|
||||
|
||||
if (pfound != NULL)
|
||||
{
|
||||
if (pfound != NULL) {
|
||||
option_index = indfound;
|
||||
woptind++;
|
||||
if (*nameend)
|
||||
{
|
||||
/* Don't test has_arg with >, because some C compilers don't
|
||||
allow it to be used on enums. */
|
||||
if (*nameend) {
|
||||
// Don't test has_arg with >, because some C compilers don't allow it to be used on
|
||||
// enums.
|
||||
if (pfound->has_arg)
|
||||
woptarg = nameend + 1;
|
||||
else
|
||||
{
|
||||
if (wopterr)
|
||||
{
|
||||
if (argv[woptind - 1][1] == '-')
|
||||
/* --option */
|
||||
fwprintf(stderr,
|
||||
_(L"%ls: Option '--%ls' doesn't allow an argument\n"),
|
||||
else {
|
||||
if (wopterr) {
|
||||
if (argv[woptind - 1][1] == '-') // --option
|
||||
fwprintf(stderr, _(L"%ls: Option '--%ls' doesn't allow an argument\n"),
|
||||
argv[0], pfound->name);
|
||||
else
|
||||
/* +option or -option */
|
||||
fwprintf(stderr,
|
||||
_(L"%ls: Option '%lc%ls' doesn't allow an argument\n"),
|
||||
// +option or -option
|
||||
fwprintf(stderr, _(L"%ls: Option '%lc%ls' doesn't allow an argument\n"),
|
||||
argv[0], argv[woptind - 1][0], pfound->name);
|
||||
}
|
||||
nextchar += wcslen(nextchar);
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
else if (pfound->has_arg == 1)
|
||||
{
|
||||
} else if (pfound->has_arg == 1) {
|
||||
if (woptind < argc)
|
||||
woptarg = argv[woptind++];
|
||||
else
|
||||
{
|
||||
else {
|
||||
if (wopterr)
|
||||
fwprintf(stderr, _(L"%ls: Option '%ls' requires an argument\n"),
|
||||
argv[0], argv[woptind - 1]);
|
||||
fwprintf(stderr, _(L"%ls: Option '%ls' requires an argument\n"), argv[0],
|
||||
argv[woptind - 1]);
|
||||
nextchar += wcslen(nextchar);
|
||||
return optstring[0] == ':' ? ':' : '?';
|
||||
}
|
||||
}
|
||||
nextchar += wcslen(nextchar);
|
||||
if (longind != NULL)
|
||||
*longind = option_index;
|
||||
if (pfound->flag)
|
||||
{
|
||||
if (longind != NULL) *longind = option_index;
|
||||
if (pfound->flag) {
|
||||
*(pfound->flag) = pfound->val;
|
||||
return 0;
|
||||
}
|
||||
return pfound->val;
|
||||
}
|
||||
|
||||
/* Can't find it as a long option. If this is not getopt_long_only,
|
||||
or the option starts with '--' or is not a valid short
|
||||
option, then it's an error.
|
||||
Otherwise interpret it as a short option. */
|
||||
if (!long_only || argv[woptind][1] == '-'
|
||||
|| my_index(optstring, *nextchar) == NULL)
|
||||
{
|
||||
if (wopterr)
|
||||
{
|
||||
if (argv[woptind][1] == '-')
|
||||
/* --option */
|
||||
fwprintf(stderr, _(L"%ls: Unrecognized option '--%ls'\n"),
|
||||
argv[0], nextchar);
|
||||
// Can't find it as a long option. If this is not getopt_long_only, or the option starts
|
||||
// with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a
|
||||
// short option.
|
||||
if (!long_only || argv[woptind][1] == '-' || my_index(optstring, *nextchar) == NULL) {
|
||||
if (wopterr) {
|
||||
if (argv[woptind][1] == '-') // --option
|
||||
fwprintf(stderr, _(L"%ls: Unrecognized option '--%ls'\n"), argv[0], nextchar);
|
||||
else
|
||||
/* +option or -option */
|
||||
fwprintf(stderr, _(L"%ls: Unrecognized option '%lc%ls'\n"),
|
||||
argv[0], argv[woptind][0], nextchar);
|
||||
// +option or -option
|
||||
fwprintf(stderr, _(L"%ls: Unrecognized option '%lc%ls'\n"), argv[0],
|
||||
argv[woptind][0], nextchar);
|
||||
}
|
||||
nextchar = (wchar_t *) L"";
|
||||
nextchar = (wchar_t *)L"";
|
||||
woptind++;
|
||||
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 *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. */
|
||||
if (*nextchar == '\0')
|
||||
++woptind;
|
||||
// Increment `woptind' when we start to process its last character.
|
||||
if (*nextchar == '\0') ++woptind;
|
||||
|
||||
if (temp == NULL || c == ':')
|
||||
{
|
||||
if (wopterr)
|
||||
{
|
||||
if (temp == NULL || c == ':') {
|
||||
if (wopterr) {
|
||||
fwprintf(stderr, _(L"%ls: Invalid option -- %lc\n"), argv[0], (wint_t)c);
|
||||
}
|
||||
woptopt = c;
|
||||
|
||||
if (*nextchar != '\0')
|
||||
woptind++;
|
||||
if (*nextchar != '\0') woptind++;
|
||||
|
||||
return '?';
|
||||
}
|
||||
if (temp[1] == ':')
|
||||
{
|
||||
if (temp[2] == ':')
|
||||
{
|
||||
/* This is an option that accepts an argument optionally. */
|
||||
if (*nextchar != '\0')
|
||||
{
|
||||
if (temp[1] == ':') {
|
||||
if (temp[2] == ':') {
|
||||
// This is an option that accepts an argument optionally.
|
||||
if (*nextchar != '\0') {
|
||||
woptarg = nextchar;
|
||||
woptind++;
|
||||
}
|
||||
else
|
||||
} else
|
||||
woptarg = NULL;
|
||||
nextchar = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is an option that requires an argument. */
|
||||
if (*nextchar != '\0')
|
||||
{
|
||||
} else {
|
||||
// This is an option that requires an argument.
|
||||
if (*nextchar != '\0') {
|
||||
woptarg = nextchar;
|
||||
/* If we end this ARGV-element by taking the rest as an arg,
|
||||
we must advance to the next element now. */
|
||||
// If we end this ARGV-element by taking the rest as an arg, we must advance to
|
||||
// the next element now.
|
||||
woptind++;
|
||||
}
|
||||
else if (woptind == argc)
|
||||
{
|
||||
if (wopterr)
|
||||
{
|
||||
/* 1003.2 specifies the format of this message. */
|
||||
fwprintf(stderr, _(L"%ls: Option requires an argument -- %lc\n"),
|
||||
argv[0], (wint_t)c);
|
||||
} else if (woptind == argc) {
|
||||
if (wopterr) {
|
||||
// 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;
|
||||
if (optstring[0] == ':')
|
||||
c = ':';
|
||||
else
|
||||
c = '?';
|
||||
}
|
||||
else
|
||||
/* We already incremented `woptind' once;
|
||||
increment it again when taking next ARGV-elt as argument. */
|
||||
} else
|
||||
// We already incremented `woptind' once; increment it again when taking next
|
||||
// ARGV-elt as argument.
|
||||
woptarg = argv[woptind++];
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
273
src/wgetopt.h
273
src/wgetopt.h
|
@ -1,27 +1,18 @@
|
|||
/** \file wgetopt.h
|
||||
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 is not usually useful since the argv
|
||||
array is always defined to be of type char**, but in fish, all
|
||||
internal commands use wide characters and hence this library is
|
||||
useful.
|
||||
|
||||
If you want to use this version of getopt in your program,
|
||||
download the fish sourcecode, 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 all the
|
||||
regular getopt functions, prefixing every function, global
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
// 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
|
||||
// is not usually useful since the argv array is always defined to be of type char**, but in fish,
|
||||
// all internal commands use wide characters and hence this library is useful.
|
||||
//
|
||||
// If you want to use this version of getopt in your program, download the fish sourcecode,
|
||||
// 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
|
||||
// all the regular getopt functions, prefixing every function, global 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.
|
||||
Copyright (C) 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc.
|
||||
|
@ -49,169 +40,131 @@ Cambridge, MA 02139, USA. */
|
|||
|
||||
#include <stddef.h>
|
||||
|
||||
class wgetopter_t
|
||||
{
|
||||
private:
|
||||
class wgetopter_t {
|
||||
private:
|
||||
void exchange(wchar_t **argv);
|
||||
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);
|
||||
|
||||
public:
|
||||
/* For communication from `getopt' to the caller.
|
||||
When `getopt' finds an option that takes an argument,
|
||||
the argument value is returned here.
|
||||
Also, when `ordering' is RETURN_IN_ORDER,
|
||||
each non-option ARGV-element is returned here. */
|
||||
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);
|
||||
|
||||
public:
|
||||
// For communication from `getopt' to the caller. When `getopt' finds an option that takes an
|
||||
// argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each
|
||||
// non-option ARGV-element is returned here.
|
||||
wchar_t *woptarg;
|
||||
|
||||
/* Index in ARGV of the next element to be scanned.
|
||||
This is used for communication to and from the caller
|
||||
and for communication between successive calls to `getopt'.
|
||||
// Index in ARGV of the next element to be scanned. This is used for communication to and from
|
||||
// the caller and for communication between successive calls to `getopt'.
|
||||
//
|
||||
// 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
|
||||
// caller should itself scan.
|
||||
//
|
||||
// Otherwise, `woptind' communicates from one call to the next how much of ARGV has been scanned
|
||||
// so far.
|
||||
|
||||
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 caller should itself scan.
|
||||
|
||||
Otherwise, `woptind' communicates from one call to the next
|
||||
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;
|
||||
|
||||
|
||||
/* The next char to be scanned in the option-element
|
||||
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. */
|
||||
|
||||
// The next char to be scanned in the option-element 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.
|
||||
wchar_t *nextchar;
|
||||
|
||||
/* Callers store zero here to inhibit the error message
|
||||
for unrecognized options. */
|
||||
|
||||
// Callers store zero here to inhibit the error message for unrecognized options.
|
||||
int wopterr;
|
||||
|
||||
/* Set to an option character which was unrecognized.
|
||||
This must be initialized on some systems to avoid linking in the
|
||||
system's own getopt implementation. */
|
||||
|
||||
// Set to an option character which was unrecognized. This must be initialized on some systems
|
||||
// to avoid linking in the system's own getopt implementation.
|
||||
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, the default is PERMUTE.
|
||||
//
|
||||
// REQUIRE_ORDER means don't recognize them as options; stop option processing when the first
|
||||
// non-option is seen. This is what Unix does. This mode of operation is selected by using `+'
|
||||
// as the first character of the list of option characters.
|
||||
//
|
||||
// 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 to be given in any order, even with
|
||||
// programs that were not written to expect this.
|
||||
//
|
||||
// RETURN_IN_ORDER is an option available to programs that were written 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 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
|
||||
// operation.
|
||||
//
|
||||
// The special argument `--' forces an end of option-scanning regardless of the value of
|
||||
// `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return EOF with
|
||||
// `woptind' != ARGC.
|
||||
enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering;
|
||||
|
||||
If the caller did not specify anything,
|
||||
the default is PERMUTE.
|
||||
|
||||
REQUIRE_ORDER means don't recognize them as options;
|
||||
stop option processing when the first non-option is seen.
|
||||
This is what Unix does.
|
||||
This mode of operation is selected by using `+' as the first
|
||||
character of the list of option characters.
|
||||
|
||||
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
|
||||
to be given in any order, even with programs that were not written to
|
||||
expect this.
|
||||
|
||||
RETURN_IN_ORDER is an option available to programs that were written
|
||||
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
|
||||
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 operation.
|
||||
|
||||
The special argument `--' forces an end of option-scanning regardless
|
||||
of the value of `ordering'. In the case of RETURN_IN_ORDER, only
|
||||
`--' can cause `getopt' to return EOF with `woptind' != ARGC. */
|
||||
|
||||
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. */
|
||||
// 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 last_nonopt;
|
||||
|
||||
wgetopter_t()
|
||||
: woptarg(NULL),
|
||||
woptind(0),
|
||||
nextchar(0),
|
||||
wopterr(0),
|
||||
woptopt('?'),
|
||||
ordering(),
|
||||
first_nonopt(0),
|
||||
last_nonopt(0) {}
|
||||
|
||||
wgetopter_t() : woptarg(NULL), woptind(0), nextchar(0), wopterr(0), woptopt('?'), 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);
|
||||
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.
|
||||
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
|
||||
of `struct option' terminated by an element containing a name which is
|
||||
zero.
|
||||
|
||||
The field `has_arg' is:
|
||||
no_argument (or 0) if the option does not take an argument,
|
||||
required_argument (or 1) if the option requires an 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 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 nonzero
|
||||
value (the equivalent single-letter option character, if there is
|
||||
one). For long options that have a zero `flag' field, `getopt'
|
||||
returns the contents of the `val' field. */
|
||||
|
||||
struct woption
|
||||
{
|
||||
/**
|
||||
long name for switch
|
||||
*/
|
||||
/// Describe the long-named options requested by the application. The LONG_OPTIONS argument to
|
||||
/// getopt_long or getopt_long_only is a vector of `struct option' terminated by an element
|
||||
/// containing a name which is zero.
|
||||
///
|
||||
/// The field `has_arg' is:
|
||||
/// no_argument (or 0) if the option does not take an argument,
|
||||
/// required_argument (or 1) if the option requires an 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
|
||||
/// 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
|
||||
/// nonzero value (the equivalent single-letter option character, if there is 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;
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
/// 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.
|
||||
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;
|
||||
|
||||
/**
|
||||
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;
|
||||
};
|
||||
|
||||
/* 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
|
||||
*/
|
||||
#define no_argument 0
|
||||
/**
|
||||
Specifies that a switch requires an argument
|
||||
*/
|
||||
#define required_argument 1
|
||||
/**
|
||||
Specifies that a switch accepts an optional argument
|
||||
*/
|
||||
#define optional_argument 2
|
||||
/// Specifies that a switch does not accept an argument.
|
||||
#define no_argument 0
|
||||
/// Specifies that a switch requires an argument.
|
||||
#define required_argument 1
|
||||
/// Specifies that a switch accepts an optional argument.
|
||||
#define optional_argument 2
|
||||
|
||||
#endif /* FISH_WGETOPT_H */
|
||||
|
|
1165
src/wildcard.cpp
1165
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
|
||||
#define FISH_WILDCARD_H
|
||||
|
||||
#include <vector>
|
||||
#include <stdbool.h>
|
||||
#include <vector>
|
||||
|
||||
#include "common.h"
|
||||
#include "expand.h"
|
||||
#include "complete.h"
|
||||
#include "expand.h"
|
||||
|
||||
// Enumeration of all wildcard types
|
||||
enum
|
||||
{
|
||||
// Character representing any character except '/' (slash).
|
||||
// Enumeration of all wildcard types.
|
||||
enum {
|
||||
/// Character representing any character except '/' (slash).
|
||||
ANY_CHAR = WILDCARD_RESERVED_BASE,
|
||||
// Character representing any character string not containing '/' (slash).
|
||||
/// Character representing any character string not containing '/' (slash).
|
||||
ANY_STRING,
|
||||
// Character representing any character string.
|
||||
/// Character representing any character string.
|
||||
ANY_STRING_RECURSIVE,
|
||||
// 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.
|
||||
/// 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.
|
||||
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
|
||||
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 */
|
||||
/// Check if the specified string contains wildcards.
|
||||
bool wildcard_has(const wcstring &, bool internal);
|
||||
bool wildcard_has(const wchar_t *, bool internal);
|
||||
|
||||
/**
|
||||
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,
|
||||
expand_flags_t expand_flags,
|
||||
complete_flags_t flags);
|
||||
/// 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,
|
||||
expand_flags_t expand_flags, complete_flags_t flags);
|
||||
|
||||
#endif
|
||||
|
|
396
src/wutil.cpp
396
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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <assert.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <wchar.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <limits.h>
|
||||
#include <libgen.h>
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <wchar.h>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "common.h"
|
||||
#include "fallback.h" // IWYU pragma: keep
|
||||
#include "wutil.h" // IWYU pragma: keep
|
||||
#include "wutil.h" // IWYU pragma: keep
|
||||
|
||||
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
|
||||
#define PATH_MAX MAXPATHLEN
|
||||
#else
|
||||
/**
|
||||
Fallback length of MAXPATHLEN. Just a hopefully sane value...
|
||||
*/
|
||||
/// Fallback length of MAXPATHLEN. Hopefully a sane value.
|
||||
#define PATH_MAX 4096
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Lock to protect wgettext */
|
||||
/// Lock to protect wgettext.
|
||||
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;
|
||||
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);
|
||||
if (!d) return false;
|
||||
|
||||
out_name = str2wcstring(d->d_name);
|
||||
if (out_is_dir)
|
||||
{
|
||||
/* The caller cares if this is a directory, so check */
|
||||
if (out_is_dir) {
|
||||
// The caller cares if this is a directory, so check.
|
||||
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;
|
||||
#ifdef HAVE_STRUCT_DIRENT_D_TYPE
|
||||
if (d->d_type == DT_DIR)
|
||||
{
|
||||
/* Known directory */
|
||||
if (d->d_type == DT_DIR) {
|
||||
// Known directory.
|
||||
is_dir = true;
|
||||
check_with_stat = false;
|
||||
}
|
||||
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. */
|
||||
} 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.
|
||||
check_with_stat = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Regular file */
|
||||
} else {
|
||||
// Regular file.
|
||||
is_dir = false;
|
||||
check_with_stat = false;
|
||||
}
|
||||
#endif // HAVE_STRUCT_DIRENT_D_TYPE
|
||||
if (check_with_stat)
|
||||
{
|
||||
/* We couldn't determine the file type from the dirent; check by stat'ing it */
|
||||
#endif // HAVE_STRUCT_DIRENT_D_TYPE
|
||||
if (check_with_stat) {
|
||||
// We couldn't determine the file type from the dirent; check by stat'ing it.
|
||||
cstring fullpath = wcs2string(dir_path);
|
||||
fullpath.push_back('/');
|
||||
fullpath.append(d->d_name);
|
||||
struct stat buf;
|
||||
if (stat(fullpath.c_str(), &buf) != 0)
|
||||
{
|
||||
if (stat(fullpath.c_str(), &buf) != 0) {
|
||||
is_dir = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
bool wreaddir(DIR *dir, std::wstring &out_name)
|
||||
{
|
||||
bool wreaddir(DIR *dir, std::wstring &out_name) {
|
||||
struct dirent *d = readdir(dir);
|
||||
if (!d) return false;
|
||||
|
||||
|
@ -110,53 +94,45 @@ bool wreaddir(DIR *dir, std::wstring &out_name)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool wreaddir_for_dirs(DIR *dir, wcstring *out_name)
|
||||
{
|
||||
bool wreaddir_for_dirs(DIR *dir, wcstring *out_name) {
|
||||
struct dirent *result = NULL;
|
||||
while (result == NULL)
|
||||
{
|
||||
while (result == NULL) {
|
||||
struct dirent *d = readdir(dir);
|
||||
if (!d) break;
|
||||
|
||||
#if HAVE_STRUCT_DIRENT_D_TYPE
|
||||
switch (d->d_type)
|
||||
{
|
||||
// These may be directories
|
||||
switch (d->d_type) {
|
||||
case DT_DIR:
|
||||
case DT_LNK:
|
||||
case DT_UNKNOWN:
|
||||
case DT_UNKNOWN: {
|
||||
// These may be directories.
|
||||
result = d;
|
||||
break;
|
||||
|
||||
// Nothing else can
|
||||
default:
|
||||
}
|
||||
default: {
|
||||
// Nothing else can.
|
||||
break;
|
||||
}
|
||||
}
|
||||
#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;
|
||||
#endif
|
||||
}
|
||||
if (result && out_name)
|
||||
{
|
||||
if (result && out_name) {
|
||||
*out_name = str2wcstring(result->d_name);
|
||||
}
|
||||
return result != NULL;
|
||||
}
|
||||
|
||||
|
||||
const wcstring wgetcwd()
|
||||
{
|
||||
const wcstring wgetcwd() {
|
||||
wcstring retval;
|
||||
|
||||
char *res = getcwd(NULL, 0);
|
||||
if (res)
|
||||
{
|
||||
if (res) {
|
||||
retval = str2wcstring(res);
|
||||
free(res);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
debug(0, _(L"getcwd() failed with errno %d/%s"), errno, strerror(errno));
|
||||
retval = wcstring();
|
||||
}
|
||||
|
@ -164,176 +140,147 @@ const wcstring wgetcwd()
|
|||
return retval;
|
||||
}
|
||||
|
||||
int wchdir(const wcstring &dir)
|
||||
{
|
||||
int wchdir(const wcstring &dir) {
|
||||
cstring tmp = wcs2string(dir);
|
||||
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;
|
||||
size_t idx = 0;
|
||||
switch (mode[idx++])
|
||||
{
|
||||
case 'r':
|
||||
switch (mode[idx++]) {
|
||||
case 'r': {
|
||||
permissions = O_RDONLY;
|
||||
break;
|
||||
case 'w':
|
||||
}
|
||||
case 'w': {
|
||||
permissions = O_WRONLY;
|
||||
options = O_CREAT | O_TRUNC;
|
||||
break;
|
||||
case 'a':
|
||||
}
|
||||
case 'a': {
|
||||
permissions = O_WRONLY;
|
||||
options = O_CREAT | O_APPEND;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
default: {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Skip binary */
|
||||
if (mode[idx] == 'b')
|
||||
idx++;
|
||||
// Skip binary.
|
||||
if (mode[idx] == 'b') idx++;
|
||||
|
||||
/* Consider append option */
|
||||
if (mode[idx] == '+')
|
||||
permissions = O_RDWR;
|
||||
// Consider append option.
|
||||
if (mode[idx] == '+') permissions = O_RDWR;
|
||||
|
||||
int fd = wopen_cloexec(path, permissions | options, 0666);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
if (fd < 0) return NULL;
|
||||
FILE *result = fdopen(fd, mode);
|
||||
if (result == NULL)
|
||||
close(fd);
|
||||
if (result == NULL) close(fd);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool set_cloexec(int fd)
|
||||
{
|
||||
bool set_cloexec(int fd) {
|
||||
int flags = fcntl(fd, F_GETFD, 0);
|
||||
if (flags < 0)
|
||||
{
|
||||
if (flags < 0) {
|
||||
return false;
|
||||
}
|
||||
else if (flags & FD_CLOEXEC)
|
||||
{
|
||||
} else if (flags & FD_CLOEXEC) {
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
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();
|
||||
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
|
||||
if (cloexec && (O_CLOEXEC != 0))
|
||||
{
|
||||
if (cloexec && (O_CLOEXEC != 0)) {
|
||||
flags |= O_CLOEXEC;
|
||||
cloexec = false;
|
||||
}
|
||||
#endif
|
||||
int fd = ::open(tmp.c_str(), flags, mode);
|
||||
if (cloexec && fd >= 0 && ! set_cloexec(fd))
|
||||
{
|
||||
if (cloexec && fd >= 0 && !set_cloexec(fd)) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
DIR *wopendir(const wcstring &name)
|
||||
{
|
||||
DIR *wopendir(const wcstring &name) {
|
||||
const cstring tmp = wcs2string(name);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
return access(tmp.c_str(), mode);
|
||||
}
|
||||
|
||||
int wunlink(const wcstring &file_name)
|
||||
{
|
||||
int wunlink(const wcstring &file_name) {
|
||||
const cstring tmp = wcs2string(file_name);
|
||||
return unlink(tmp.c_str());
|
||||
}
|
||||
|
||||
void wperror(const wchar_t *s)
|
||||
{
|
||||
void wperror(const wchar_t *s) {
|
||||
int e = errno;
|
||||
if (s[0] != L'\0')
|
||||
{
|
||||
if (s[0] != L'\0') {
|
||||
fwprintf(stderr, L"%ls: ", s);
|
||||
}
|
||||
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 err = 0;
|
||||
if (!(flags & O_NONBLOCK))
|
||||
{
|
||||
if (!(flags & O_NONBLOCK)) {
|
||||
err = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
||||
}
|
||||
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 err = 0;
|
||||
if (flags & O_NONBLOCK)
|
||||
{
|
||||
if (flags & O_NONBLOCK) {
|
||||
err = fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
// In general, strerror is not async-safe, and therefore we cannot use it directly
|
||||
// So instead we have to grub through sys_nerr and sys_errlist directly
|
||||
// On GNU toolchain, this will produce a deprecation warning from the linker (!!),
|
||||
// which appears impossible to suppress!
|
||||
const char *safe_strerror(int err)
|
||||
{
|
||||
// In general, strerror is not async-safe, and therefore we cannot use it directly. So instead we
|
||||
// have to grub through sys_nerr and sys_errlist directly On GNU toolchain, this will produce a
|
||||
// deprecation warning from the linker (!!), which appears impossible to suppress!
|
||||
const char *safe_strerror(int err) {
|
||||
#if defined(__UCLIBC__)
|
||||
// uClibc does not have sys_errlist, however, its strerror is believed to be async-safe
|
||||
// See #808
|
||||
// uClibc does not have sys_errlist, however, its strerror is believed to be async-safe.
|
||||
// See issue #808.
|
||||
return strerror(err);
|
||||
#elif defined(HAVE__SYS__ERRS) || defined(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];
|
||||
}
|
||||
#elif defined(HAVE__SYS__ERRS)
|
||||
|
@ -342,15 +289,15 @@ const char *safe_strerror(int err)
|
|||
extern int _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
|
||||
#endif // defined(HAVE__SYS__ERRS) || defined(HAVE_SYS_ERRLIST)
|
||||
#endif // defined(HAVE__SYS__ERRS) || defined(HAVE_SYS_ERRLIST)
|
||||
{
|
||||
int saved_err = errno;
|
||||
|
||||
/* Use a shared buffer for this case */
|
||||
// Use a shared buffer for this case.
|
||||
static char buff[384];
|
||||
char errnum_buff[64];
|
||||
format_long_safe(errnum_buff, err);
|
||||
|
@ -365,16 +312,14 @@ const char *safe_strerror(int err)
|
|||
}
|
||||
}
|
||||
|
||||
void safe_perror(const char *message)
|
||||
{
|
||||
// Note we cannot use strerror, because on Linux it uses gettext, which is not safe
|
||||
void safe_perror(const char *message) {
|
||||
// Note we cannot use strerror, because on Linux it uses gettext, which is not safe.
|
||||
int err = errno;
|
||||
|
||||
char buff[384];
|
||||
buff[0] = '\0';
|
||||
|
||||
if (message)
|
||||
{
|
||||
if (message) {
|
||||
safe_append(buff, message, sizeof buff);
|
||||
safe_append(buff, ": ", sizeof buff);
|
||||
}
|
||||
|
@ -387,23 +332,18 @@ void safe_perror(const char *message)
|
|||
|
||||
#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);
|
||||
char *narrow_res = realpath(narrow_path.c_str(), NULL);
|
||||
|
||||
if (!narrow_res)
|
||||
return NULL;
|
||||
if (!narrow_res) return NULL;
|
||||
|
||||
wchar_t *res;
|
||||
wcstring wide_res = str2wcstring(narrow_res);
|
||||
if (resolved_path)
|
||||
{
|
||||
if (resolved_path) {
|
||||
wcslcpy(resolved_path, wide_res.c_str(), PATH_MAX);
|
||||
res = resolved_path;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
res = wcsdup(wide_res.c_str());
|
||||
}
|
||||
|
||||
|
@ -414,24 +354,19 @@ wchar_t *wrealpath(const wcstring &pathname, wchar_t *resolved_path)
|
|||
|
||||
#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);
|
||||
char narrow_buff[PATH_MAX];
|
||||
char *narrow_res = realpath(tmp.c_str(), narrow_buff);
|
||||
wchar_t *res;
|
||||
|
||||
if (!narrow_res)
|
||||
return 0;
|
||||
if (!narrow_res) return 0;
|
||||
|
||||
const wcstring wide_res = str2wcstring(narrow_res);
|
||||
if (resolved_path)
|
||||
{
|
||||
if (resolved_path) {
|
||||
wcslcpy(resolved_path, wide_res.c_str(), PATH_MAX);
|
||||
res = resolved_path;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
res = wcsdup(wide_res.c_str());
|
||||
}
|
||||
return res;
|
||||
|
@ -439,9 +374,7 @@ wchar_t *wrealpath(const wcstring &pathname, wchar_t *resolved_path)
|
|||
|
||||
#endif
|
||||
|
||||
|
||||
wcstring wdirname(const wcstring &path)
|
||||
{
|
||||
wcstring wdirname(const wcstring &path) {
|
||||
char *tmp = wcs2str(path.c_str());
|
||||
char *narrow_res = dirname(tmp);
|
||||
wcstring result = format_string(L"%s", narrow_res);
|
||||
|
@ -449,8 +382,7 @@ wcstring wdirname(const wcstring &path)
|
|||
return result;
|
||||
}
|
||||
|
||||
wcstring wbasename(const wcstring &path)
|
||||
{
|
||||
wcstring wbasename(const wcstring &path) {
|
||||
char *tmp = wcs2str(path.c_str());
|
||||
char *narrow_res = basename(tmp);
|
||||
wcstring result = format_string(L"%s", narrow_res);
|
||||
|
@ -458,29 +390,24 @@ wcstring wbasename(const wcstring &path)
|
|||
return result;
|
||||
}
|
||||
|
||||
/* Really init wgettext */
|
||||
static void wgettext_really_init()
|
||||
{
|
||||
// Really init wgettext.
|
||||
static void wgettext_really_init() {
|
||||
pthread_mutex_init(&wgettext_lock, NULL);
|
||||
fish_bindtextdomain(PACKAGE_NAME, LOCALEDIR);
|
||||
fish_textdomain(PACKAGE_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
For wgettext: Internal init function. Automatically called when a translation is first requested.
|
||||
*/
|
||||
static void wgettext_init_if_necessary()
|
||||
{
|
||||
/// For wgettext: Internal init function. Automatically called when a translation is first
|
||||
/// requested.
|
||||
static void wgettext_init_if_necessary() {
|
||||
static pthread_once_t once = PTHREAD_ONCE_INIT;
|
||||
pthread_once(&once, wgettext_really_init);
|
||||
}
|
||||
|
||||
const wchar_t *wgettext(const wchar_t *in)
|
||||
{
|
||||
if (!in)
|
||||
return in;
|
||||
const wchar_t *wgettext(const wchar_t *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;
|
||||
|
||||
wgettext_init_if_necessary();
|
||||
|
@ -489,50 +416,42 @@ const wchar_t *wgettext(const wchar_t *in)
|
|||
scoped_lock lock(wgettext_lock);
|
||||
|
||||
wcstring &val = wgettext_map[key];
|
||||
if (val.empty())
|
||||
{
|
||||
if (val.empty()) {
|
||||
cstring mbs_in = wcs2string(key);
|
||||
char *out = fish_gettext(mbs_in.c_str());
|
||||
val = format_string(L"%s", out);
|
||||
}
|
||||
errno = err;
|
||||
|
||||
// The returned string is stored in the map
|
||||
// TODO: If we want to shrink the map, this would be a problem
|
||||
// The returned string is stored in the map.
|
||||
// TODO: If we want to shrink the map, this would be a problem.
|
||||
return val.c_str();
|
||||
}
|
||||
|
||||
int wmkdir(const wcstring &name, int mode)
|
||||
{
|
||||
int wmkdir(const wcstring &name, int mode) {
|
||||
cstring name_narrow = wcs2string(name);
|
||||
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 new_narrow =wcs2string(newv);
|
||||
cstring new_narrow = wcs2string(newv);
|
||||
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);
|
||||
if (ret > INT_MAX)
|
||||
{
|
||||
if (ret > INT_MAX) {
|
||||
ret = INT_MAX;
|
||||
errno = ERANGE;
|
||||
}
|
||||
else if (ret < INT_MIN)
|
||||
{
|
||||
} else if (ret < INT_MIN) {
|
||||
ret = INT_MIN;
|
||||
errno = ERANGE;
|
||||
}
|
||||
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);
|
||||
|
||||
file_id_t result = {};
|
||||
|
@ -559,70 +478,49 @@ file_id_t file_id_t::file_id_from_stat(const struct stat *buf)
|
|||
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;
|
||||
struct stat buf = {};
|
||||
if (0 == fstat(fd, &buf))
|
||||
{
|
||||
if (0 == fstat(fd, &buf)) {
|
||||
result = file_id_t::file_id_from_stat(&buf);
|
||||
}
|
||||
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;
|
||||
struct stat buf = {};
|
||||
if (0 == wstat(path, &buf))
|
||||
{
|
||||
if (0 == wstat(path, &buf)) {
|
||||
result = file_id_t::file_id_from_stat(&buf);
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
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; }
|
||||
|
||||
bool file_id_t::operator!=(const file_id_t &rhs) const
|
||||
{
|
||||
return ! (*this == rhs);
|
||||
}
|
||||
bool file_id_t::operator!=(const file_id_t &rhs) const { return !(*this == rhs); }
|
||||
|
||||
template<typename T>
|
||||
int compare(T a, T b)
|
||||
{
|
||||
if (a < b)
|
||||
{
|
||||
template <typename T>
|
||||
int compare(T a, T b) {
|
||||
if (a < b) {
|
||||
return -1;
|
||||
}
|
||||
else if (a > b)
|
||||
{
|
||||
} else if (a > b) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 */
|
||||
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.
|
||||
int ret = 0;
|
||||
if (! ret) ret = compare(device, rhs.device);
|
||||
if (! ret) ret = compare(inode, rhs.inode);
|
||||
if (! ret) ret = compare(size, rhs.size);
|
||||
if (! ret) ret = compare(change_seconds, rhs.change_seconds);
|
||||
if (! ret) ret = compare(change_nanoseconds, rhs.change_nanoseconds);
|
||||
if (! ret) ret = compare(mod_seconds, rhs.mod_seconds);
|
||||
if (! ret) ret = compare(mod_nanoseconds, rhs.mod_nanoseconds);
|
||||
if (!ret) ret = compare(device, rhs.device);
|
||||
if (!ret) ret = compare(inode, rhs.inode);
|
||||
if (!ret) ret = compare(size, rhs.size);
|
||||
if (!ret) ret = compare(change_seconds, rhs.change_seconds);
|
||||
if (!ret) ret = compare(change_nanoseconds, rhs.change_nanoseconds);
|
||||
if (!ret) ret = compare(mod_seconds, rhs.mod_seconds);
|
||||
if (!ret) ret = compare(mod_nanoseconds, rhs.mod_nanoseconds);
|
||||
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; }
|
||||
|
|
131
src/wutil.h
131
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
|
||||
#define FISH_WUTIL_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <dirent.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <string>
|
||||
#include <stdbool.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);
|
||||
|
||||
/** Sets CLO_EXEC on a given fd */
|
||||
/// Sets CLO_EXEC on a given 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);
|
||||
|
||||
/** 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);
|
||||
|
||||
/** 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);
|
||||
|
||||
/** 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);
|
||||
|
||||
/**
|
||||
Wide character version of stat().
|
||||
*/
|
||||
/// Wide character version of stat().
|
||||
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);
|
||||
|
||||
/**
|
||||
Wide character version of access().
|
||||
*/
|
||||
/// Wide character version of access().
|
||||
int waccess(const wcstring &pathname, int mode);
|
||||
|
||||
/**
|
||||
Wide character version of unlink().
|
||||
*/
|
||||
/// Wide character version of unlink().
|
||||
int wunlink(const wcstring &pathname);
|
||||
|
||||
/**
|
||||
Wide character version of perror().
|
||||
*/
|
||||
/// Wide character version of perror().
|
||||
void wperror(const wchar_t *s);
|
||||
|
||||
/**
|
||||
Async-safe version of perror().
|
||||
*/
|
||||
/// Async-safe version of perror().
|
||||
void safe_perror(const char *message);
|
||||
|
||||
/**
|
||||
Async-safe version of strerror().
|
||||
*/
|
||||
/// Async-safe version of strerror().
|
||||
const char *safe_strerror(int err);
|
||||
|
||||
// Wide character version of getcwd().
|
||||
/// Wide character version of getcwd().
|
||||
const wcstring wgetcwd();
|
||||
|
||||
/**
|
||||
Wide character version of chdir()
|
||||
*/
|
||||
/// Wide character version of chdir().
|
||||
int wchdir(const wcstring &dir);
|
||||
|
||||
/**
|
||||
Wide character version of realpath function. Just like the GNU
|
||||
version of realpath, wrealpath will accept 0 as the value for the
|
||||
second argument, in which case the result will be allocated using
|
||||
malloc, and must be free'd by the user.
|
||||
*/
|
||||
/// Wide character version of realpath function. Just like the GNU version of realpath, wrealpath
|
||||
/// will accept 0 as the value for the 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);
|
||||
|
||||
/**
|
||||
Wide character version of readdir()
|
||||
*/
|
||||
/// Wide character version of readdir().
|
||||
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 (i.e. the file is a symlink), then return it.
|
||||
Note that this does not guarantee that everything returned is a directory,
|
||||
it's just an optimization for cases where we would check for directories anyways.
|
||||
*/
|
||||
/// Like wreaddir, but skip items that are known to not be directories. If this requires a stat
|
||||
/// (i.e. the file is a symlink), then return it. Note that this does not guarantee that everything
|
||||
/// returned is a directory, it's just an optimization for cases where we would check for
|
||||
/// directories anyways.
|
||||
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);
|
||||
|
||||
/**
|
||||
Wide character version of basename()
|
||||
*/
|
||||
/// Wide character version of basename().
|
||||
std::wstring wbasename(const std::wstring &path);
|
||||
|
||||
/**
|
||||
Wide character wrapper around the gettext function. For historic
|
||||
reasons, unlike the real gettext function, wgettext takes care of
|
||||
setting the correct domain, etc. using the textdomain and
|
||||
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.
|
||||
*/
|
||||
/// Wide character wrapper around the gettext function. For historic reasons, unlike the real
|
||||
/// gettext function, wgettext takes care of setting the correct domain, etc. using the textdomain
|
||||
/// and 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);
|
||||
|
||||
/**
|
||||
Wide character version of mkdir
|
||||
*/
|
||||
/// Wide character version of mkdir.
|
||||
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);
|
||||
|
||||
/** 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);
|
||||
/// 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);
|
||||
|
||||
/** 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. */
|
||||
struct file_id_t
|
||||
{
|
||||
/// 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.
|
||||
struct file_id_t {
|
||||
dev_t device;
|
||||
ino_t inode;
|
||||
uint64_t size;
|
||||
|
@ -147,12 +111,12 @@ struct file_id_t
|
|||
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;
|
||||
|
||||
static file_id_t file_id_from_stat(const struct stat *buf);
|
||||
|
||||
private:
|
||||
private:
|
||||
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;
|
||||
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue