• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

GothenburgBitFactory / taskwarrior / 12358478612

16 Dec 2024 05:59PM UTC coverage: 84.898% (-0.6%) from 85.522%
12358478612

push

github

web-flow
[pre-commit.ci] pre-commit autoupdate (#3725)

updates:
- [github.com/pre-commit/mirrors-clang-format: v19.1.4 → v19.1.5](https://github.com/pre-commit/mirrors-clang-format/compare/v19.1.4...v19.1.5)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

19276 of 22705 relevant lines covered (84.9%)

23265.72 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.36
/src/util.cpp
1
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Copyright 2006 - 2021, Tomas Babej, Paul Beckingham, Federico Hernandez.
4
//
5
// Permission is hereby granted, free of charge, to any person obtaining a copy
6
// of this software and associated documentation files (the "Software"), to deal
7
// in the Software without restriction, including without limitation the rights
8
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
// copies of the Software, and to permit persons to whom the Software is
10
// furnished to do so, subject to the following conditions:
11
//
12
// The above copyright notice and this permission notice shall be included
13
// in all copies or substantial portions of the Software.
14
//
15
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
// SOFTWARE.
22
//
23
// https://www.opensource.org/licenses/mit-license.php
24
//
25
////////////////////////////////////////////////////////////////////////////////
26

27
#include <cmake.h>
28
// cmake.h include header must come first
29

30
#include <format.h>
31
#include <shared.h>
32
// If <iostream> is included, put it after <stdio.h>, because it includes
33
// <stdio.h>, and therefore would ignore the _WITH_GETLINE.
34
#ifdef FREEBSD
35
#define _WITH_GETLINE
36
#endif
37
#include <Lexer.h>
38
#include <main.h>
39
#include <pwd.h>
40
#include <signal.h>
41
#include <stdint.h>
42
#include <stdio.h>
43
#include <stdlib.h>
44
#include <string.h>
45
#include <sys/select.h>
46
#include <sys/time.h>
47
#include <sys/types.h>
48
#include <sys/wait.h>
49
#include <unicode.h>
50
#include <unistd.h>
51
#include <utf8.h>
52
#include <util.h>
53

54
#include <algorithm>
55
#include <cstring>
56
#include <fstream>
57
#include <iostream>
58
#include <sstream>
59
#include <string>
60
#include <vector>
61

62
#define STRING_UTIL_CONFIRM_YES "yes"
63
#define STRING_UTIL_CONFIRM_YES_U "Yes"
64
#define STRING_UTIL_CONFIRM_NO "no"
65
#define STRING_UTIL_CONFIRM_ALL "all"
66
#define STRING_UTIL_CONFIRM_ALL_U "All"
67
#define STRING_UTIL_CONFIRM_QUIT "quit"
68

69
static const char* newline = "\n";
70
static const char* noline = "";
71

72
////////////////////////////////////////////////////////////////////////////////
73
static void signal_handler(int s) {
×
74
  if (s == SIGINT) {
×
75
    std::cout << "\n\nInterrupted: No changes made.\n";
×
76
    exit(1);
×
77
  }
78
}
×
79

80
////////////////////////////////////////////////////////////////////////////////
81
// 0 = no
82
// 1 = yes
83
// 2 = all
84
// 3 = quit
85
int confirm4(const std::string& question) {
27✔
86
  std::vector<std::string> options{STRING_UTIL_CONFIRM_YES_U, STRING_UTIL_CONFIRM_YES,
87
                                   STRING_UTIL_CONFIRM_NO,    STRING_UTIL_CONFIRM_ALL_U,
88
                                   STRING_UTIL_CONFIRM_ALL,   STRING_UTIL_CONFIRM_QUIT};
216✔
89
  std::vector<std::string> matches;
27✔
90

91
  signal(SIGINT, signal_handler);
27✔
92

93
  do {
94
    std::cout << question << " (" << options[1] << '/' << options[2] << '/' << options[4] << '/'
81✔
95
              << options[5] << ") ";
27✔
96

97
    std::string answer{""};
27✔
98
    std::getline(std::cin, answer);
27✔
99
    Context::getContext().debug("STDIN '" + answer + '\'');
27✔
100
    answer = std::cin.eof() ? STRING_UTIL_CONFIRM_QUIT : Lexer::lowerCase(Lexer::trim(answer));
78✔
101
    autoComplete(answer, options, matches, 1);  // Hard-coded 1.
27✔
102
  } while (!std::cin.eof() && matches.size() != 1);
27✔
103

104
  signal(SIGINT, SIG_DFL);
27✔
105

106
  if (matches.size() == 1) {
27✔
107
    if (matches[0] == STRING_UTIL_CONFIRM_YES_U)
27✔
108
      return 1;
×
109
    else if (matches[0] == STRING_UTIL_CONFIRM_YES)
27✔
110
      return 1;
13✔
111
    else if (matches[0] == STRING_UTIL_CONFIRM_ALL_U)
14✔
112
      return 2;
×
113
    else if (matches[0] == STRING_UTIL_CONFIRM_ALL)
14✔
114
      return 2;
5✔
115
    else if (matches[0] == STRING_UTIL_CONFIRM_QUIT)
9✔
116
      return 3;
4✔
117
  }
118

119
  return 0;
5✔
120
}
108✔
121

122
// Handle the generation of UUIDs on FreeBSD in a separate implementation
123
// of the uuid () function, since the API is quite different from Linux's.
124
// Also, uuid_unparse_lower is not needed on FreeBSD, because the string
125
// representation is always lowercase anyway.
126
// For the implementation details, refer to
127
// https://svnweb.freebsd.org/base/head/sys/kern/kern_uuid.c
128
#if defined(FREEBSD) || defined(OPENBSD)
129
const std::string uuid() {
130
  uuid_t id;
131
  uint32_t status;
132
  char* buffer(0);
133
  uuid_create(&id, &status);
134
  uuid_to_string(&id, &buffer, &status);
135

136
  std::string res(buffer);
137
  free(buffer);
138

139
  return res;
140
}
141
#else
142

143
////////////////////////////////////////////////////////////////////////////////
144
#ifndef HAVE_UUID_UNPARSE_LOWER
145
// Older versions of libuuid don't have uuid_unparse_lower(), only uuid_unparse()
146
void uuid_unparse_lower(uuid_t uu, char* out) {
147
  uuid_unparse(uu, out);
148
  // Characters in out are either 0-9, a-z, '-', or A-Z.  A-Z is mapped to
149
  // a-z by bitwise or with 0x20, and the others already have this bit set
150
  for (size_t i = 0; i < 36; ++i) out[i] |= 0x20;
151
}
152
#endif
153

154
const std::string uuid() {
2,798✔
155
  uuid_t id;
156
  uuid_generate(id);
2,798✔
157
  char buffer[100]{};
2,798✔
158
  uuid_unparse_lower(id, buffer);
2,798✔
159

160
  // Bug found by Steven de Brouwer.
161
  buffer[36] = '\0';
2,798✔
162

163
  return std::string(buffer);
5,596✔
164
}
165
#endif
166

167
// Collides with std::numeric_limits methods
168
#undef max
169

170
////////////////////////////////////////////////////////////////////////////////
171
// Accept a list of projects, and return an indented list that reflects the
172
// hierarchy.
173
//
174
//      Input  - "one"
175
//               "one.two"
176
//               "one.two.three"
177
//               "one.four"
178
//               "two"
179
//      Output - "one"
180
//               "  one.two"
181
//               "    one.two.three"
182
//               "  one.four"
183
//               "two"
184
//
185
// There are two optional arguments, 'whitespace', and 'delimiter',
186
//
187
//  - whitespace is the string used to build the prefixes of indented items.
188
//    - defaults to two spaces, "  "
189
//  - delimiter is the character used to split up projects into subprojects.
190
//    - defaults to the period, '.'
191
//
192
const std::string indentProject(const std::string& project,
42✔
193
                                const std::string& whitespace /* = "  " */,
194
                                char delimiter /* = '.' */) {
195
  // Count the delimiters in *i.
196
  std::string prefix = "";
42✔
197
  std::string::size_type pos = 0;
42✔
198
  std::string::size_type lastpos = 0;
42✔
199
  while ((pos = project.find(delimiter, pos + 1)) != std::string::npos) {
59✔
200
    if (pos != project.size() - 1) {
17✔
201
      prefix += whitespace;
15✔
202
      lastpos = pos;
15✔
203
    }
204
  }
205

206
  std::string child = "";
42✔
207
  if (lastpos == 0)
42✔
208
    child = project;
30✔
209
  else
210
    child = project.substr(lastpos + 1);
12✔
211

212
  return prefix + child;
84✔
213
}
42✔
214

215
////////////////////////////////////////////////////////////////////////////////
216
const std::vector<std::string> extractParents(const std::string& project,
64✔
217
                                              const char& delimiter /* = '.' */) {
218
  std::vector<std::string> vec;
64✔
219
  std::string::size_type pos = 0;
64✔
220
  std::string::size_type copyUntil = 0;
64✔
221
  while ((copyUntil = project.find(delimiter, pos + 1)) != std::string::npos) {
80✔
222
    if (copyUntil != project.size() - 1) vec.push_back(project.substr(0, copyUntil));
16✔
223
    pos = copyUntil;
16✔
224
  }
225
  return vec;
64✔
226
}
×
227

228
////////////////////////////////////////////////////////////////////////////////
229
#ifndef HAVE_TIMEGM
230
time_t timegm(struct tm* tm) {
231
  time_t ret;
232
  char* tz;
233
  tz = getenv("TZ");
234
  setenv("TZ", "UTC", 1);
235
  tzset();
236
  ret = mktime(tm);
237
  if (tz)
238
    setenv("TZ", tz, 1);
239
  else
240
    unsetenv("TZ");
241
  tzset();
242
  return ret;
243
}
244
#endif
245

246
////////////////////////////////////////////////////////////////////////////////
247
bool nontrivial(const std::string& input) {
76✔
248
  std::string::size_type i = 0;
76✔
249
  int character;
250
  while ((character = utf8_next_char(input, i)))
94✔
251
    if (!unicodeWhitespace(character)) return true;
84✔
252

253
  return false;
10✔
254
}
255

256
////////////////////////////////////////////////////////////////////////////////
257
const char* optionalBlankLine() {
1,396✔
258
  return Context::getContext().verbose("blank") ? newline : noline;
4,188✔
259
}
260

261
////////////////////////////////////////////////////////////////////////////////
262
void setHeaderUnderline(Table& table) {
396✔
263
  // If an alternating row color is specified, notify the table.
264
  if (Context::getContext().color()) {
396✔
265
    Color alternate(Context::getContext().config.get("color.alternate"));
170✔
266
    table.colorOdd(alternate);
85✔
267
    table.intraColorOdd(alternate);
85✔
268

269
    if (Context::getContext().config.getBoolean("fontunderline")) {
255✔
270
      table.colorHeader(Color("underline " + Context::getContext().config.get("color.label")));
54✔
271
    } else {
272
      table.colorHeader(Color(Context::getContext().config.get("color.label")));
134✔
273
      table.underlineHeaders();
67✔
274
    }
275
  } else {
276
    if (Context::getContext().config.getBoolean("fontunderline"))
933✔
277
      table.colorHeader(Color("underline"));
608✔
278
    else
279
      table.underlineHeaders();
7✔
280
  }
281
}
396✔
282

283
////////////////////////////////////////////////////////////////////////////////
284
// Perform strtol on a string and check if the extracted value matches.
285
//
286
bool extractLongInteger(const std::string& input, long& output) {
57✔
287
  output = strtol(input.c_str(), nullptr, 10);
57✔
288
  return (format("{1}", output) == input);
171✔
289
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc