Dup Goto 📝

TidyPath

PT2/lang/cpp/random 07-31 13:46:47
To Pop
146 lines, 439 words, 3391 chars Monday 2023-07-31 13:46:47

This takes the PATH environment variable and filters out duplicates and nonexistent directories. (I originally used a Perl script, but rewrote in c++ for speed.)

#include <iostream>
#include <set>
#include <unordered_set>
#include <string>
#include <vector>
#include <sstream>
#include <iterator>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

using namespace std;

bool exists(const string& s) {
  const char* a = s.c_str();
  struct stat statbuf;
  if( stat(a,&statbuf) == 0 ) return true;
  return false;
}

vector<string> split(const string& str, const string& delim)
{
    vector<string> tokens;
    size_t prev = 0, pos = 0;
    do
    {
        pos = str.find(delim, prev);
        if (pos == string::npos) pos = str.length();
        string token = str.substr(prev, pos-prev);
        if (!token.empty()) tokens.push_back(token);
        prev = pos + delim.length();
    }
    while (pos < str.length() && prev < str.length());
    return tokens;
}

bool compstr(const char* a, const char* b, int l) {
  int i;
  for( i=0; i<l; i++ ) {
    if( a[i] != b[i] ) return false;
  }
  return true;
}

int main(int argc, char *argv[], char *envp[]) {
  char* path = nullptr;
  while(*envp) {
    if( compstr(*envp,"PATH=",5) ) {
      path = *envp;
      break;
    }
    envp++;
  }
  if( path != nullptr ) {
    path += 5;
    unordered_set<string> xs;
    vector<string> pcs = split(path,":");
    vector<string> npath;
    for( auto s : pcs ) {
      if( xs.count(s) == 0 ) {
        if( exists(s) ) {
          npath.push_back(s);
        }
        xs.insert(s);
      }
    }
    const char* const delim = ":";
    ostringstream imploded;
    copy(npath.begin(), npath.end(),
           ostream_iterator<string>(imploded, delim));
    cout << imploded.str() << "\n";
  } else {
    cerr << "no path" << endl;
  }
}

Filterpath

A slight more general variation of the above, this takes path components on the command line.

#include <iostream>
#include <set>
#include <unordered_set>
#include <string>
#include <vector>
#include <sstream>
#include <iterator>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

using namespace std;

bool exists(const string& s) {
  const char* a = s.c_str();
  return false;
}

vector<string> split(const string& str, const string& delim)
{
    vector<string> tokens;
    size_t prev = 0, pos = 0;
    do
    {
        pos = str.find(delim, prev);
        if (pos == string::npos) pos = str.length();
        string token = str.substr(prev, pos-prev);
        if (!token.empty()) tokens.push_back(token);
        prev = pos + delim.length();
    }
    while (pos < str.length() && prev < str.length());
    return tokens;
}

int main(int argc, char *argv[]) {
  const char* const delim = ":";
  unordered_set<string> xs;
  vector<string> npath;
  struct stat statbuf;
  for(int i=1; i<argc; i++) {
    vector<string> pcs = split(argv[i],delim);
    for( auto s : pcs ) {
      if( xs.count(s) == 0 ) {
        if( stat(s.c_str(),&statbuf) == 0 ) {
          npath.push_back(s);
        }
        xs.insert(s);
      }
    }
  }
  ostringstream imploded;
  copy(npath.begin(), npath.end(),
          ostream_iterator<string>(imploded, delim));
  string result = imploded.str();
  if( result.length() == 0 ) return 0;
  result = result.substr(0,result.length()-1);
  cout << result << "\n";
}