LoginSignup
1
0

More than 5 years have passed since last update.

C言語 envpからPATHの値を配列に格納する

Last updated at Posted at 2016-12-02

myshell を作ってみる機会があって、その時書いたものをまとめます。

やりたいこと

実行ファイルに渡される環境変数に入っている、コマンドの在り処を char * 型の配列に入れます。

はじめに

環境変数が入っている envp[] はどんな状態なのかを調べました。

show_all.c
int show_all(char *envp[])
{
  while(*envp)
      printf("%s\n",*envp++);

  return 0;
}

こんな感じの関数を実行すると、 envp[18] に次のような値が入っていました。

PATH=/Library/Frameworks/Python.framework/Versions/3.5/bin:/Users/rild/.pyenv/bin:/Users/rild/.rbenv/shims:/opt/local/bin:/opt/local/sbin:/opt/local/bin:/opt/local/sbin:/Users/rild/.nvm/versions/node/v5.5.0/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Library/TeX/texbin:/Library/Frameworks/Python.framework/Versions/3.5/bin:/Users/rild/.pyenv/bin:/Users/rild/.rbenv/shims:/opt/local/bin:/opt/local/sbin:/Users/rild/.sdkman/candidates/kotlin/current/bin:/Users/rild/.sdkman/candidates/gradle/current/bin:/Users/rild/Library/Android/sdk/platform-tools:/Users/rild/Documents/android/apktool.jar:/usr/local/share/python:/Users/rild/Library/Android/sdk/platform-tools:/Users/rild/Documents/android/apktool.jar:/usr/local/share/python

ここから、 : で区切られた、コマンドのパスを取り出したかったのです。

目標

こんな感じにします。

path[0]=/Library/Frameworks/Python.framework/Versions/3.5/bin
path[1]=/Users/rild/.pyenv/bin
path[2]=/Users/rild/.rbenv/shims
path[3]=/opt/local/bin
path[4]=/opt/local/sbin
path[5]=/opt/local/bin
path[6]=/opt/local/sbin
path[7]=/Users/rild/.nvm/versions/node/v5.5.0/bin
path[8]=/usr/local/bin
path[9]=/usr/bin
path[10]=/bin
path[11]=/usr/sbin
path[12]=/sbin
path[13]=/opt/X11/bin
path[14]=/Library/TeX/texbin
path[15]=/Library/Frameworks/Python.framework/Versions/3.5/bin
path[16]=/Users/rild/.pyenv/bin
path[17]=/Users/rild/.rbenv/shims
path[18]=/opt/local/bin
path[19]=/opt/local/sbin
path[20]=/Users/rild/.sdkman/candidates/kotlin/current/bin
path[21]=/Users/rild/.sdkman/candidates/gradle/current/bin
path[22]=/Users/rild/Library/Android/sdk/platform-tools
path[23]=/Users/rild/Documents/android/apktool.jar
path[24]=/usr/local/share/python
path[25]=/Users/rild/Library/Android/sdk/platform-tools
path[26]=/Users/rild/Documents/android/apktool.jar
path[27]=/usr/local/share/python

コード

envp.c
#include <string.h>
#include <stdio.h>

// split funtion with `:`---> start
int iscolon(char p)
{
  return p == ':';
}

void
split_wthcolon(int *path_c, char *path[], char *p)
{
    *path_c = 0;

    for(;;) {
      while (iscolon(*p))
          p++;
      if (*p == '\0') return;
      path[(*path_c)++] = p;

      while (*p && !iscolon(*p)) {
        p++;
      }
      if (*p == '\0')
        return;
      *p++ = '\0';
    }
}
// split funtion <--- end

// search "PATH=" index --->
int get_path_index(char *envp[])
{
  int envc = 0;

  // find char * pointing "PATH=..."
  while(*envp) {
    if (!strncmp(*envp, "PATH=", 5)) {
      return envc;
    }
    envc++;
    envp++;
  }
  return 0;
}
// search "PATH=" index <--- end

// split to path array
int get_path_from_buf(int * path_c, char *path[], char *buf)
{
  int i;
  for (i = 0; i < 5; i++) buf++; // rm "PATH="
  split_wthcolon(path_c, path, buf);

  return 0;
}

int main(int argc, char *argv[], char *envp[])
{
  char buf[1024]; // PATH contains '762 words'

  strcpy(buf, envp[get_path_index(envp)]);
  fprintf(stderr, "%d\n", get_path_index(envp)); // 18
  fprintf(stderr, "%s\n", buf); // envp[18]

  char *path[32]; // PATH contatins '27' colon ':'
  int path_c; // path count
  get_path_from_buf(&path_c, path, buf);

  int i;
  for (i = 0; i < path_c; i++) {
    fprintf(stderr, "%s\n", path[i]);
  }

  return 0;
}

最初、 get_path_from_buf に直接 envp[get_path_index(envp)] を渡していたのですが、中身が書き換わってしまうため、値をコピーして引数に渡してみました。

最後に

for (i = 0; i < 5; i++) buf++; // rm "PATH=" のあたりとかすごくいけてないので、もっといい方法があるはず。。。

参考

追記

getenv関数にPATHを指定すれば、get_path_indexとかはいらなかったですね。
http://www.c-lang.net/general29/index.html

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0