@ 260915.5

250303.1 · efc601e4bd731d9ed30c32500922e6b947b459d4

released 7.3

reading declarations

bin/win32/ug.exe

Binary file changed

bin/win32/ugrep-indexer.exe

Binary file changed

bin/win32/ugrep.exe

Binary file changed

bin/win64/ug.exe

Binary file changed

bin/win64/ugrep-indexer.exe

Binary file changed

bin/win64/ugrep.exe

Binary file changed

include/reflex/pattern.h

@@ -1245,6 +1245,21 @@ class Pattern {   {     return opcode & 0xffff;   }+  /// check if lower case+  static inline bool islowercase(Char c)+  {+    return (c >= 'a' && c <= 'z');+  }+  /// check if upper case+  static inline bool isuppercase(Char c)+  {+    return (c >= 'A' && c <= 'Z');+  }+  /// check if lower or upper case+  static inline bool isanycase(Char c)+  {+    return islowercase(c) || isuppercase(c);+  }   /// convert to lower case if c is a letter a-z, A-Z.   static inline Char lowercase(Char c)   {

lib/pattern.cpp

@@ -296,7 +296,7 @@ void Pattern::init(const char *options, const uint8_t *pred)           for (DFA::State::Edges::iterator t = state->edges.begin(); t != state->edges.end(); ++t)           {             Char c = t->first;-            if (c >= 'a' && c <= 'z')+            if (islowercase(c))             {               state->edges[uppercase(c)] = DFA::State::Edge(uppercase(c), t->second.second);               ++eno_;@@ -828,7 +828,7 @@ void Pattern::parse(               c = static_cast<Char>(s - abtnvfr + '\a');           }         }-        else if (c >= 'A' && c <= 'Z' && opt_.i)+        else if (isuppercase(c) && opt_.i)         {           c = lowercase(c);         }@@ -1736,7 +1736,7 @@ void Pattern::compile(             Char c = t->first;             DFA::State *target_state = last_state = last_state->next = dfa_.state(t->second.second);             state->edges[c] = DFA::State::Edge(c, target_state);-            if (c >= 'a' && c <= 'z')+            if (islowercase(c))             {               state->edges[uppercase(c)] = DFA::State::Edge(uppercase(c), target_state);               ++eno_;@@ -1765,7 +1765,7 @@ void Pattern::compile(           {             Char c = t->first;             chars.add(c);-            if (c >= 'a' && c <= 'z')+            if (islowercase(c))               chars.add(uppercase(c));           }         }@@ -1791,9 +1791,9 @@ void Pattern::compile(               {                 if (common.contains(c))                 {-                  if (std::isalpha(c))+                  if (isanycase(c))                   {-                    if (c >= 'a' && c <= 'z')+                    if (islowercase(c))                     {                       pos = i->second;                       DFA::State *target_state = last_state = last_state->next = dfa_.state(state->tnode->edges[c].second, pos);@@ -1853,7 +1853,7 @@ void Pattern::compile(               if (chars.contains(c))               {                 DFA::State *target_state = last_state = last_state->next = dfa_.state(state->tnode->edges[c].second);-                if (std::isalpha(c))+                if (isanycase(c))                 {                   state->edges[lowercase(c)] = DFA::State::Edge(lowercase(c), target_state);                   state->edges[uppercase(c)] = DFA::State::Edge(uppercase(c), target_state);@@ -1893,7 +1893,7 @@ void Pattern::compile(           DFA::State *target_state = last_state = last_state->next = dfa_.state(&t->second);           state->edges[c] = DFA::State::Edge(c, target_state);           ++eno_;-          if (opt_.i && c >= 'a' && c <= 'z')+          if (opt_.i && islowercase(c))           {             state->edges[uppercase(c)] = DFA::State::Edge(uppercase(c), target_state);             ++eno_;@@ -1911,12 +1911,8 @@ void Pattern::compile(           for (std::map<Char,Tree::Node>::iterator t = state->tnode->edges.begin(); t != state->tnode->edges.end(); ++t)           {             Char c = t->first;-            if (c >= 'a')-            {-              if (c > 'z')-                break;+            if (islowercase(c))               chars.add(uppercase(c));-            }           }         }         Moves::iterator i = moves.begin();@@ -1936,9 +1932,9 @@ void Pattern::compile(               {                 if (common.contains(c))                 {-                  if (std::isalpha(c))+                  if (isanycase(c))                   {-                    if (c >= 'a' && c <= 'z')+                    if (islowercase(c))                     {                       pos = i->second;                       DFA::State *target_state = last_state = last_state->next = dfa_.state(&state->tnode->edges[c], pos);@@ -1996,7 +1992,7 @@ void Pattern::compile(             if (chars.contains(c))             {               DFA::State *target_state = last_state = last_state->next = dfa_.state(&state->tnode->edges[c]);-              if (opt_.i && std::isalpha(c))+              if (opt_.i && isanycase(c))               {                 state->edges[lowercase(c)] = DFA::State::Edge(lowercase(c), target_state);                 state->edges[uppercase(c)] = DFA::State::Edge(uppercase(c), target_state);@@ -2027,7 +2023,7 @@ void Pattern::compile(               {                 Char c = (i << 4) + j;                 DFA::State *target_state = last_state = last_state->next = dfa_.state(p[j]);-                if (opt_.i && std::isalpha(c))+                if (opt_.i && isanycase(c))                 {                   state->edges[lowercase(c)] = DFA::State::Edge(lowercase(c), target_state);                   state->edges[uppercase(c)] = DFA::State::Edge(uppercase(c), target_state);@@ -2083,9 +2079,9 @@ void Pattern::compile(               {                 if (common.contains(c))                 {-                  if (std::isalpha(c))+                  if (isanycase(c))                   {-                    if (c >= 'a' && c <= 'z')+                    if (islowercase(c))                     {                       pos = i->second;                       DFA::State *target_state = last_state = last_state->next = dfa_.state(state->tnode->edge[c >> 4][c & 0xf], pos);@@ -2143,7 +2139,7 @@ void Pattern::compile(             if (chars.contains(c))             {               DFA::State *target_state = last_state = last_state->next = dfa_.state(state->tnode->edge[c >> 4][c & 0xf]);-              if (opt_.i && std::isalpha(c))+              if (opt_.i && isanycase(c))               {                 state->edges[lowercase(c)] = DFA::State::Edge(lowercase(c), target_state);                 state->edges[uppercase(c)] = DFA::State::Edge(uppercase(c), target_state);@@ -2456,10 +2452,10 @@ void Pattern::compile_transition(           Chars chars;           if (literal)           {-            if (std::isalpha(c) && is_modified(ModConst::i, modifiers, loc))+            if (isanycase(c) && is_modified(ModConst::i, modifiers, loc))             {-              chars.add(uppercase(c));               chars.add(lowercase(c));+              chars.add(uppercase(c));             }             else             {@@ -2499,10 +2495,10 @@ void Pattern::compile_transition(                   switch (escape_at(loc))                   {                     case '\0': // no escape at current loc-                      if (std::isalpha(c) && is_modified(ModConst::i, modifiers, loc))+                      if (isanycase(c) && is_modified(ModConst::i, modifiers, loc))                       {-                        chars.add(uppercase(c));                         chars.add(lowercase(c));+                        chars.add(uppercase(c));                       }                       else                       {@@ -2539,10 +2535,10 @@ void Pattern::compile_transition(                       break;                     default:                       c = parse_esc(loc, &chars);-                      if (c <= 'z' && std::isalpha(c) && is_modified(ModConst::i, modifiers, loc))+                      if (isanycase(c) && is_modified(ModConst::i, modifiers, loc))                       {-                        chars.add(uppercase(c));                         chars.add(lowercase(c));+                        chars.add(uppercase(c));                       }                   }                 }@@ -2667,7 +2663,7 @@ void Pattern::compile_list(Location loc, Chars& chars, const Mods modifiers) con         {           if (is_modified(ModConst::i, modifiers, loc))           {-            if (lo >= 'a' && lo <= 'z' && c >= 'A' && c <= 'Z')+            if (islowercase(lo) && isuppercase(c))               c = lowercase(c);             Char a = lo;             Char b = c;@@ -2691,10 +2687,10 @@ void Pattern::compile_list(Location loc, Chars& chars, const Mods modifiers) con         }         else         {-          if (std::isalpha(c) && is_modified(ModConst::i, modifiers, loc))+          if (isanycase(c) && is_modified(ModConst::i, modifiers, loc))           {-            chars.add(uppercase(c));             chars.add(lowercase(c));+            chars.add(uppercase(c));           }           else           {

man.sh

@@ -32,10 +32,11 @@ regular expression matches one or more newlines.  An empty pattern matches every line.  Each input line that matches at least one of the patterns is written to the standard output. .PP-The \fBug\fR command is intended for interactive searching, using a .ugrep-configuration file located in the working directory or home directory, see-CONFIGURATION.  \fBug\fR is equivalent to \fBugrep --config --pretty --sort\fR-to load a .ugrep file, enhance the terminal output, and sort files by name.+The \fBug\fR command is intended for interactive searching, using a `.ugrep'+configuration file located in the working directory or, if not found, in the+home directory, see CONFIGURATION.  \fBug\fR is equivalent to \fBugrep --config+--pretty --sort\fR to load a configuration file, enhance the terminal output,+and to sort files by name. .PP The \fBugrep+\fR and \fBug+\fR commands are the same as the \fBugrep\fR and \fBug\fR commands, but also use filters to search pdfs, documents, e-books,@@ -179,10 +180,10 @@ An error occurred. If \fB-q\fR or \fB--quiet\fR or \fB--silent\fR is used and a line is selected, the exit status is 0 even if an error occurred. .SH CONFIGURATION-The \fBug\fR command is intended for context-dependent interactive searching-and is equivalent to the \fBugrep --config --pretty --sort\fR command to load-the default configuration file `.ugrep' when present in the working directory-or in the home directory.+The \fBug\fR command is intended for interactive searching and is equivalent to+the \fBugrep --config --pretty --sort\fR command to load the `.ugrep`+configuration file located in the working directory or, when not found, in the+home directory. .PP A configuration file contains `NAME=VALUE' pairs per line, where `NAME` is the name of a long option (without `--') and `=VALUE' is an argument, which is@@ -191,8 +192,8 @@ starting with a `#' are ignored. .PP The \fB--config\fR=\fIFILE\fR option and its abbreviated form \fB---\fR\fIFILE\fR load the specified configuration file located in the-working directory or, when not found, located in the home directory.  An error-is produced when \fIFILE\fR is not found or cannot be read.+working directory or, when not found, in the home directory.  An error is+produced when \fIFILE\fR is not found or cannot be read. .PP Command line options are parsed in the following order: the configuration file is loaded first, followed by the remaining options and arguments on the command@@ -200,9 +201,10 @@ line. .PP The \fB--save-config\fR option saves a `.ugrep' configuration file to the working directory with a subset of the options specified on the command line.-The \fB--save-config\fR=\fIFILE\fR option saves the configuration to-\fIFILE\fR.  The configuration is written to standard output when \fIFILE\fR is-a `-'.+Only part of the specified options are saved that do not cause searches to fail+when combined with other options.  The \fB--save-config\fR=\fIFILE\fR option+saves the configuration to \fIFILE\fR.  The configuration is written to+standard output when \fIFILE\fR is a `-'. .SH GLOBBING Globbing is used by options \fB-g\fR, \fB--include\fR, \fB--include-dir\fR, \fB--include-from\fR, \fB--exclude\fR, \fB--exclude-dir\fR,

man/ug.1

@@ -1,4 +1,4 @@-.TH UGREP "1" "March 01, 2025" "ugrep 7.3.0" "User Commands"+.TH UGREP "1" "March 03, 2025" "ugrep 7.3.0" "User Commands" .SH NAME \fBugrep\fR, \fBug\fR -- file pattern searcher .SH SYNOPSIS@@ -17,10 +17,11 @@ regular expression matches one or more newlines.  An empty pattern matches every line.  Each input line that matches at least one of the patterns is written to the standard output. .PP-The \fBug\fR command is intended for interactive searching, using a .ugrep-configuration file located in the working directory or home directory, see-CONFIGURATION.  \fBug\fR is equivalent to \fBugrep --config --pretty --sort\fR-to load a .ugrep file, enhance the terminal output, and sort files by name.+The \fBug\fR command is intended for interactive searching, using a `.ugrep'+configuration file located in the working directory or, if not found, in the+home directory, see CONFIGURATION.  \fBug\fR is equivalent to \fBugrep --config+--pretty --sort\fR to load a configuration file, enhance the terminal output,+and to sort files by name. .PP The \fBugrep+\fR and \fBug+\fR commands are the same as the \fBugrep\fR and \fBug\fR commands, but also use filters to search pdfs, documents, e-books,@@ -257,8 +258,8 @@ Use configuration FILE.  The default FILE is `.ugrep'.  The working directory is checked first for FILE, then the home directory.  The options specified in the configuration FILE are parsed first, followed by the remaining options specified on the command line.-The ug command automatically loads a `.ugrep' configuration file,-unless \fB\-\-config\fR=\fIFILE\fR or \fB\-\-no\-config\fR is specified.+The ug command automatically loads a `.ugrep' configuration file+when present, unless \fB\-\-config\fR=\fIFILE\fR or \fB\-\-no\-config\fR is specified. .TP \fB\-\-no\-config\fR Do not automatically load the default .ugrep configuration file.@@ -775,8 +776,8 @@ which is automatically loaded by the ug command.  When FILE is a OPTIONS are saved that do not cause searches to fail when combined with other options.  Additional options may be specified by editing the saved configuration file.  A configuration file may be modified-manually to specify one or more config[=\fIFILE\fR] to indirectly load-the specified FILE, but recursive config loading is not allowed.+by adding one or more config=\fIFILE\fR to include configuration files,+but recursive configuration file inclusion is not permitted. .TP \fB\-\-separator\fR[=\fISEP\fR], \fB\-\-context\-separator\fR=\fISEP\fR Use SEP as field separator between file name, line number, column@@ -968,10 +969,10 @@ An error occurred. If \fB-q\fR or \fB--quiet\fR or \fB--silent\fR is used and a line is selected, the exit status is 0 even if an error occurred. .SH CONFIGURATION-The \fBug\fR command is intended for context-dependent interactive searching-and is equivalent to the \fBugrep --config --pretty --sort\fR command to load-the default configuration file `.ugrep' when present in the working directory-or in the home directory.+The \fBug\fR command is intended for interactive searching and is equivalent to+the \fBugrep --config --pretty --sort\fR command to load the `.ugrep`+configuration file located in the working directory or, when not found, in the+home directory. .PP A configuration file contains `NAME=VALUE' pairs per line, where `NAME` is the name of a long option (without `--') and `=VALUE' is an argument, which is@@ -980,8 +981,8 @@ starting with a `#' are ignored. .PP The \fB--config\fR=\fIFILE\fR option and its abbreviated form \fB---\fR\fIFILE\fR load the specified configuration file located in the-working directory or, when not found, located in the home directory.  An error-is produced when \fIFILE\fR is not found or cannot be read.+working directory or, when not found, in the home directory.  An error is+produced when \fIFILE\fR is not found or cannot be read. .PP Command line options are parsed in the following order: the configuration file is loaded first, followed by the remaining options and arguments on the command@@ -989,9 +990,10 @@ line. .PP The \fB--save-config\fR option saves a `.ugrep' configuration file to the working directory with a subset of the options specified on the command line.-The \fB--save-config\fR=\fIFILE\fR option saves the configuration to-\fIFILE\fR.  The configuration is written to standard output when \fIFILE\fR is-a `-'.+Only part of the specified options are saved that do not cause searches to fail+when combined with other options.  The \fB--save-config\fR=\fIFILE\fR option+saves the configuration to \fIFILE\fR.  The configuration is written to+standard output when \fIFILE\fR is a `-'. .SH GLOBBING Globbing is used by options \fB-g\fR, \fB--include\fR, \fB--include-dir\fR, \fB--include-from\fR, \fB--exclude\fR, \fB--exclude-dir\fR,

man/ugrep-indexer.1

@@ -1,4 +1,4 @@-.TH UGREP-INDEXER "1" "March 01, 2025" "ugrep-indexer 7.3.0" "User Commands"+.TH UGREP-INDEXER "1" "March 03, 2025" "ugrep-indexer 7.3.0" "User Commands" .SH NAME \fBugrep-indexer\fR -- file indexer to accelerate recursive searching .SH SYNOPSIS

man/ugrep.1

@@ -1,4 +1,4 @@-.TH UGREP "1" "March 01, 2025" "ugrep 7.3.0" "User Commands"+.TH UGREP "1" "March 03, 2025" "ugrep 7.3.0" "User Commands" .SH NAME \fBugrep\fR, \fBug\fR -- file pattern searcher .SH SYNOPSIS@@ -17,10 +17,11 @@ regular expression matches one or more newlines.  An empty pattern matches every line.  Each input line that matches at least one of the patterns is written to the standard output. .PP-The \fBug\fR command is intended for interactive searching, using a .ugrep-configuration file located in the working directory or home directory, see-CONFIGURATION.  \fBug\fR is equivalent to \fBugrep --config --pretty --sort\fR-to load a .ugrep file, enhance the terminal output, and sort files by name.+The \fBug\fR command is intended for interactive searching, using a `.ugrep'+configuration file located in the working directory or, if not found, in the+home directory, see CONFIGURATION.  \fBug\fR is equivalent to \fBugrep --config+--pretty --sort\fR to load a configuration file, enhance the terminal output,+and to sort files by name. .PP The \fBugrep+\fR and \fBug+\fR commands are the same as the \fBugrep\fR and \fBug\fR commands, but also use filters to search pdfs, documents, e-books,@@ -257,8 +258,8 @@ Use configuration FILE.  The default FILE is `.ugrep'.  The working directory is checked first for FILE, then the home directory.  The options specified in the configuration FILE are parsed first, followed by the remaining options specified on the command line.-The ug command automatically loads a `.ugrep' configuration file,-unless \fB\-\-config\fR=\fIFILE\fR or \fB\-\-no\-config\fR is specified.+The ug command automatically loads a `.ugrep' configuration file+when present, unless \fB\-\-config\fR=\fIFILE\fR or \fB\-\-no\-config\fR is specified. .TP \fB\-\-no\-config\fR Do not automatically load the default .ugrep configuration file.@@ -775,8 +776,8 @@ which is automatically loaded by the ug command.  When FILE is a OPTIONS are saved that do not cause searches to fail when combined with other options.  Additional options may be specified by editing the saved configuration file.  A configuration file may be modified-manually to specify one or more config[=\fIFILE\fR] to indirectly load-the specified FILE, but recursive config loading is not allowed.+by adding one or more config=\fIFILE\fR to include configuration files,+but recursive configuration file inclusion is not permitted. .TP \fB\-\-separator\fR[=\fISEP\fR], \fB\-\-context\-separator\fR=\fISEP\fR Use SEP as field separator between file name, line number, column@@ -968,10 +969,10 @@ An error occurred. If \fB-q\fR or \fB--quiet\fR or \fB--silent\fR is used and a line is selected, the exit status is 0 even if an error occurred. .SH CONFIGURATION-The \fBug\fR command is intended for context-dependent interactive searching-and is equivalent to the \fBugrep --config --pretty --sort\fR command to load-the default configuration file `.ugrep' when present in the working directory-or in the home directory.+The \fBug\fR command is intended for interactive searching and is equivalent to+the \fBugrep --config --pretty --sort\fR command to load the `.ugrep`+configuration file located in the working directory or, when not found, in the+home directory. .PP A configuration file contains `NAME=VALUE' pairs per line, where `NAME` is the name of a long option (without `--') and `=VALUE' is an argument, which is@@ -980,8 +981,8 @@ starting with a `#' are ignored. .PP The \fB--config\fR=\fIFILE\fR option and its abbreviated form \fB---\fR\fIFILE\fR load the specified configuration file located in the-working directory or, when not found, located in the home directory.  An error-is produced when \fIFILE\fR is not found or cannot be read.+working directory or, when not found, in the home directory.  An error is+produced when \fIFILE\fR is not found or cannot be read. .PP Command line options are parsed in the following order: the configuration file is loaded first, followed by the remaining options and arguments on the command@@ -989,9 +990,10 @@ line. .PP The \fB--save-config\fR option saves a `.ugrep' configuration file to the working directory with a subset of the options specified on the command line.-The \fB--save-config\fR=\fIFILE\fR option saves the configuration to-\fIFILE\fR.  The configuration is written to standard output when \fIFILE\fR is-a `-'.+Only part of the specified options are saved that do not cause searches to fail+when combined with other options.  The \fB--save-config\fR=\fIFILE\fR option+saves the configuration to \fIFILE\fR.  The configuration is written to+standard output when \fIFILE\fR is a `-'. .SH GLOBBING Globbing is used by options \fB-g\fR, \fB--include\fR, \fB--include-dir\fR, \fB--include-from\fR, \fB--exclude\fR, \fB--exclude-dir\fR,

src/cnf.cpp

@@ -30,7 +30,7 @@ @file      cnf.cpp @brief     CNF class for normalization of Boolean search queries @author    Robert van Engelen - engelen@genivia.com-@copyright (c) 2019,2025, Robert van Engelen, Genivia Inc. All rights reserved.+@copyright (c) 2019-2025, Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt */ 

src/cnf.hpp

@@ -30,7 +30,7 @@ @file      cnf.hpp @brief     CNF class for normalization of Boolean search queries @author    Robert van Engelen - engelen@genivia.com-@copyright (c) 2019,2025, Robert van Engelen, Genivia Inc. All rights reserved.+@copyright (c) 2019-2025, Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt */ 

src/flag.hpp

@@ -30,7 +30,7 @@ @file      flag.hpp @brief     Tri-state Flag class and global flags set by options @author    Robert van Engelen - engelen@genivia.com-@copyright (c) 2019,2025, Robert van Engelen, Genivia Inc. All rights reserved.+@copyright (c) 2019-2025, Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt */ 

src/mmap.hpp

@@ -30,7 +30,7 @@ @file      mmap.hpp @brief     class to manage memory-mapped files @author    Robert van Engelen - engelen@genivia.com-@copyright (c) 2019,2025, Robert van Engelen, Genivia Inc. All rights reserved.+@copyright (c) 2019-2025, Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt */ 

src/output.cpp

@@ -30,7 +30,7 @@ @file      output.cpp @brief     Output management @author    Robert van Engelen - engelen@genivia.com-@copyright (c) 2019,2025, Robert van Engelen, Genivia Inc. All rights reserved.+@copyright (c) 2019-2025, Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt */ 

src/output.hpp

@@ -30,7 +30,7 @@ @file      output.hpp @brief     Output management @author    Robert van Engelen - engelen@genivia.com-@copyright (c) 2019,2025, Robert van Engelen, Genivia Inc. All rights reserved.+@copyright (c) 2019-2025, Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt */ 

src/query.cpp

@@ -30,7 +30,7 @@ @file      query.cpp @brief     Query engine TUI @author    Robert van Engelen - engelen@genivia.com-@copyright (c) 2019,2025, Robert van Engelen, Genivia Inc. All rights reserved.+@copyright (c) 2019-2025, Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt */ 

src/query.hpp

@@ -30,7 +30,7 @@ @file      query.hpp @brief     Query engine and UI @author    Robert van Engelen - engelen@genivia.com-@copyright (c) 2019,2025, Robert van Engelen, Genivia Inc. All rights reserved.+@copyright (c) 2019-2025, Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt */ 

src/screen.cpp

@@ -30,7 +30,7 @@ @file      screen.cpp @brief     ANSI SGR code controlled screen API - static, not thread safe @author    Robert van Engelen - engelen@genivia.com-@copyright (c) 2019,2025, Robert van Engelen, Genivia Inc. All rights reserved.+@copyright (c) 2019-2025, Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt */ 

src/screen.hpp

@@ -30,7 +30,7 @@ @file      screen.hpp @brief     ANSI SGR code controlled screen API - static, not thread safe @author    Robert van Engelen - engelen@genivia.com-@copyright (c) 2019,2025, Robert van Engelen, Genivia Inc. All rights reserved.+@copyright (c) 2019-2025, Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt */ 

src/stats.cpp

@@ -30,7 +30,7 @@ @file      stats.cpp @brief     collect global statistics - static, partially thread-safe @author    Robert van Engelen - engelen@genivia.com-@copyright (c) 2019,2025, Robert van Engelen, Genivia Inc. All rights reserved.+@copyright (c) 2019-2025, Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt */ 

src/stats.hpp

@@ -30,7 +30,7 @@ @file      stats.hpp @brief     collect global statistics - static, partially thread-safe (see below) @author    Robert van Engelen - engelen@genivia.com-@copyright (c) 2019,2025, Robert van Engelen, Genivia Inc. All rights reserved.+@copyright (c) 2019-2025, Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt  Thread-safe functions:

src/ugrep-indexer.cpp

@@ -30,7 +30,7 @@ @file      ugrep-indexer.cpp @brief     file system indexer for the ugrep search utility @author    Robert van Engelen - engelen@genivia.com-@copyright (c) 2023,2025 Robert van Engelen, Genivia Inc. All rights reserved.+@copyright (c) 2023-2025 Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt */ 

src/ugrep.cpp

@@ -30,7 +30,7 @@ @file      ugrep.cpp @brief     file pattern searcher @author    Robert van Engelen - engelen@genivia.com-@copyright (c) 2019,2025, Robert van Engelen, Genivia Inc. All rights reserved.+@copyright (c) 2019-2025, Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt  User manual:@@ -4550,7 +4550,7 @@ FILE *Static::output = stdout; // redirectable error output destination is standard error by default or a pipe FILE *Static::errout = stderr; -// full home directory path+// full home directory path or NULL to expand ~ in options with path arguments const char *Static::home_dir = NULL;  // Grep object handle, to cancel the search with cancel_ugrep()@@ -4859,37 +4859,48 @@ static void load_config(std::list<std::pair<CNF::PATTERN,const char*>>& pattern_   // if config file was parsed before, then only try parsing the home dir config file   bool home = flag_config_files.find(flag_config) != flag_config_files.end(); -  // open a local config file or in the home directory+  // open a config file in the working dir or in the home directory   std::string config_file(flag_config);   FILE *file = NULL;+   if (home || fopen_smart(&file, flag_config, "r") != 0)   {     file = NULL;++    // if not in the working directory, then check the home directory     if (Static::home_dir != NULL && *flag_config != '~' && *flag_config != PATHSEPCHR)     {       // check the home directory for the configuration file, parse only if not parsed before       config_file.assign(Static::home_dir).append(PATHSEPSTR).append(flag_config);       if (flag_config_files.find(config_file) != flag_config_files.end() ||           fopen_smart(&file, config_file.c_str(), "r") != 0)-      {         file = NULL;-      }-      else-      {-        // new config file in the home dir to parse, add to the set-        flag_config_files.insert(config_file);-      }     }-  }-  else-  {-    // new config file to parse, add to the set-    flag_config_files.insert(flag_config);++#if defined(WITH_XDG_CONFIG_HOME) && !defined(OS_WIN)+    // if the default configuration file is to be used, then check XDG_CONFIG_HOME/ugrep/config first+    if (file == NULL && strcmp(flag_config, ".ugrep") == 0)+    {+      // get XDG_CONFIG_HOME path, defaults to $HOME/.config/ugrep/config when present+      const char *xdg_config_home = getenv("XDG_CONFIG_HOME");+      if (xdg_config_home == NULL || *xdg_config_home == '\0')+        xdg_config_home = ".config";++      // check if $XDG_CONFIG_HOME/ugrep/config or $HOME/.config/ugrep/config is present to parse+      config_file.assign(xdg_config_home).append(PATHSEPSTR).append("ugrep").append(PATHSEPSTR).append("config");+      if (flag_config_files.find(config_file) != flag_config_files.end() ||+          fopen_smart(&file, config_file.c_str(), "r") != 0)+        file = NULL;+    }+#endif   }    // parse config file   if (file != NULL)   {+    // add config file path to the set+    flag_config_files.insert(config_file);+     reflex::BufferedInput input(file);      std::string line;@@ -4993,12 +5004,16 @@ static void save_config()   // if not saved to standard output ("-"), then inform user   if (!flag_no_messages && strcmp(flag_save_config, "-") != 0)   {-    if (flag_config == NULL)-      fprintf(Static::errout, "ugrep: saving configuration file %s\n", flag_save_config);-    else if (exists && strcmp(flag_config, flag_save_config) == 0)-      fprintf(Static::errout, "ugrep: updating configuration file %s\n", flag_save_config);-    else-      fprintf(Static::errout, "ugrep: saving configuration file %s with options based on %s\n", flag_save_config, flag_config);+    fprintf(Static::errout, "ugrep: %s configuration file %s", exists ? "updating" : "saving", flag_save_config);++    if (!flag_config_files.empty())+    {+      fprintf(Static::errout, " with options based on");+      for (const auto& i : flag_config_files)+        fprintf(Static::errout, " %s", i.c_str());+    }++    fprintf(Static::errout, "\n");   }    if (fopen_smart(&file, flag_save_config, "w") != 0)@@ -14053,8 +14068,8 @@ void help(std::ostream& out)             directory is checked first for FILE, then the home directory.  The\n\             options specified in the configuration FILE are parsed first,\n\             followed by the remaining options specified on the command line.\n\-            The ug command automatically loads a `.ugrep' configuration file,\n\-            unless --config=FILE or --no-config is specified.\n\+            The ug command automatically loads a `.ugrep' configuration file\n\+            when present, unless --config=FILE or --no-config is specified.\n\     --no-config\n\             Do not automatically load the default .ugrep configuration file.\n\     --no-confirm\n\@@ -14531,8 +14546,8 @@ void help(std::ostream& out)             OPTIONS are saved that do not cause searches to fail when combined\n\             with other options.  Additional options may be specified by editing\n\             the saved configuration file.  A configuration file may be modified\n\-            manually to specify one or more config[=FILE] to indirectly load\n\-            the specified FILE, but recursive config loading is not allowed.\n\+            by adding one or more config=FILE to include configuration files,\n\+            but recursive configuration file inclusion is not permitted.\n\     --separator[=SEP], --context-separator=SEP\n\             Use SEP as field separator between file name, line number, column\n\             number, byte offset and the matched line.  The default separator is\n\

src/ugrep.hpp

@@ -30,7 +30,7 @@ @file      ugrep.hpp @brief     file pattern searcher @author    Robert van Engelen - engelen@genivia.com-@copyright (c) 2019,2025, Robert van Engelen, Genivia Inc. All rights reserved.+@copyright (c) 2019-2025, Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt */ @@ -63,6 +63,9 @@ // modifiers: h=highlight, u=underline, i=invert, f=faint, n=normal, H=highlight off, U=underline off, I=invert off #define WITH_EASY_GREP_COLORS +// use $XDG_CONFIG_HOME/ugrep/config for ug (or ugrep --config) when no .ugrep files are found, migh be confusing!+// #define WITH_XDG_CONFIG_HOME+ // check if we are compiling for a windows OS, but not Cygwin or MinGW #if (defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__BORLANDC__)) && !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(__MINGW64__) # define OS_WIN

src/vkey.cpp

@@ -30,7 +30,7 @@ @file      vkey.cpp @brief     Virtual terminal keyboard input API - static, not thread safe @author    Robert van Engelen - engelen@genivia.com-@copyright (c) 2019,2025, Robert van Engelen, Genivia Inc. All rights reserved.+@copyright (c) 2019-2025, Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt */ 

src/vkey.hpp

@@ -30,7 +30,7 @@ @file      vkey.hpp @brief     Virtual terminal keyboard input API - static, not thread safe @author    Robert van Engelen - engelen@genivia.com-@copyright (c) 2019,2025, Robert van Engelen, Genivia Inc. All rights reserved.+@copyright (c) 2019-2025, Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt  Supports Unix/Linux, MacOS, DOS, and Windows.

src/zstream.hpp

@@ -30,7 +30,7 @@ @file      zstream.hpp @brief     file decompression streams - zstreambuf extends std::streambuf @author    Robert van Engelen - engelen@genivia.com-@copyright (c) 2019,2025, Robert van Engelen, Genivia Inc. All rights reserved.+@copyright (c) 2019-2025, Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt */ 

src/zthread.hpp

@@ -30,7 +30,7 @@ @file      zthread.hpp @brief     file decompression threads @author    Robert van Engelen - engelen@genivia.com-@copyright (c) 2019,2025, Robert van Engelen, Genivia Inc. All rights reserved.+@copyright (c) 2019-2025, Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt */