Программистское. Скучное.
Mar. 3rd, 2005 05:40 amПосле 5 лет тотальной Perl лоботомии я понял, что забыл С практически начисто... Провозился 2 дня с вылизыванием 80 строчек кода :( Но до сих пор не уверен, что сделал все правильно. Так что, если кто присоветует, что тут еще можно улучщить - пишите :) Да, если по скорости какие-то оптимизации - тоже :)
Да, код под FreeBSD5 :)
Кстати, не уверен, насколько верно передавать int a в функцию с void* ptr через &a, а потом приводить через *(int*)ptr. Но в теории, размера указателя может не хватить, чтобы поместить в него int(хотя до сих пор работало:)).
Да, код под FreeBSD5 :)
#include <errno.h>
#include <sys/types.h>
#include <sys/extattr.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
static struct {
int space;
const char *name;
size_t len;
}
extattr[] = {
{ EXTATTR_NAMESPACE_SYSTEM, “system.”, sizeof(“system.”) },
{ EXTATTR_NAMESPACE_USER, “user.”, sizeof(“user.”) },
};
ssize_t my_listxattr (int type, const void *arg, char *list, size_t size) {
ssize_t list_size, tot_size = 0;
int i, t, len;
char *buf;
/* Iterate through extattr(2) namespaces */
for(t = 0; t < sizeof(extattr)/sizeof(extattr[0]); t++) {
switch(type) {
case 0:
list_size = extattr_list_file((const char*)arg, extattr[t].space, list, size);
break;
case 1:
list_size = extattr_list_link((const char*)arg, extattr[t].space, list, size);
break;
case 2:
list_size = extattr_list_fd(*(int*)arg, extattr[t].space, list, size);
break;
default:
errno = ENOSYS;
return -1;
}
/* Some error happened. Errno should be set by previous call */
if(list_size < 0)
return -1;
/* No attributes */
if(list_size == 0)
continue;
/* XXX: Call with an empty buffer may be used to calculate
necessary buffer size. Unfortunately, we can't say, how
many attributes were returned, so here is the potential
problem with the emulation.
*/
if(list == NULL) {
/* For sure, at least one attribute exists. */
tot_size += list_size + extattr[t].len - 1;
continue;
}
/* Count necessary offset to fit namespace prefixes */
len = 0;
for(i = 0; i < list_size; i += list[i] + 1)
len += extattr[t].len - 1;
tot_size += list_size + len;
/* Buffer is too small to fit the results */
if(tot_size > size) {
errno = ERANGE;
return -1;
}
/* Shift the results back, so we can prepend prefixes */
buf = memmove(list + len, list, list_size);
for(i = 0; i < list_size; i += len + 1) {
len = buf[i];
strncpy(list, extattr[t].name, extattr[t].len);
strncat(list, buf + i + 1, len);
list += extattr[t].len + len;
}
size -= tot_size;
}
return tot_size;
}
ssize_t sys_listxattr (const char *path, char *list, size_t size)
{
return my_listxattr(0, path, list, size);
}
ssize_t sys_llistxattr (const char *path, char *list, size_t size)
{
return my_listxattr(1, path, list, size);
}
ssize_t sys_flistxattr (int filedes, char *list, size_t size)
{
return my_listxattr(2, &filedes, list, size);
}
int main(int argc, char *argv[]) {
char buf[1024];
ssize_t size;
int fd, i = 0;
//size = sys_listxattr(argv[1], buf, sizeof(buf));
fd = open(argv[1], O_RDONLY);
size = sys_flistxattr(fd, buf, sizeof(buf));
//size = sys_flistxattr(fd, NULL, 0);
printf("Len: %d\n", size);
for(i = 0; i < size; i += strlen(buf+i)+1) {
printf("%s\n", buf+i);
}
return 0;
}
Кстати, не уверен, насколько верно передавать int a в функцию с void* ptr через &a, а потом приводить через *(int*)ptr. Но в теории, размера указателя может не хватить, чтобы поместить в него int(хотя до сих пор работало:)).
no subject
Date: 2005-03-02 08:53 pm (UTC)no subject
Date: 2005-03-02 08:55 pm (UTC)Вообще я эту конструкцию на автомате писал, так что уже и не уверен :)
no subject
Date: 2005-03-02 08:58 pm (UTC)no subject
Date: 2005-03-02 09:03 pm (UTC)А вот например в glib есть функция pointer2int(). Или макрос. И обратный(-ая). Вот кто они после этого :)?
Я возьму вот этот кусочек, для начала:
Date: 2005-03-02 09:05 pm (UTC)я бы сделал так:extattr[] = { { EXTATTR_NAMESPACE_SYSTEM, “system.”, sizeof(“system.”) }, { EXTATTR_NAMESPACE_USER, “user.”, sizeof(“user.”) }, };Комфорт + меньшая вероятность ошибки. ;-)#define extattr_STRnLEN(str) str, sizeof(str) extattr[] = { { EXTATTR_NAMESPACE_SYSTEM, extattr_STRnLEN("system.") }, { EXTATTR_NAMESPACE_SYSTEM, extattr_STRnLEN("user.") } }; #undef extattr_STRnLENRe: Я возьму вот этот кусочек, для начала:
Date: 2005-03-02 09:09 pm (UTC)Пожалуйста
no subject
Date: 2005-03-02 09:31 pm (UTC)typedef union extattr_arg
{
const char *file;
const char *link;
int fd;
} extattr_arg;
ssize_t my_listxattr (int type, extattr_arg arg, char *list, size_t size) {
...
case 0:
list_size = extattr_list_file(arg.file, extattr[t].space, list, size);
break;
case 1:
list_size = extattr_list_link(arg.link, extattr[t].space, list, size);
break;
case 2:
list_size = extattr_list_fd(arg.fd, extattr[t].space, list, size);
break;
...
ssize_t sys_listxattr (const char *path, char *list, size_t size)
{
extattr_arg arg;
arg.file = path;
return my_listxattr(0, arg, list, size);
}
ssize_t sys_llistxattr (const char *path, char *list, size_t size)
{
extattr_arg arg;
arg.link = path;
return my_listxattr(1, arg, list, size);
}
ssize_t sys_flistxattr (int filedes, char *list, size_t size)
{
extattr_arg arg;
arg.fd = filedes;
return my_listxattr(2, arg, list, size);
}
no subject
Date: 2005-03-02 09:34 pm (UTC)Re: Я возьму вот этот кусочек, для начала:
Date: 2005-03-03 01:07 am (UTC)злая собакамакрос".no subject
Date: 2005-03-03 01:13 am (UTC)Только вот текст постинга (не код) наводит на крамольную мысль, что сам автор кода не ведает, что творит :))))
no subject
Date: 2005-03-03 01:56 am (UTC)1. Хорошо бы функции extattr_list_* свести в массивчик (да, а первый параметр сделать именно union). Тогда вместо дурацкого switch был бы вызов функции из массива. Причем указатель в этом массиве, очевидно, вычисляется снаружи главного цикла. Вообще, у тебя хроническая болезнь - невынос инвариантов из циклов (да да, я в курсе, что-то может соптимизировать компилятор - но лучше не полагаться на волю случая...:)
2. Циклы от 0 до n менее эффективны, чем от n до 0. Потому как операция сравнения с 0 - дешевле. Типа for (i=n;--i>=0;)
3. Немного глупо каждый раз делать extattr[t] - надо просто указателем гулять по extattr.
no subject
Date: 2005-03-03 02:01 am (UTC)for(i = 0; i < list_size; i += len + 1) {
len = buf[i];
strncpy(list, extattr[t].name, extattr[t].len);
strncat(list, buf + i + 1, len);
list += extattr[t].len + len;
}
переделав в:
for(i = 0; i < list_size; i += len + 1) {
len = buf[i];
// меньше на проверку внутри, а строка у нас точно NUL-терминирована в известном месте
strcpy(list, extattr[t].name);
// не ищем конец строки перед добавлением в конец, потому как знаем где он
list += extattr[t].len;
// если в bsd есть stxcpy, то две следующие строчки меняются на него
strncpy(list, buf + i + 1, len-1); // а можно и memcpy в общем-то - будет ещё быстрее
list[len-1] = '\0';
list += len;
}
Не буду спорить, насчет традиции. Но в данном случае, ...
no subject
Date: 2005-03-03 04:03 am (UTC)Я пытаюсь сэмулировать линуксячие функции на FreeBSD :) Может, в Линук эмулятор это дело заодно продать?
no subject
Date: 2005-03-03 05:52 am (UTC)Но вот представь как аналогичная функциия для IRIX написана:
static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags);
Вот те path и filedes - это то что я через void* передаю :) А там - либо (1, 0), либо (0, 1) :)))
no subject
Date: 2005-03-03 05:52 am (UTC)no subject
Date: 2005-03-03 06:19 am (UTC)А на чем основана мысль, что с 0 сравнивать дешевле?
@@ -10,16 +10,16 @@
movl %esp,%ebp
subl $24,%esp
nop
- movl $10,-4(%ebp)
+ movl $0,-4(%ebp)
.p2align 4,,7
.L3:
- cmpl $0,-4(%ebp)
- jg .L5
+ cmpl $9,-4(%ebp)
+ jle .L5
jmp .L4
.p2align 4,,7
.L6:
.L5:
- decl -4(%ebp)
+ incl -4(%ebp)
jmp .L3
.p2align 4,,7
.L4:
Результат сравнения прямого и обратного цикла, скомпилированного в ассемблер :) Как видишь - одинаковый абсолютно код :)
А вот насчет указателя верно замечено :) Правда, опять же - придется тип вводить, чтобы такой указатель создать... Не хотелось бы namespace засорять :)
no subject
Date: 2005-03-03 07:46 am (UTC)1. wrapper можно заинлайнить (он же однострочный и простой). Это все compile-time время. Зато гарантировано константное (и небольшое - в случае инлайна) время вызова конечной функции - не if-then-elif-then-else... (еще и умноженное на кол-во проходов цикла!) Да и вообще архитектурно элегантно-выпендрежнее получается:)
2. Ты меня убил асмовским кодом... Эти уроды, чтобы с 0 сравнить - в стек его грузят? Тогда да, беру свои слова обратно про оптимальность цикла. И начинаю ругаться на gcc...:) Пойду покомпилирую что ли, поизучаю... Еще в древние времена всякие bcc/cl умели нормально с 0 на x86 сравнивать...
3. А указатель таки введи, для красоты-то:)
no subject
Date: 2005-03-03 07:54 am (UTC)3d: 4b dec %ebx
3e: 79 ec jns 2c <main+0x2c>
Вот так при limit != 0 - не с оптимизировать...
no subject
Date: 2005-03-03 08:35 am (UTC)no subject
Date: 2005-03-03 10:07 am (UTC)У меня с оптимизатором код совершенно одинаковый для:
for(i=10; i >= 0; i--) { }
и
for(i=0; i < 10; i++) { }
no subject
Date: 2005-03-03 10:17 am (UTC){ EXTATTR_NAMESPACE_SYSTEM, "system.", sizeof("system.")-1 },
...
for(i = 0; i < list_size; i += len + 1) {
len = buf[i];
strcpy(list, extattr[t].name);
list += extattr[t].len;
strncpy(list, buf + i + 1, len);
list[len] = '\0';
list += len + 1;
}
no subject
Date: 2005-03-03 10:40 am (UTC)Я делаю
for (int i=10;--i>=0;) {}
no subject
Date: 2005-03-03 10:41 am (UTC)