Skip to main content

The aliases.cpp File Reference

Included Headers

#include <unordered_map> #include <cassert> #include "message.h" #include "aliases.h" #include "containers.h" #include "config.h" #include "regex.h" #include "textstream.h" #include "util.h" #include "debug.h" #include "stringutil.h"

Classes Index

structAliasInfo
structMarker

Typedefs Index

usingAliasOverloads = std::unordered_map< int, AliasInfo >
usingAliasInfoMap = std::unordered_map< std::string, AliasOverloads >

Functions Index

static std::stringexpandAliasRec (StringUnorderedSet &aliasesProcessed, std::string_view s, bool allowRecursion=FALSE)
static intcountAliasArguments (std::string_view args, std::string_view sep)
static std::stringextractAliasArgs (std::string_view args)
static std::stringexpandAlias (std::string_view aliasName, std::string_view aliasValue)
static voidaddValidAliasToMap (std::string_view alias)
static std::stringescapeAlias (std::string_view value)
voidreadAliases ()
static size_tfindEndOfCommand (std::string_view s)

For a string s that starts with a command name, returns the character offset within that string representing the first character after the command. More...

static std::stringreplaceAliasArguments (StringUnorderedSet &aliasesProcessed, std::string_view aliasValue, std::string_view argList, std::string_view sep)

Replaces the markers in an alias definition aliasValue with the corresponding values found in the comma separated argument list argList and the returns the result after recursive alias expansion. More...

static std::stringescapeSeparators (const std::string &s, const std::string &sep)
std::stringresolveAliasCmd (std::string_view aliasCmd)
boolisAliasCmd (std::string_view aliasCmd)

Variables Index

static AliasInfoMapg_aliasInfoMap

Typedefs

AliasInfoMap

using AliasInfoMap = std::unordered_map<std::string,AliasOverloads>

Definition at line 40 of file aliases.cpp.

40using AliasInfoMap = std::unordered_map<std::string,AliasOverloads>; // key = alias name (with parameter part)

AliasOverloads

using AliasOverloads = std::unordered_map<int,AliasInfo>

Definition at line 39 of file aliases.cpp.

39using AliasOverloads = std::unordered_map<int,AliasInfo>; // key = parameter count

Functions

addValidAliasToMap()

void addValidAliasToMap (std::string_view alias)
static

Definition at line 56 of file aliases.cpp.

56static void addValidAliasToMap(std::string_view alias)
57{
58 bool valid = true;
59 std::string aliasName;
60 std::string aliasValue;
61 int numParams = 0;
62 std::string separator;
63
64 static std::string_view separators = "!#$%&,.?|;:'+=~`/";
65 auto isValidSeparator = [](char c) -> bool { return separators.find(c)!=std::string::npos; };
66
67 static const reg::Ex re1(R"(^\a[\w-]*\s*=)");
68 static const reg::Ex re2(R"(^\a[\w-]*{[^}]*}\s*=)");
69 if (reg::search(std::string{alias},re1) || reg::search(std::string{alias},re2)) // valid name= or name{...}= part
70 {
71 size_t i=alias.find('=');
72 assert(i!=std::string::npos); // based on re1 and re2 there is always a =
73 std::string name{ stripWhiteSpace(alias.substr(0,i)) };
74 aliasValue = alias.substr(i+1);
75 //printf("Alias: found name='%s' value='%s'\n",qPrint(name),qPrint(aliasValue));
76 size_t l = name.length();
77 size_t j = name.find('{');
78 if (j!=std::string::npos) // alias with parameters
79 {
80 if (name[l-1]=='}')
81 {
82 separator=",";
83 size_t k=j+1;
84 while (k<l-1 && isdigit(name[k])) k++;
85 numParams = atoi(name.substr(j+1,k-j-1).c_str());
86 if (numParams>0)
87 {
88 if (k<l-1) // we have a separator
89 {
90 size_t m=k;
91 while (m<l && isValidSeparator(name[m])) m++;
92 if (m<l-1)
93 {
94 err("Invalid alias '{}': invalid separator character '{:c}' (code {:d}), allowed characters: {}. Check your config file.\n",alias,name[m],name[m],std::string{separators});
95 valid=false;
96 }
97 else
98 {
99 separator=name.substr(k,l-k-1);
100 }
101 }
102 if (valid) // valid alias with parameters
103 {
104 aliasName = name.substr(0,j);
105 Debug::print(Debug::Alias,0,"Alias definition: name='{}' #param='{}' separator='{}' value='{}'\n",
106 aliasName,numParams,separator,aliasValue);
107 }
108 }
109 else
110 {
111 err("Invalid alias '{}': missing number of parameters. Check your config file.\n",std::string{alias});
112 valid=false;
113 }
114 }
115 else
116 {
117 err("Invalid alias '{}': missing closing bracket. Check your config file.\n",std::string{alias});
118 valid=false;
119 }
120 }
121 else // valid alias without parameters
122 {
123 aliasName = name;
124 numParams = 0;
125 Debug::print(Debug::Alias,0,"Alias definition: name='{}' value='{}'\n",aliasName,aliasValue);
126 }
127 }
128 else
129 {
130 err("Invalid alias '{}': invalid 'name=' or 'name{{...}}=' part. Check you config file.\n",std::string{alias});
131 valid=false;
132 }
133
134 if (valid) // alias definition passed all checks, so store it.
135 {
136 auto it = g_aliasInfoMap.find(aliasName);
137 if (it==g_aliasInfoMap.end()) // insert new alias
138 {
139 AliasOverloads overloads { { numParams, AliasInfo(aliasValue, separator) } };
140 g_aliasInfoMap.emplace(aliasName,overloads);
141 }
142 else // replace exiting alias with new definition
143 {
144 auto it2 = it->second.find(numParams);
145 if (it2==it->second.end()) // new alias overload for the given number of parameters
146 {
147 it->second.emplace(numParams, AliasInfo(aliasValue,separator));
148 }
149 else // replace alias with new definition
150 {
151 it2->second = AliasInfo(aliasValue,separator);
152 }
153 }
154 }
155}

References Debug::Alias, err, g_aliasInfoMap, Debug::print, reg::search and stripWhiteSpace.

Referenced by readAliases.

countAliasArguments()

int countAliasArguments (std::string_view args, std::string_view sep)
static

Definition at line 450 of file aliases.cpp.

450static int countAliasArguments(std::string_view args, std::string_view sep)
451{
452 int count = 1;
453 size_t l = args.length();
454 for (size_t i=0;i<l;i++)
455 {
456 char c = args[i];
457 if (!sep.empty() &&
458 c==sep[0] && // start with separator character
459 (i==0 || args[i-1]!='\\') && // is not escaped
460 args.substr(i,sep.length())==sep) // whole separator matches
461 {
462 count++;
463 }
464 else if (c=='@' || c=='\\')
465 {
466 // check if this is the start of another aliased command (see bug704172)
467 i += findEndOfCommand(args.substr(i+1));
468 }
469 }
470 //printf("countAliasArguments(%s,sep=%s)=%d\n",qPrint(args),qPrint(sep),count);
471 return count;
472}

Reference findEndOfCommand.

Referenced by expandAliasRec.

escapeAlias()

std::string escapeAlias (std::string_view value)
static

Definition at line 160 of file aliases.cpp.

160static std::string escapeAlias(std::string_view value)
161{
162 std::string newValue = substituteStringView(value,"^^ ","@ilinebr ");
163 newValue = substituteStringView(newValue,"^^","@ilinebr ");
164 //printf("escapeAlias('%s')='%s'\n",qPrint(std::string{value}),qPrint(newValue));
165 return newValue;
166}

Reference substituteStringView.

Referenced by readAliases.

escapeSeparators()

std::string escapeSeparators (const std::string & s, const std::string & sep)
static

Definition at line 323 of file aliases.cpp.

323static std::string escapeSeparators(const std::string &s, const std::string &sep)
324{
325 if (s.empty() || sep.empty()) return s;
326 std::string result;
327 result.reserve(s.length()+10);
328 size_t i, p=0, l=sep.length();
329 while ((i=s.find(sep,p))!=std::string::npos)
330 {
331 result += s.substr(p,i-p);
332 if (i>0 && s[i-1]!='\\') // escape the separator
333 {
334 result += '\\';
335 }
336 result += s.substr(i,l);
337 p = i+l;
338 }
339 result += s.substr(p);
340 //printf("escapeSeparators(%s,sep='%s')=%s\n",qPrint(s),qPrint(sep),qPrint(result));
341 return result;
342}

Referenced by expandAliasRec.

expandAlias()

std::string expandAlias (std::string_view aliasName, std::string_view aliasValue)
static

Definition at line 514 of file aliases.cpp.

