OVH Cloud OVH Cloud

transformer un tampon en lignes

56 réponses
Avatar
Benoit Izac
Bonjour,

Je cherche à faire une fonction qui me permette de transformer un tampon
en lignes de façon à traiter ces dernières par la suite.

J'ai un bout de code qui fonctionne :
========================================================================
#include <stdio.h>
#include <stdlib.h>

#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define BS 10
#define LM 100

int get_line(const char *buffer, size_t *bp, size_t bs,
char *line, size_t *lp, size_t ls)
{
while (*bp < bs) {
/* not enough space in line */
if (!(*lp < ls)) {
(*bp)--;
line[(*lp)-1] = 0;
(*lp) = 0;
return -1;
}
/* end of file? */
if (buffer[*bp] == EOF) {
printf("end of file?\n");
line[*lp] = 0;
return 0;
}
/* end of line */
if (buffer[*bp] == '\n') {
line[*lp] = 0;
(*lp) = 0;
(*bp)++;
return 1;
}
line[*lp] = buffer[*bp];
(*lp)++;
(*bp)++;
}
/* end of buffer */
(*bp) = 0;
line[*lp] = 0;
return 0;
}


int main(int argc, char *argv[])
{
int fd;
size_t r;
char buf[BS];
char line[LM];
size_t bp = 0;
size_t lp = 0;

if (argc != 2)
exit(1);

fd = open(argv[1], O_RDONLY);
if (fd < 0)
exit(2);

while((r = read(fd, buf, BS))) {
while (get_line(buf, &bp, r, line, &lp, LM))
printf("%s\n", line);
}

close(fd);
return 0;
}
========================================================================
PS : Désolé pour ceux qui ne sont pas sous Unix, j'ai bien essayé de
faire la même chose avec fread() mais cette dernière ne me renvoie pas
la taille lu, ce qui pose un problème à la dernière lecture où r est la
plupart du temps différent de BS.

Mon choix lorsque la taille de line est trop petite est discutable
(vaut-il mieux tronquer les lignes ?) mais ce n'est pas vraiment ce qui
me pose problème.

Les questions :
* Ce code est-il correct (fonctionne-t-il dans tous les cas) ?
* Est-il possible d'alléger le code (que get_line est moins
d'arguments) en déclarant bp et lp static ?
* Existe-t-il une autre solution (fonction toute faite, autre
algorithme) ?

Merci.
--
Benoit Izac

10 réponses

1 2 3 4 5
Avatar
Benoit Izac
Bonjour,

le 30/07/2010 à 20:07, xtof pernod a écrit dans le message
<4c5314e2$0$10207$ :

#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>



Inutiles à priori ici.



read() est dans unistd.h, open() demande les deux autres.




c'est stat.h qui est de trop, alors.. bref, pas grave.



Oui, effectivement, en regardant là :
<http://www.opengroup.org/onlinepubs/009695399/functions/open.html> il
apparaît en OH = Optional Header. Le fait est que sur la page de manuel
correspondante (tirée de cette page), le OH n'apparaît pas. Sur la page
de manuel d'un Linux, on a le droit à sys/types.h. Bref, mauvaise pages
de manuel, changer de pages...

Bon, on reprend tout alors: tu veux une fonction qui te découpe
un tableau de caractères en entrée, en un tableau de lignes ?

Une ligne = 0..MAX car. terminée par 'n'.

Le tout fourni par:
size_t archive_read_data(struct archive *, void *buff, size_t len);



Exactement.

Dans ce cas, tu peux regarder du coté de strtok(3)



J'ai essayé :

while ((r = archive_read_data(a, buff, len))) {
line = strtok(buf, "n");
if (line)
printf("%sn", line);
while((line = strtok(NULL, "n")))
printf("%sn", line);
}

Conclusions :
* les lignes avec juste un 'n' sont supprimées
* si len (la taille de buff) est trop petite pour avoir une ligne
entière, la ligne est coupée

Donc, soit je ne sais pas l'utiliser, soit ça ne me convient pas.

--
Benoit Izac
Avatar
Benoit Izac
Bon je vais reprendre les explications car il semble que je n'ai pas été
clair. Soit le bout de code suivant :
======================================================================= #include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUFSIZE 4096
#define LINE_MAX 2048

char *get_line(char *line, ...)
{
...
}

int main(int argc, char *argv[])
{
FILE *fp;
size_t r;
char buf[BUFSIZE];
char line[LINE_MAX];

if (argc != 2)
exit(1);

fp = fopen(argv[1], "r");
if (!fp)
exit(2);

while((r = fread(buf, 1, BUFSIZE, fp)) > 0)
while (get_line(line, ...) != NULL)
if (strstr("blah", line)
printf("%sn", line);

fclose(fp);
return 0;
}
======================================================================= Le fread() n'est pas la fonction qui remplit buf, c'est juste là pour
l'exemple.

Comment écriveriez-vous get_line() ?

--
Benoit Izac
Avatar
xtof pernod
Le 30/07/2010 21:13, Benoit Izac a fait rien qu'à écrire:
le 30/07/2010 à 20:07, xtof pernod a écrit dans le message
<4c5314e2$0$10207$ :

Sur la page
de manuel d'un Linux, on a le droit à sys/types.h.



Ah oui, exact: stat.h, pour open(path, O_CREAT|..., mode)
types.h je vois pas, par contre.

Bref, mauvaise pages de manuel, changer de pages...



Diable, un Unix avec un man pas au top ?!

(...) fonction qui découpe






un tableau de caractères en entrée, en un tableau de lignes ?

Une ligne = 0..MAX car. terminée par 'n'.

Le tout fourni par:
size_t archive_read_data(struct archive *, void *buff, size_t len);



Exactement.

Dans ce cas, tu peux regarder du coté de strtok(3)



J'ai essayé :

while ((r = archive_read_data(a, buff, len))) {
line = strtok(buf, "n");
if (line)
printf("%sn", line);
while((line = strtok(NULL, "n")))
printf("%sn", line);
}



Tu peux simplifier encore un poil:

char *p;
while(r=arc(a,buf,len)) {
p = buf;
while((line = strtok(p, "n")))
printf("%sn", line);
p = NULL;
}
}


Conclusions :
* les lignes avec juste un 'n' sont supprimées



Euh, oui, normal.. pas de token entre 2 délimiteurs de suite.

* si len (la taille de buff) est trop petite pour avoir une ligne
entière, la ligne est coupée



Là, je dirais que c'est à toi de prévoir suffisamment grand.

Donc, soit je ne sais pas l'utiliser, soit ça ne me convient pas.



Tout n'est pas perdu: dans "SEE ALSO", il cite strchr et index
(entre autres) mais celles ci devraient faire ton bonheur.


--
Benoit Izac




--
christophe.
Avatar
Benoit Izac
Bonjour,

le 30/07/2010 à 21:46, xtof pernod a écrit dans le message
<4c532c15$0$5424$ :

Conclusions :
* les lignes avec juste un 'n' sont supprimées



Euh, oui, normal.. pas de token entre 2 délimiteurs de suite.



Pour mon usage, ce n'est pas gênant, mais il faut être conscient que ce
n'est pas une solution universelle.

* si len (la taille de buff) est trop petite pour avoir une ligne
entière, la ligne est coupée



Là, je dirais que c'est à toi de prévoir suffisamment grand.



Je pense qu'il y a moyen de faire ça avec archive_entry_size() pour
avoir sa taille, d'allouer puis de faire le archive_read_data(). Mais
bon, ça veut dire mettre un fichier entier en mémoire à chaque fois.
Je vais quand même tester pour voir.

Donc, soit je ne sais pas l'utiliser, soit ça ne me convient pas.



Tout n'est pas perdu: dans "SEE ALSO", il cite strchr et index
(entre autres) mais celles ci devraient faire ton bonheur.



Ce serait plutôt memchr() dans mon cas mais je ne vois pas ce que ça
change par rapport au parcourt du buffer que je faisais précédemment.
Dans tous les cas, memchr(), va parcourir la chaîne, puis memcpy() va le
faire aussi.

--
Benoit Izac
Avatar
Pierre Maurette
Benoit Izac, le 30/07/2010 a écrit :

[...]

Comment écriveriez-vous get_line() ?



En français ?

--
Pierre Maurette
Avatar
Alexandre Bacquart
On 07/30/2010 07:56 PM, Samuel DEVULDER wrote:
Samuel DEVULDER a écrit :

extern void plot(int color, int y, int x);
// Ah ouais ok c'est donc un "y8" en fait.



J'imagine même pas la galère si le prototype avait été:

extern void plot(int, int, int);



En même temps, on ne fait pas ce genre de prototypes dans des en-têtes
sensés être lus par quelqu'un, et encore moins sans commentaires.

Avec ça, ton prototype initial :

extern void plot(int color, int y, int x);

...n'est qu'une vulgaire blague pour n'importe qui a déjà mis les pieds
dans une bibliothèque graphique. Toutes celles que je connais ont la
convention d'ordre x,y (puis z éventuellement, puis un autre pour la 4D)
pour les coordonnées. Si tu as vu y,x ailleurs, dis-moi où que je
l'évite à tout prix (je ne parle pas d'une activité quelconque autour
des maths où ce serait la norme, mais d'une bibliothèque C).

