Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

stat et wchar_t

18 réponses
Avatar
unbewust
si je cr=E9e "=E0 la main" au terminal, une dir (ou un fichier) contenant
des caract=E8res Unicode et que je fais un stat dessus (depuis C en
castant le path en (char *) =E7a me dit que le fichier n'existe pas.

j'imagine comme en entr=E9e du stat c'est un char * qui est demand=E9, que
les routines de comparaisons de string internes n'utilisent pas les
wchar_t comme wcscmp ???

y aurait'il une lib de "wstat" (stat en wchar_t) ???

ce que je trouve curieux est que le mkdir marche, le touch aussi avec
des caract=E8res Unicode, mais pas le stat, j'en ai eu la confirmation
par un mdls sur les dits rep et/ou fichier...

10 réponses

1 2
Avatar
Xavier Roche
si je crée "à la main" au terminal, une dir (ou un fichier) contenant
des caractères Unicode et que je fais un stat dessus (depuis C en
castant le path en (char *) ça me dit que le fichier n'existe pas.


Sous quel OS ? Un *nix ?

y aurait'il une lib de "wstat" (stat en wchar_t) ???


Sous Windows, les système de fichiers sont par défaut Unicode, càd. que
tout fichier peut comporter autre chose que de l'ascii, et que cet autre
chose sont des caractères Unicode (toujours restreints au plan 0 il me
semble). Un "nom de fichier" est donc une chaîne de caractère Unicode
(avec quelques restrictions). Le fichier "toto.c" est ainsi identifié
par les 6 caractères UCS2 't', 'o', 't', 'o', '.', 'c'

Et donc les fonctions type "stat", qui acceptent des chaînes MBCS (dont
l'encodage dépent à priori de l'application et se sa codepage) ont un
pendant plus pratique en "wide char" prenant directement de l'UCS2.

Sous Linux (/Unix), un nom de fichier est une chaîne opaque 8-bit.
Evidemment, cela n'est pas franchement pratique pour gérer des accents,
et historiquement chaque administrateur adoptait un encodage différent
(ISO-8859-1 pour nous, SHIFT_JIS côté soleil levant, etc.) via la locale
du système (man locale)

Ainsi, si la locale est réglée sur un système en "ISO-8859-1", et que
vous branchez le disque dur correspondant sur un système avec une locale
en "SHIFT-JIS", vous ne pourrez lire aucun fichier accentué sur pas mal
d'applications qui manipulent les fichiers sous leur forme "localisée"
(c'est mal, mais je crois que c'est ce qui se pratique sur les
sélecteurs de fichiers graphique sous Linux)
Et donc pour la portabilité de manière générale, il n'y a hélas pas
grand chose, sauf à utiliser.. de l'ASCII:
<http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_276&gt;


Ainsi une fonction "wide" n'a aucun sens, car tout est fonction des
conventions utilisées.

Aujourd'hui, il est considéré comme raisonnable de tout passer en UTF-8
(ie. locale bloquée sur UTF-8 au niveau système) pour justement éviter
les petits problèmes de manipulation de fichiers dont on ne peut pas
"voir" le nom :p

Bref, pour résumer, vous devriez pouvoir énumérer via un readdir() les
fichiers (même si l'encoding est "cassé" par rapport à la locale) et les
effacer via unlink(), car toute ces fonctions manipulent des chaînes
opaques 8-bit

ce que je trouve curieux est que le mkdir marche, le touch aussi avec
des caractères Unicode, mais pas le stat, j'en ai eu la confirmation
par un mdls sur les dits rep et/ou fichier...


Avez-vous essayé un 'ls -b' pour voir les caractères spéciaux en question ?

Avatar
Pascal Bourguignon
unbewust writes:

si je crée "à la main" au terminal, une dir (ou un fichier) contenant
des caractères Unicode et que je fais un stat dessus (depuis C en
castant le path en (char *) ça me dit que le fichier n'existe pas.


Il faut t'assurer que l'encodage utilisé par ton clavier et par le
shell soit le même que celui utilisé par le source de ton programme.


j'imagine comme en entrée du stat c'est un char * qui est demandé, que
les routines de comparaisons de string internes n'utilisent pas les
wchar_t comme wcscmp ???


En effet. Pour un système POSIX, les chemins sont des vecteurs
d'octets, avec seulement deux valeurs spéciales:

0 qui termine le chemin.
47 qui sépare les répertoires.

Quand tu tape:

int fd=open("/tmp/myapp/tmpfile",...);

le système ne voit que:

47 116 109 112 47 109 121 97 112 112 47 116 109 112 102 105 108 101 0

Il découpe donc en trois parties:

116 109 112 109 121 97 112 112 116 109 112 102 105 108 101


ce que je trouve curieux est que le mkdir marche, le touch aussi avec
des caractères Unicode, mais pas le stat, j'en ai eu la confirmation
par un mdls sur les dits rep et/ou fichier...


La façon de base de s'assurer que les encodages correspond est de
régler les variables d'environnement LC_*. Par exemple:

LC_CTYPE=fr_FR.UTF-8
export LC_CTYPE

Mais il faut aussi configurer son terminal pour qu'il envoit les
caractères accentués dans l'encodage indiqué, et pour qu'il les
affiche correctement. Il faut aussi configurer son éditeur pour qu'il
utilise ce même encodage. Avec emacs, on peut simplement mettre un
commentaire sur la première ligne, comme:

/* -*- coding:utf-8 -*- */



Aussi, avec UTF-8 il y a un piège. Si un programme travaille
simplement avec une séquence d'octet, il pourra sembler fonctionner
avec une séquence encodée en UTF-8, mais sans se rendre compte des
caractères unicodes. Le même problème peut aussi se produire avec
d'autres couples d'encodage (eg ISO-8859-2 avec ISO-8859-1, etc).
Alors on peut avoir l'impression que ça marche alors que ça ne marche
pas. Heureusement, dans ton cas, tu t'es rendu compte que ça ne
marchait pas.


y aurait'il une lib de "wstat" (stat en wchar_t) ???


Tu n'aurais besoin d'utiliser les fonctions d'encodage/décodage wchar
que si le source du programme n'utilisait pas le même encodage que le
reste. (Ou si tu veux pouvoir travailler avec plusieurs encodages
différents). Je ne sais pas s'il y a déjà une telle bibliothèque,
mais c'est vraiment trivial d'écrire ces fonctions qui combinent
seulement deux fonctions...


--
__Pascal Bourguignon__ http://www.informatimago.com/

NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.

Avatar
Pascal Bourguignon
Xavier Roche writes:
Aujourd'hui, il est considéré comme raisonnable de tout passer en
UTF-8
(ie. locale bloquée sur UTF-8 au niveau système) pour justement éviter
les petits problèmes de manipulation de fichiers dont on ne peut pas
"voir" le nom :p


Bloquer un local sur UTF-8 au niveau du système est problématique, car
il y a des séquences UTF-8 illégales, mais il n'y a pas de séquence
d'octet illégales (hormis les questions de longueur) dans les chemins
POSIX.

De plus, quand on monte des volumes amovibles ou quand on transfer des
fichiers via Internet, on peut se retrouver avec des noms utilisant
des encodages différents dans le même système.


--
__Pascal Bourguignon__ http://www.informatimago.com/

NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.

Avatar
Xavier Roche
Bloquer un local sur UTF-8 au niveau du système est problématique, car
il y a des séquences UTF-8 illégales


Oui, mais la locale est utilisée de manière optionnelle (en théorie
uniquement pour la conversion saisie utilisateur => nom de fichier et
nom de fichier => affichage) ; ainsi un sélecteur de fichier rencontrant
un nom avec une séquence localisée invalide DEVRAIT afficher des "?" à
l'utilisateur MAIS transmettre le nom opaque de manière correcte à
l'application, pour permettre d'ouvrir/effacer/sauvegarder le fichier.

De plus, quand on monte des volumes amovibles ou quand on transfer des
fichiers via Internet, on peut se retrouver avec des noms utilisant
des encodages différents dans le même système.


Via Internet, c'est au navigateur de transformer le nom reçu en séquence
localisée. Pour les montage, c'est en effet toujours un casse-tête quand
on a autre chose que UTF-8.

Le cas comique étant les ISO-2022_*, qui amha doivent mettre un sacré
bazard si un administrateur a la mauvaise idée de les utiliser dans sa
locale.

Avatar
Eric Levenez
Le 14/08/07 15:35, dans <f9sb37$5ai$, « Xavier Roche »
a écrit :

Sous Linux (/Unix), un nom de fichier est une chaîne opaque 8-bit.
Evidemment, cela n'est pas franchement pratique pour gérer des accents,
et historiquement chaque administrateur adoptait un encodage différent
(ISO-8859-1 pour nous, SHIFT_JIS côté soleil levant, etc.) via la locale
du système (man locale)


Sur l'unix Mac OS X, un nom de fichier est une chaîne UTF-8 et pas
uniquement une chaîne "opaque". Le système va donc rejeter toutes séquence
UTF-8 illégale.

--
Éric Lévénez -- <http://www.levenez.com/&gt;
Unix is not only an OS, it's a way of life.

Avatar
Xavier Roche
Sur l'unix Mac OS X, un nom de fichier est une chaîne UTF-8 et pas
uniquement une chaîne "opaque". Le système va donc rejeter toutes séquence
UTF-8 illégale.


Un open() avec une chaîne invalide renvoi donc un code d'erreur ?

Avatar
Eric Levenez
Le 14/08/07 16:29, dans <f9se8m$5ai$, « Xavier Roche »
a écrit :

Sur l'unix Mac OS X, un nom de fichier est une chaîne UTF-8 et pas
uniquement une chaîne "opaque". Le système va donc rejeter toutes séquence
UTF-8 illégale.


Un open() avec une chaîne invalide renvoi donc un code d'erreur ?


Oui : EINVAL = "Invalid argument".

--
Éric Lévénez -- <http://www.levenez.com/&gt;
Unix is not only an OS, it's a way of life.


Avatar
Pascal Bourguignon
Eric Levenez writes:

Le 14/08/07 15:35, dans <f9sb37$5ai$, « Xavier Roche »
a écrit :

Sous Linux (/Unix), un nom de fichier est une chaîne opaque 8-bit.
Evidemment, cela n'est pas franchement pratique pour gérer des accents,
et historiquement chaque administrateur adoptait un encodage différent
(ISO-8859-1 pour nous, SHIFT_JIS côté soleil levant, etc.) via la locale
du système (man locale)


Sur l'unix Mac OS X, un nom de fichier est une chaîne UTF-8 et pas
uniquement une chaîne "opaque". Le système va donc rejeter toutes séquence
UTF-8 illégale.


Ceci est faux.

Ce n'est pas sur l'unix MacOSX, c'est sur le file system HFS+.

Quand on monte un volume qui n'est pas HFS+ sur MacOSX (par exemple,
un volume ext3 sur Linux via NFS), on y trouve des séquences d'octets
qui ne sont pas des encodage utf-8 valide, et que MacOSX gère
parfaitement comme tout bon système POSIX.

Un programme MacOSX qui assumerait UTF-8 pourait avoir des
surprises... Comme par exemple, le Finder. Heureusement, ls est un
bon programme POSIX qui respecte les règles.

--
__Pascal Bourguignon__ http://www.informatimago.com/

NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.


Avatar
Xavier Roche
Ce n'est pas sur l'unix MacOSX, c'est sur le file system HFS+.


On doit donc retomber dans un cas similaire à des montages réseau smbfs
montés via samba.

(bon, on est un peu HS ici, EOT :p)

Avatar
unbewust
On 14 août, 15:41, Pascal Bourguignon wrote:
unbewust writes:
si je crée "à la main" au terminal, une dir (ou un fichier) contena nt
des caractères Unicode et que je fais un stat dessus (depuis C en
castant le path en (char *) ça me dit que le fichier n'existe pas.


Il faut t'assurer que l'encodage utilisé par ton clavier et par le
shell soit le même que celui utilisé par le source de ton programme.

j'imagine comme en entrée du stat c'est un char * qui est demandé, que
les routines de comparaisons de string internes n'utilisent pas les
wchar_t comme wcscmp ???


En effet. Pour un système POSIX, les chemins sont des vecteurs
d'octets, avec seulement deux valeurs spéciales:

0 qui termine le chemin.
47 qui sépare les répertoires.

Quand tu tape:

int fd=open("/tmp/myapp/tmpfile",...);

le système ne voit que:

47 116 109 112 47 109 121 97 112 112 47 116 109 112 102 105 108 101 0

Il découpe donc en trois parties:

116 109 112 109 121 97 112 112 116 109 112 102 105 108 101

ce que je trouve curieux est que le mkdir marche, le touch aussi avec
des caractères Unicode, mais pas le stat, j'en ai eu la confirmation
par un mdls sur les dits rep et/ou fichier...


La façon de base de s'assurer que les encodages correspond est de
régler les variables d'environnement LC_*. Par exemple:

LC_CTYPE=fr_FR.UTF-8


OK, merci, c'est exactement ce que j'ai par défaut sur ma bécanne...

export LC_CTYPE

Mais il faut aussi configurer son terminal pour qu'il envoit les
caractères accentués dans l'encodage indiqué, et pour qu'il les
affiche correctement. Il faut aussi configurer son éditeur pour qu'il
utilise ce même encodage. Avec emacs, on peut simplement mettre un
commentaire sur la première ligne, comme:

/* -*- coding:utf-8 -*- */

Aussi, avec UTF-8 il y a un piège. Si un programme travaille
simplement avec une séquence d'octet, il pourra sembler fonctionner
avec une séquence encodée en UTF-8, mais sans se rendre compte des
caractères unicodes. Le même problème peut aussi se produire avec
d'autres couples d'encodage (eg ISO-8859-2 avec ISO-8859-1, etc).
Alors on peut avoir l'impression que ça marche alors que ça ne marche
pas. Heureusement, dans ton cas, tu t'es rendu compte que ça ne
marchait pas.

y aurait'il une lib de "wstat" (stat en wchar_t) ???


Tu n'aurais besoin d'utiliser les fonctions d'encodage/décodage wchar
que si le source du programme n'utilisait pas le même encodage que le
reste. (Ou si tu veux pouvoir travailler avec plusieurs encodages
différents).


mon source est aussi en UTF-8

Je ne sais pas s'il y a déjà une telle bibliothèque,
mais c'est vraiment trivial d'écrire ces fonctions qui combinent
seulement deux fonctions...

--
__Pascal Bourguignon__ http://www.informatimago.com/

NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.



1 2