514static std::string expandAlias(std::string_view aliasName,std::string_view aliasValue)
515{
516 std::string result;
517 StringUnorderedSet aliasesProcessed;
518 // avoid expanding this command recursively
519 aliasesProcessed.insert(std::string{aliasName});
520 // expand embedded commands
521 //printf("Expanding: '%s'->'%s'\n",qPrint(aliasName),qPrint(aliasValue));
522 result = expandAliasRec(aliasesProcessed,aliasValue);
523 //printf("Expanding result: '%s'->'%s'\n",qPrint(aliasName),qPrint(result));
524 Debug::print(Debug::Alias,0,"Expanding alias: input='{}' result='{}'\n",std::string{aliasValue},result);
525 return result;
526}

References Debug::Alias, expandAliasRec and Debug::print.

Referenced by readAliases.

expandAliasRec()

std::string expandAliasRec (StringUnorderedSet & aliasesProcessed, std::string_view s, bool allowRecursion=FALSE)
static

Definition at line 344 of file aliases.cpp.

344static std::string expandAliasRec(StringUnorderedSet &aliasesProcessed,std::string_view s,bool allowRecursion)
345{
346 std::string result;
347 static const reg::Ex re(R"([\\@](\a[\w-]*))");
348 std::string str{s};
349 reg::Match match;
350 size_t p = 0;
351 while (reg::search(str,match,re,p))
352 {
353 size_t i = match.position();
354 size_t l = match.length();
355 if (i>p) result+=s.substr(p,i-p);
356
357 std::string args = extractAliasArgs(s.substr(i+l));
358 bool hasArgs = !args.empty(); // found directly after command
359 size_t argsLen = args.length();
360 std::string cmd = match[1].str();
361 int selectedNumArgs = -1;
362 //printf("looking for alias '%s' with params '%s'\n",qPrint(cmd),qPrint(args));
363 auto it = g_aliasInfoMap.find(cmd);
364 if (it == g_aliasInfoMap.end())
365 {
366 // if command has a - then also try part in without it
367 size_t minusPos = cmd.find('-');
368 if (minusPos!=std::string::npos)
369 {
370 it = g_aliasInfoMap.find(cmd.substr(0,minusPos));
371 if (it!=g_aliasInfoMap.end()) // found part before - as alias
372 {
373 cmd = cmd.substr(0,minusPos);
374 args = "";
375 hasArgs = false;
376 argsLen = 0;
377 l = cmd.length()+1; // 1 for the minus sign
378 }
379 }
380 }
381 if (it != g_aliasInfoMap.end()) // cmd is an alias
382 {
383 //printf("found an alias, hasArgs=%d\n",hasArgs);
384 if (hasArgs)
385 {
386 // Find the an alias that matches the number of arguments.
387 // If there are multiple candidates, take the one that matches the most parameters
388 for (const auto &[numParams,aliasInfo] : it->second)
389 {
390 int numArgs = countAliasArguments(args,aliasInfo.separator);
391 if (numParams==numArgs && numArgs>selectedNumArgs)
392 {
393 selectedNumArgs = numArgs;
394 }
395 }
396 if (selectedNumArgs==-1) // no match found, check if there is an alias with one argument
397 {
398 auto it2 = it->second.find(1);
399 if (it2 != it->second.end())
400 {
401 args = escapeSeparators(args,it2->second.separator); // escape separator so that everything is seen as one argument
402 selectedNumArgs = 1;
403 }
404 }
405 }
406 else
407 {
408 selectedNumArgs = 0;
409 }
410 }
411 else
412 {
413 //printf("Alias %s not found\n",qPrint(cmd));
414 }
415 //printf("Found command s='%s' cmd='%s' numArgs=%d args='%s'\n", qPrint(s),qPrint(cmd),selectedNumArgs,qPrint(args));
416 std::string qualifiedName = cmd+":"+std::to_string(selectedNumArgs);
417 if ((allowRecursion || aliasesProcessed.find(qualifiedName)==aliasesProcessed.end()) &&
418 it!=g_aliasInfoMap.end() && selectedNumArgs!=-1 &&
419 it->second.find(selectedNumArgs)!=it->second.end()) // expand the alias
420 {
421 const auto &aliasInfo = it->second.find(selectedNumArgs)->second;
422 //printf("is an alias with separator='%s' selectedNumArgs=%d hasArgs=%d!\n",qPrint(aliasInfo.separator),selectedNumArgs,hasArgs);
423 if (!allowRecursion) aliasesProcessed.insert(qualifiedName);
424 std::string val = aliasInfo.value;
425 if (hasArgs)
426 {
427 //printf("before replaceAliasArguments(val='%s')\n",qPrint(val));
428 val = replaceAliasArguments(aliasesProcessed,val,args,aliasInfo.separator);
429 //printf("after replaceAliasArguments sep='%s' val='%s' args='%s'\n",
430 // qPrint(aliasInfo.separator),qPrint(val),qPrint(args));
431 }
432 result += expandAliasRec(aliasesProcessed,val);
433 if (!allowRecursion) aliasesProcessed.erase(qualifiedName);
434 p = i+l;
435 if (hasArgs) p += argsLen+2;
436 }
437 else // command is not an alias
438 {
439 //printf("not an alias!\n");
440 result += match.str();
441 p = i+l;
442 }
443 }
444 result += s.substr(p);
445 //printf("expandAliases \"%s\"->\"%s\"\n",qPrint(s),qPrint(result));
446 return result;
447}

