1

For educational use I'm trying to implement a simple find program (similar to find(1) with much less functionality).

While implementing the first functionality - "-user " - I got challanged by combining two different functions (once for uid and once for name) with one "control-function?". I guess I'm looking for something similar like overloaded functions in C#, what's the best practice to solve such a problem in C?

I would appreciate a solution approach, which allows my program to process both options while calling it: E.g.:

  • "my_find -user vincent"
  • "my_find -user 1000"

If you find some coding or style issues within my samples, please point them out, I'm willing to learn! I'm aware of missing out on some clean memory management but will add this later on.

Update I was thinking about a function which is processing the argument as a char array and checks each char for its ASCII code and call the function if no "char" was found. Is something like that "legit"?

#include <dirent.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <pwd.h>

void entries_with_uid(char *init_path, int pattern_uid);
void entries_with_name(char *init_path, char *pattern_name);

int main(int argc, char **argv)
{
    /*
    char *path = argv[1];
    */
    entries_with_name("/home/mario/Documents/codes", "mario");
    entries_with_uid("/home/mario/test_project", 1000);
    return 0;
}

void entries_with_uid(char *init_path, int pattern_uid)
{
    DIR *dir;
    struct dirent *entry;

    dir = opendir(init_path);
    entry = readdir(dir);

    if(dir == NULL) return;
    if(entry == NULL) return;

    do {
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue;

        char path[1024];
        int len = snprintf(path, sizeof(path)-1, "%s/%s", init_path, entry->d_name);

        path[len] = 0;

        struct stat sb;
        stat(path, &sb);

        if(sb.st_uid == pattern_uid) printf("%s\n", path);

        if (entry->d_type == DT_DIR) entries_with_uid(path, pattern_uid);
    } while (entry = readdir(dir));

    closedir(dir);
}

void entries_with_name(char *init_path, char *pattern_name)
{
    DIR *dir;
    struct dirent *entry;

    dir = opendir(init_path);
    entry = readdir(dir);

    if(dir == NULL) return;
    if(entry == NULL) return;

    do {
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue;

        char path[1024];
        int len = snprintf(path, sizeof(path)-1, "%s/%s", init_path, entry->d_name);

        path[len] = 0;

        struct stat sb;
        stat(path, &sb);

        struct passwd *pwd = getpwuid(sb.st_uid);

        if(strcmp(pwd->pw_name, pattern_name) == 0) printf("%s\n", path);

        if (entry->d_type == DT_DIR) entries_with_name(path, pattern_name);
    } while (entry = readdir(dir));

    closedir(dir);
}

Thanks!

Update

I solved the problem meanwhile with a function which is checking for an alphanumeric string within the argument:

int count_alphanumeric(char *string)
{
    int alphanumeric_counter = 0;
    int i = 0;

    while(string[i]!='\0')
    {

     if (string[i] <= 57 && string[i] >= 48)
     {
         i++;
         continue;
     }
     else alphanumeric_counter++;
     i++;
    }
    return alphanumeric_counter;
}

Still looking for a more elegant option! ;)

Cheeers!

10
  • The 2011 revision of the C standard added generic selections. So one can write macros the simulate overloaded functions. Unfortunately, the behavior is slightly under specified. Commented Mar 5, 2017 at 12:00
  • Is there any best or good practice professionals are mostly using? Commented Mar 5, 2017 at 12:02
  • Well, you can avoid ambiguity if you write the selection to accept a char* and always cast to it when passing a string (a bit cumbersome, but portable). Commented Mar 5, 2017 at 12:10
  • Do you mean casting the <uid> to a string when working with it? Commented Mar 5, 2017 at 12:21
  • Why not using clear names? -userid and -username? Commented Mar 5, 2017 at 12:21

1 Answer 1

1

You need to check whether a string typed by the user is a number or not. This has nothing to do with function overloading or any such syntactic sugar. Function overloading is based on types known at compile time, not on stuff a user can type, so don't look for a clever way to use it. Your current idea is absolutely fine.

The implementation, however, is not. What the heck is 57? Why should anyone remember the ASCII table? Characters constants are written in single quotes, e.g. '0' and '9'. Why reinvent the wheel anyway? Scrap it and use the proper idiomatic C way.

int is_numeric (const char* s, unsigned long* number_return)
{
     char* endp;
     *number_return = strtoul(s, &endp, 0);
     return (*endp == '\0');
}
Sign up to request clarification or add additional context in comments.

1 Comment

a "proper idiomatic C way" is what I've been looking for! Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.