Пример #1
0
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
{
    char b_path[MAX_STR_SIZE];
    char b_name[MAX_STR_SIZE];
    char b_cmd[MAX_STR_SIZE];
    const wchar_t *tmpline = &line[wcslen(cmd) + 2];   /* start after "/command \"" */

    if (wcs_to_mbs_buf(b_path, tmpline, sizeof(b_path)) == -1)
        return -1;

    if (wcs_to_mbs_buf(b_cmd, cmd, sizeof(b_cmd)) == -1)
        return -1;

    if (b_path[0] == '~')
        complt_home_dir(self, b_path, sizeof(b_path), b_cmd, strlen(b_cmd) + 2);

    int si = char_rfind(b_path, '/', strlen(b_path));

    if (!b_path[0]) {    /* list everything in pwd */
        b_path[0] = '.';
        b_path[1] = '\0';
    } else if (!si && b_path[0] != '/') {    /* look for matches in pwd */
        char tmp[MAX_STR_SIZE];
        snprintf(tmp, sizeof(tmp), ".%s", b_path);
        snprintf(b_path, sizeof(b_path), "%s", tmp);
    }

    snprintf(b_name, sizeof(b_name), "%s", &b_path[si + 1]);
    b_path[si + 1] = '\0';
    int b_name_len = strlen(b_name);
    DIR *dp = opendir(b_path);

    if (dp == NULL)
        return -1;

    char dirnames[MAX_DIRS][NAME_MAX];
    struct dirent *entry;
    int dircount = 0;

    while ((entry = readdir(dp)) && dircount < MAX_DIRS) {
        if (strncmp(entry->d_name, b_name, b_name_len) == 0
                                && strcmp(".", entry->d_name) && strcmp("..", entry->d_name)) {
            snprintf(dirnames[dircount], sizeof(dirnames[dircount]), "%s", entry->d_name);
            ++dircount;
        }
    }

    closedir(dp);

    if (dircount == 0)
        return -1;

    if (dircount > 1) {
        qsort(dirnames, dircount, NAME_MAX, qsort_strcasecmp_hlpr);
        print_matches(self, m, dirnames, dircount, NAME_MAX);
    }

    return complete_line(self, dirnames, dircount, NAME_MAX);
}
Пример #2
0
/* looks for all instances in list that begin with the last entered word in line according to pos,
   then fills line with the complete word. e.g. "Hello jo" would complete the line
   with "Hello john". If multiple matches, prints out all the matches and semi-completes line.

   list is a pointer to the list of strings being compared, n_items is the number of items
   in the list, and size is the size of each item in the list.

   Returns the difference between the old len and new len of line on success, -1 if error */
int complete_line(ToxWindow *self, const void *list, int n_items, int size)
{
    ChatContext *ctx = self->chatwin;

    if (ctx->pos <= 0 || ctx->len <= 0 || ctx->len >= MAX_STR_SIZE || size > MAX_STR_SIZE)
        return -1;

    const char *L = (char *) list;
    const char *endchrs = " ";
    char ubuf[MAX_STR_SIZE];

    /* work with multibyte string copy of buf for simplicity */
    if (wcs_to_mbs_buf(ubuf, ctx->line, sizeof(ubuf)) == -1)
        return -1;

    bool dir_search = strncmp(ubuf, "/sendfile", strlen("/sendfile")) == 0;

    /* isolate substring from space behind pos to pos */
    char tmp[MAX_STR_SIZE];
    snprintf(tmp, sizeof(tmp), "%s", ubuf);
    tmp[ctx->pos] = '\0';

    const char *s = dir_search ? strchr(tmp, '\"') : strrchr(tmp, ' ');
    char *sub = malloc(strlen(ubuf) + 1);

    if (sub == NULL)
        exit_toxic_err("failed in complete_line", FATALERR_MEMORY);

    if (!s && !dir_search) {
        strcpy(sub, tmp);

        if (sub[0] != '/')
            endchrs = ": ";
    } else if (s) {
        strcpy(sub, &s[1]);

        if (dir_search) {
            int sub_len = strlen(sub);
            int si = char_rfind(sub, '/', sub_len);

            if (si || *sub == '/')
                memmove(sub, &sub[si + 1], sub_len - si);
        }
    }

    if (string_is_empty(sub)) {
        free(sub);
        return -1;
    }

    int s_len = strlen(sub);
    const char *str;
    int n_matches = 0;
    char matches[n_items][MAX_STR_SIZE];
    int i = 0;

    /* put all list matches in matches array */
    for (i = 0; i < n_items; ++i) {
        str = &L[i * size];

        if (strncasecmp(str, sub, s_len) == 0)
            strcpy(matches[n_matches++], str);
    }

    free(sub);

    if (!n_matches)
        return -1;

    if (!dir_search && n_matches > 1)
        print_matches(self, NULL, matches, n_matches, MAX_STR_SIZE);

    char match[MAX_STR_SIZE];
    get_str_match(self, match, matches, n_matches);

    if (dir_search) {
        if (n_matches == 1)
            endchrs = char_rfind(match, '.', strlen(match)) ? "\"" : "/";
        else
            endchrs = "";
    } else if (n_matches > 1) {
        endchrs = "";
    }

    /* put match in correct spot in buf and append endchars */
    int n_endchrs = strlen(endchrs);
    int m_len = strlen(match);
    int strt = ctx->pos - s_len;
    int diff = m_len - s_len + n_endchrs;

    if (ctx->len + diff >= MAX_STR_SIZE)
        return -1;

    char tmpend[MAX_STR_SIZE];
    strcpy(tmpend, &ubuf[ctx->pos]);
    strcpy(&ubuf[strt], match);
    strcpy(&ubuf[strt + m_len], endchrs);
    strcpy(&ubuf[strt + m_len + n_endchrs], tmpend);

    /* convert to widechar and copy back to original buf */
    wchar_t newbuf[MAX_STR_SIZE];

    if (mbs_to_wcs_buf(newbuf, ubuf, MAX_STR_SIZE) == -1)
        return -1;

    wcscpy(ctx->line, newbuf);

    ctx->len += diff;
    ctx->pos += diff;

    return diff;
}
Пример #3
0
/*
 * Looks for all instances in list that begin with the last entered word in line according to pos,
 * then fills line with the complete word. e.g. "Hello jo" would complete the line
 * with "Hello john". If multiple matches, prints out all the matches and semi-completes line.
 *
 * list is a pointer to the list of strings being compared, n_items is the number of items
 * in the list, and size is the size of each item in the list.
 *
 * dir_search should be true if the line being completed is a file path.
 *
 * Returns the difference between the old len and new len of line on success.
 * Returns -1 on error.
 *
 * Note: This function should not be called directly. Use complete_line() and complete_path() instead.
 */