Ensuite, l'exemple n'est pas super, je n'aime pas ces fonctions
multitâches et préfère largement un état pour la couleur (modèle
d'OpenGL). C'est en tous cas le plus efficace quand on veut aller vite,
ce qui est souvent le cas avec les bidules graphiques.

Pour en revenir au propos, et autrement dit :

plot({.x = 12, .y = 128, .color = 3});

...me plaît évidement plus que :

plot(3,128,12); // avec sa sémantique à coucher dehors

...mais me plaît beaucoup moins que :

color(3);
plot(12, 128);

On peut le mettre sur une ligne pour mettre l'emphase sur l'association
de la couleur et du point :

color(3); plot(12, 128);

Comparé à :

plot({.x = 12, .y = 128, .color = 3});

?

Il me faudra un meilleur exemple pour être convaincu.



--
Alex
Avatar
xtof pernod
Le 30/07/2010 19:52, Antoine Leca a fait rien qu'à écrire:
Benoit Izac a écrit :
Bonjour,

le 30/07/2010 à 19:02, Xavier Roche a écrit dans le message
<i2v0js$nu7$ :

#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>


Inutiles à priori ici.



read() est dans unistd.h, open() demande les deux autres.
(...)



En ce qui concerne <sys/stat.h>, je ne vois pas l'intérêt, et encore
moins la liaison avec open().



Pour S_IRUSR, S_IWUSR & S_IXUSR etc. dans le cas où open(), avec O_CREAT,
a besoin du 3eme parametre (mode).

Sauf qu'en général on met 0640, et stat.h ne sert pas..

(...)



--
christophe.
Avatar
xtof pernod
Le 30/07/2010 22:34, Benoit Izac a fait rien qu'à écrire:
Bonjour,

le 30/07/2010 à 21:46, xtof pernod a écrit dans le message
<4c532c15$0$5424$ :

Conclusions :
* les lignes avec juste un 'n' sont supprimées



Euh, oui, normal.. pas de token entre 2 délimiteurs de suite.



Pour mon usage, ce n'est pas gênant, mais il faut être conscient que ce
n'est pas une solution universelle.



? ben.. Ca fait bien ce que ça dit. Et en toute logique, plusieurs délimiteurs
de suite n'encadrent aucun "token", et donc ça ne retourne rien.

Essaye autre chose si ça te convient pas..


* si len (la taille de buff) est trop petite pour avoir une ligne
entière, la ligne est coupée



Là, je dirais que c'est à toi de prévoir suffisamment grand.



Je pense qu'il y a moyen de faire ça avec archive_entry_size() pour
avoir sa taille, d'allouer puis de faire le archive_read_data(). Mais
bon, ça veut dire mettre un fichier entier en mémoire à chaque fois.
Je vais quand même tester pour voir.



Comme tu veux, mais àma tu te compliques la vie.

Donc, soit je ne sais pas l'utiliser, soit ça ne me convient pas.



Tout n'est pas perdu: dans "SEE ALSO", il cite strchr et index
(entre autres) mais celles ci devraient faire ton bonheur.



Ce serait plutôt memchr() dans mon cas mais je ne vois pas ce que ça



Implicitement, "lignes" + 'n' veut dire que tu traines des chaines
de caractères imprimables (surtout que tu les sorts au printf());
mem*(), c'est pour des données quelconques et/ou binaires. A toi de voir.

change par rapport au parcourt du buffer que je faisais précédemment.



Euh, quel parcours, de quelle version ?!

Dans tous les cas, memchr(), va parcourir la chaîne, puis memcpy() va le
faire aussi.



Certes, mais là tu t'embêtes avec des points de détail. Combien de temps
cpu, pour scruter quelques dizaines d'octets ?

--
christophe.
Avatar
xtof pernod
Le 30/07/2010 22:46, Pierre Maurette a fait rien qu'à écrire:
Benoit Izac, le 30/07/2010 a écrit :

[...]

Comment écriveriez-vous get_line() ?



En français ?




Vu dans une doc' de Bull (ça date un peu:)
imprimef("le resultat est %dn", x);

Traduction exhaustive s'il en est.

--
christophe.
Avatar
espie
In article <4c533f6e$0$10196$,
xtof pernod wrote:
Pour S_IRUSR, S_IWUSR & S_IXUSR etc. dans le cas où open(), avec O_CREAT,
a besoin du 3eme parametre (mode).

Sauf qu'en général on met 0640, et stat.h ne sert pas..



0640 ? Ah non, 0666 le plus souvent. umask(2), c'est pas fait pour les
chiens...
1 2 3 4 5