References countAliasArguments, escapeSeparators, expandAliasRec, extractAliasArgs, g_aliasInfoMap, replaceAliasArguments and reg::search.

Referenced by expandAlias, expandAliasRec, replaceAliasArguments and resolveAliasCmd.

extractAliasArgs()

std::string extractAliasArgs (std::string_view args)
static

Definition at line 474 of file aliases.cpp.

474static std::string extractAliasArgs(std::string_view args)
475{
476 int bc = 0;
477 char prevChar = 0;
478 if (!args.empty() && args[0]=='{') // alias has argument
479 {
480 for (size_t i=0;i<args.length();i++)
481 {
482 char c = args[i];
483 if (prevChar!='\\') // not escaped
484 {
485 if (c=='{') bc++;
486 if (c=='}') bc--;
487 prevChar=c;
488 }
489 else
490 {
491 prevChar=0;
492 }
493
494 if (bc==0)
495 {
496 //printf("extractAliasArgs('%s')->'%s'\n",qPrint(args),qPrint(args.substr(1,i-1)));
497 return std::string{args.substr(1,i-1)};
498 }
499 }
500 }
501 return std::string{};
502}

Referenced by expandAliasRec and findEndOfCommand.

findEndOfCommand()

size_t findEndOfCommand (std::string_view s)
static

For a string s that starts with a command name, returns the character offset within that string representing the first character after the command.

For an alias with argument, this is the offset to the character just after the argument list.

Examples:

  • s=="a b" returns 1
  • s=="a{2,3} b" returns 6 = s=="#" returns 0

Definition at line 214 of file aliases.cpp.

214static size_t findEndOfCommand(std::string_view s)
215{
216 char c=' ';
217 size_t i=0;
218 if (!s.empty())
219 {
220 while (i<s.length() && (c=s[i]) && isId(c)) i++;
221 if (c=='{') i+=extractAliasArgs(s.substr(i)).length()+2; // 2 for '{' and '}'
222 }
223 return i;
224}

References extractAliasArgs and isId.

Referenced by countAliasArguments and replaceAliasArguments.

isAliasCmd()

bool isAliasCmd (std::string_view aliasCmd)

Definition at line 528 of file aliases.cpp.

528bool isAliasCmd(std::string_view aliasCmd)
529{
530 return g_aliasInfoMap.find(std::string{aliasCmd}) != g_aliasInfoMap.end();
531}

Reference g_aliasInfoMap.

Referenced by DocPara::handleCommand.

readAliases()

void readAliases ()

Definition at line 170 of file aliases.cpp.

171{
172 // add aliases to a dictionary
173 const StringVector &aliasList = Config_getList(ALIASES);
174 for (const auto &al : aliasList)
175 {
177 }
178 for (auto &[name,overloads] : g_aliasInfoMap)
179 {
180 for (auto &[numParams,aliasInfo] : overloads)
181 {
182 aliasInfo.value = expandAlias(name+":"+std::to_string(numParams),aliasInfo.value);
183 }
184 }
185 for (auto &[name,overloads] : g_aliasInfoMap)
186 {
187 for (auto &[numParams,aliasInfo] : overloads)
188 {
189 aliasInfo.value = escapeAlias(aliasInfo.value);
190 }
191 }
192}

References addValidAliasToMap, Config_getList, escapeAlias, expandAlias and g_aliasInfoMap.

Referenced by adjustConfiguration.

replaceAliasArguments()

std::string replaceAliasArguments (StringUnorderedSet & aliasesProcessed, std::string_view aliasValue, std::string_view argList, std::string_view sep)
static

Replaces the markers in an alias definition aliasValue with the corresponding values found in the comma separated argument list argList and the returns the result after recursive alias expansion.

Definition at line 230 of file aliases.cpp.

