разбить полное имя файла на части - PullRequest
4 голосов
/ 12 июня 2009

Я создаю функцию, которая разделит полное имя файла Unix (например, /home/earlz/test.bin) на отдельные части. У меня есть функция, и она отлично работает для первых двух частей, но после этого выдает ошибочный вывод ...

strlcpy_char скопирует строку, используя термин в качестве терминатора, а также 0. Если оно заканчивается термином, то термин будет последним символом строки, а затем будет нулевым.

возвращает длину строки trg ...

int strlcpy_char(char *trg,const char *src,int max,char term){
    int i;
    if(max==0){return 0;}
    for(i=0;i<max-1;i++){
            if(*src==0){
                    *trg=0;
                    return i;
            }
            if(*src==term){
                    *trg=term;
                    trg++;
                    *trg=0; //null terminate
                    return i+1;
            }
            *trg=*src;
            src++;
            trg++;
    }
    *trg=0;
    return max; 
}

.

int get_path_part(char *file,int n,char *buf){
    int i;
    int current_i=0;
    //file is assumed to start with '/'so it skips the first character.
    for(i=0;i<=n;i++){
            current_i++;
            current_i=strlcpy_char(buf,&file[current_i],MAX_PATH_PART_SIZE,'/');
            if(current_i<=1){ //zero length string..
                    kputs("!"); //just a debug message. This never happens with the example
                    return -1; //not enough parts to the path
            }
    }
    if(buf[current_i-1]=='/'){
            return 1; //is not the last part
    }else{
            return 0; //is the last part(the file part)
    }
}

Я использую этот код для проверки:

        kputs("test path: ");
        kgets(cmd);
        kputs("\n");
        char *tmp=malloc(256);
        int i=0;
        get_path_part(cmd,i,tmp);
        kputs(tmp);
        kputs("\n");
        i=1;
        get_path_part(cmd,i,tmp);
        kputs(tmp);
        kputs("\n");
        i=2;
        get_path_part(cmd,i,tmp);
        kputs(tmp);
        kputs("\n");

Когда я пытаюсь что-то вроде "/home/test.bin", он работает правильно, выводя

/home
/test.bin

Но когда я пытаюсь "/home/earlz/test.bin", я получаю

/home
/earlz
/arlz

Кто-нибудь видит проблему в моем коде, поскольку я искал, но я просто не вижу никакой проблемы.

Кроме того, прежде чем сказать «но есть библиотека для этого», я делаю это в ядре операционной системы, поэтому у меня едва хватает стандартной библиотеки. У меня есть только части string.h, и на самом деле это стандартно.

Ответы [ 7 ]

4 голосов
/ 12 июня 2009

Вы перезаписываете current_i вместо того, чтобы добавлять его по ходу пути.

So

current_i++;
current_i=strlcpy_char(buf,&file[current_i],MAX_PATH_PART_SIZE,'/');

действительно должно быть

current_i += strlcpy_char(buf,&file[current_i+1],MAX_PATH_PART_SIZE,'/');
2 голосов
/ 12 июня 2009

Вам не нужно делать что-то вроде

tocurrent_i += strlcpy_char...

вместо

tocurrent_i = strlcpy_char...
2 голосов
/ 12 июня 2009

Я думаю, вам нужно отследить ваш current_i для i> 1, поскольку максимальное значение, возвращаемое из strlcpy, не имеет представления о том, где вы находитесь в общей строке файла. имеет ли смысл?

current_i=strlcpy_char(buf,&file[current_i],MAX_PATH_PART_SIZE,'/');
0 голосов
/ 12 июня 2009

Попробуйте что-нибудь наподобие приведенного ниже кода.

Если вам нужны реализации стандартных функций C (например, strchr ()), попробуйте koders.com или просто google для strchr.c.

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

const char *NextToken(const char *pStart, char chSep, char *pToken, size_t nTokMax)
{
    const char *pEnd;
    size_t nLength;

    /* set output to empty */
    *pToken=0;

    /* make sure input is OK */
    if (!pStart || *pStart!=chSep)
        return NULL;

    /* find end of token */
    pEnd = strchr(pStart+1, chSep);
    if (pEnd)
        nLength = pEnd - pStart;
    else
        nLength = strlen(pStart);

    if (nLength >= nTokMax) /* too big */
        return NULL;

    strncpy(pToken, pStart, nLength);
    pToken[nLength] = 0;

    return pEnd;
}

int main()
{
    #define BUFFSIZE 256
    char cmd[BUFFSIZE];
    char tmp[BUFFSIZE];
    const char *pStart=cmd;
    int i=0;

    puts("test path: ");
    fgets(cmd, BUFFSIZE, stdin);
    puts("");

    do {
        pStart = NextToken(pStart, '/', tmp, BUFFSIZE);
        if (tmp[0])
            puts(tmp);
    } while (pStart);
    return 0;
}
0 голосов
/ 12 июня 2009

Вот как бы я это сделал

char ** split_into_parts(char *path) {
  char ** parts = malloc(sizeof(char *) * 100);
  int i = 0;
  int j = 0;

  if (*path == '/') {
    path++;
  }

  parts[0] = 0;
  while (*path) {
    if (*path == '/') {
      parts[i][j] = 0;
      i++;
      parts[i] = 0;
      j = 0;
    } else {
      if (parts[i] == 0) {
        parts[i] = malloc(sizeof(char) * 100);
      }
      parts[i][j] = *path;
      j++;
    }
    path++;
  }
  parts[i+1] = 0;

  return parts;
}
0 голосов
/ 12 июня 2009

Если вы используете Glib, g_strsplit очень удобен и прост в использовании.

0 голосов
/ 12 июня 2009

Ваш код должен быть повторно введен? Если не использовать strtok, он находится в strings.h

STRTOK(P)

NAME
       strtok, strtok_r - split string into tokens

SYNOPSIS
       #include <string.h>

       char *strtok(char *restrict s1, const char *restrict s2);

       char *strtok_r(char *restrict s, const char *restrict sep,
              char **restrict lasts);

Извините, что не комментировал ваш код:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...