+ // Lambda handling the "/.." case:
+ // [] + "/.." ==> []
+ // [.] + "/.." ==> [./..]
+ // [foo] is always [./foo] due to init above
+ // [*/..] + "/.." ==> [*/../..]
+ // [*/foo] + "/.." ==> [*]
+ auto goParent_f = [&](){
+ if ( _name.empty() )
+ /*NOOP*/;
+ else if ( _name.size() == 1 ) // content is '.'
+ _name += "/..";
+ else
+ {
+ std::string::size_type pos = _name.rfind( "/" );
+ if ( pos == _name.size() - 3 && _name[pos+1] == '.' && _name[pos+2] == '.' )
+ _name += "/..";
+ else
+ _name.erase( pos );
+ }
+ };
+
+ for ( char ch : name_r )
+ {
+ switch ( ch )
+ {
+ case '/':
+ switch ( pending )
+ {
+ case P_none: pending = P_slash; break;
+ case P_slash: break;
+ case P_dot1: pending = P_slash; break;
+ case P_dot2: goParent_f(); pending = P_slash; break;
+ }
+ break;
+
+ case '.':
+ switch ( pending )
+ {
+ case P_none: _name += '.'; break;
+ case P_slash: pending = P_dot1; break;
+ case P_dot1: pending = P_dot2; break;
+ case P_dot2: _name += "/..."; pending = P_none; break;
+ }
+ break;
+
+ default:
+ switch ( pending )
+ {
+ case P_none: break;
+ case P_slash: _name += '/'; pending = P_none; break;
+ case P_dot1: _name += "/."; pending = P_none; break;
+ case P_dot2: _name += "/.."; pending = P_none; break;
+ }
+ _name += ch;
+ break;
+ }