230static std::string replaceAliasArguments(StringUnorderedSet &aliasesProcessed,
231 std::string_view aliasValue,std::string_view argList,
232 std::string_view sep)
233{
234 //printf("----- replaceAliasArguments(val=[%s],args=[%s],sep=[%s])\n",qPrint(aliasValue),qPrint(argList),qPrint(sep));
235
236 // first make a list of arguments from the comma separated argument list
238 size_t l=argList.length();
239 size_t p=0;
240 for (size_t i=0;i<l;i++)
241 {
242 char c = argList[i];
243 if (!sep.empty() &&
244 c==sep[0] && // start with separator character
245 (i==0 || argList[i-1]!='\\') && // is not escaped
246 argList.substr(i,sep.length())==sep) // whole separator matches
247 {
248 args.push_back(argList.substr(p,i-p));
249 p = i+sep.length(); // start of next argument
250 i = p-1; // compensate with -1 for loop iterator
251 }
252 else if (c=='@' || c=='\\') // command
253 {
254 // check if this is the start of another aliased command (see bug704172)
255 i+=findEndOfCommand(argList.substr(i+1));
256 }
257 }
258 if (l>p) args.push_back(argList.substr(p));
259 //printf("found %zu arguments\n",args.size());
260
261 // next we look for the positions of the markers and add them to a list
262 std::vector<Marker> markerList;
263 l = aliasValue.length();
264 char pc = '\0';
265 bool insideMarkerId = false;
266 size_t markerStart = 0;
267 auto isDigit = [](char c) { return c>='0' && c<='9'; };
268 for (size_t i=0;i<=l;i++)
269 {
270 char c = i<l ? aliasValue[i] : '\0';
271 if (insideMarkerId && !isDigit(c)) // found end of a markerId
272 {
273 insideMarkerId = false;
274 size_t markerLen = i-markerStart;
275 markerList.emplace_back(markerStart-1,
276 static_cast<size_t>(std::stoi(std::string{aliasValue.substr(markerStart,markerLen)})),
277 markerLen+1);
278 }
279 if (c=='\\' && (pc=='@' || pc=='\\')) // found escaped backslash
280 {
281 // skip
282 pc = '\0';
283 }
284 else
285 {
286 if (isDigit(c) && pc=='\\') // found start of a markerId
287 {
288 insideMarkerId=true;
289 markerStart=i;
290 }
291 pc = c;
292 }
293 }
294
295 // then we replace the markers with the corresponding arguments in one pass
296 std::string result;
297 p = 0;
298 for (const Marker &m : markerList)
299 {
300 result+=aliasValue.substr(p,m.pos-p);
301 //printf("part before marker: '%s'\n",qPrint(aliasValue.substr(p,m.pos-p)));
302 if (m.number>0 && m.number<=args.size()) // valid number
303 {
304 result+=expandAliasRec(aliasesProcessed,args[m.number-1],true);
305 //printf("marker index=%zu pos=%zu number=%zu size=%zu replacement %s\n",i,m.pos,m.number,m.size,
306 // qPrint(args[m.number-1]));
307 }
308 p=m.pos+m.size; // continue after the marker
309 }
310 result+=aliasValue.substr(p); // append remainder
311 //printf("string after replacement of markers: '%s'\n",qPrint(result));
312
313 // expand the result again
314 substituteInplace(result,"\\{","{");
315 substituteInplace(result,"\\}","}");
316 substituteInplace(result,std::string{"\\"}+std::string{sep},sep);
317 result = expandAliasRec(aliasesProcessed,result);
318
319 //printf("final string '%s'\n",qPrint(result));
320 return result;
321}

References expandAliasRec, findEndOfCommand and substituteInplace.

Referenced by expandAliasRec.

resolveAliasCmd()

std::string resolveAliasCmd (std::string_view aliasCmd)

Definition at line 504 of file aliases.cpp.

504std::string resolveAliasCmd(std::string_view aliasCmd)
505{
506 StringUnorderedSet aliasesProcessed;
507 //printf("Expanding: '%s'\n",qPrint(aliasCmd));
508 std::string result = expandAliasRec(aliasesProcessed,aliasCmd);
509 //printf("Expanding result: '%s'->'%s'\n",qPrint(aliasCmd),qPrint(result));
510 Debug::print(Debug::Alias,0,"Resolving alias: cmd='{}' result='{}'\n",std::string{aliasCmd},result);
511 return result;
512}

References Debug::Alias, expandAliasRec and Debug::print.

Referenced by replaceAliases.

Variables

g_aliasInfoMap

AliasInfoMap g_aliasInfoMap
static

Definition at line 52 of file aliases.cpp.

Referenced by addValidAliasToMap, expandAliasRec, isAliasCmd and readAliases.


Generated via doxygen2docusaurus by Doxygen 1.14.0.