static int complete_line_helper(ToxWindow *self, const void *list, size_t n_items, size_t size, bool dir_search)
{
    ChatContext *ctx = self->chatwin;

    if (ctx->pos <= 0 || ctx->len <= 0 || ctx->pos > ctx->len) {
        return -1;
    }

    if (ctx->len >= MAX_STR_SIZE || size > MAX_STR_SIZE) {
        return -1;
    }

    const char *L = (const char *) list;
    const char *endchrs = " ";
    char ubuf[MAX_STR_SIZE] = {0};

    /* work with multibyte string copy of buf for simplicity */
    if (wcs_to_mbs_buf(ubuf, ctx->line, sizeof(ubuf)) == -1) {
        return -1;
    }

    /* isolate substring from space behind pos to pos */
    char tmp[MAX_STR_SIZE];
    snprintf(tmp, sizeof(tmp), "%s", ubuf);
    tmp[ctx->pos] = '\0';

    const char *s = dir_search ? strchr(tmp, ' ') : strrchr(tmp, ' ');
    char *sub = calloc(1, strlen(ubuf) + 1);

    if (sub == NULL) {
        exit_toxic_err("failed in complete_line_helper", FATALERR_MEMORY);
    }

    if (!s && !dir_search) {
        strcpy(sub, tmp);

        if (sub[0] != '/') {
            endchrs = ": ";
        }
    } else if (s) {
        strcpy(sub, &s[1]);

        if (dir_search) {
            int sub_len = strlen(sub);
            int si = char_rfind(sub, '/', sub_len);

            if (si || *sub == '/') {
                memmove(sub, &sub[si + 1], sub_len - si);
            }
        }
    }

    if (!sub[0]) {
        free(sub);
        return 0;
    }

    int s_len = strlen(sub);
    size_t n_matches = 0;
    char matches[n_items][MAX_STR_SIZE];
    int i = 0;

    /* put all list matches in matches array */
    for (i = 0; i < n_items; ++i) {
        char str[MAX_CMDNAME_SIZE + 1];
        snprintf(str, sizeof(str), "%s", &L[i * size]);

        if (strncasecmp(str, sub, s_len) == 0) {
            strcpy(matches[n_matches++], str);
        }
    }

    free(sub);

    if (!n_matches) {
        return -1;
    }

    if (!dir_search && n_matches > 1) {
        print_matches(self, NULL, matches, n_matches, MAX_STR_SIZE);
    }

    char match[MAX_STR_SIZE];
    size_t match_len = get_str_match(self, match, sizeof(match), matches, n_matches);

    if (match_len == 0) {
        return 0;
    }

    if (dir_search) {
        if (n_matches == 1) {
            endchrs = char_rfind(match, '.', match_len) ? "" : "/";
        } else {
            endchrs = "";
        }
    } else if (n_matches > 1) {
        endchrs = "";
    }

    /* put match in correct spot in buf and append endchars */
    int n_endchrs = strlen(endchrs);
    int strt = ctx->pos - s_len;
    int diff = match_len - s_len + n_endchrs;

    if (ctx->len + diff >= MAX_STR_SIZE) {
        return -1;
    }

    char tmpend[MAX_STR_SIZE];
    snprintf(tmpend, sizeof(tmpend), "%s", &ubuf[ctx->pos]);

    if (match_len + n_endchrs + strlen(tmpend) >= sizeof(ubuf)) {
        return -1;
    }

    strcpy(&ubuf[strt], match);

    /* If path points to a file with no extension don't append a forward slash */
    if (dir_search && *endchrs == '/') {
        const char *path_start = strchr(ubuf+1, '/');

        if (!path_start) {
            path_start = strchr(ubuf+1, ' ');

            if (!path_start) {
                return -1;
            }
        }

        if (strlen(path_start) < 2) {
            return -1;
        }

        ++path_start;

        if (file_type(path_start) == FILE_TYPE_REGULAR) {
            endchrs = "";
            diff -= n_endchrs;
        }
    }

    strcpy(&ubuf[strt + match_len], endchrs);
    strcpy(&ubuf[strt + match_len + n_endchrs], tmpend);

    /* convert to widechar and copy back to original buf */
    wchar_t newbuf[MAX_STR_SIZE];

    if (mbs_to_wcs_buf(newbuf, ubuf, sizeof(newbuf) / sizeof(wchar_t)) == -1) {
        return -1;
    }

    wcscpy(ctx->line, newbuf);

    ctx->len += diff;
    ctx->pos += diff;

    return diff;
}