3 MPDM - Minimum Profit Data Manager
4 Copyright (C) 2003/2007 Angel Ortega <angel@triptico.com>
6 mpdm_f.c - File management
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 http://www.triptico.com
28 #ifdef CONFOPT_CANONICALIZE_FILE_NAME
37 #ifdef CONFOPT_UNISTD_H
53 #ifdef CONFOPT_SYS_TYPES_H
54 #include <sys/types.h>
57 #ifdef CONFOPT_SYS_WAIT_H
61 #ifdef CONFOPT_SYS_STAT_H
80 wchar_t * (* f_read
) (const struct mpdm_file
*, int *);
81 int (* f_write
)(const struct mpdm_file
*, const wchar_t *);
86 #endif /* CONFOPT_ICONV */
91 #endif /* CONFOPT_WIN32 */
100 ********************/
103 static void store_syserr(void)
104 /* stores the system error inside the global ERRNO */
106 mpdm_hset_s(mpdm_root(), L
"ERRNO", MPDM_MBS(strerror(errno
)));
110 static int get_char(const struct mpdm_file
*f
)
111 /* reads a character from a file structure */
117 if (f
->hin
!= NULL
) {
121 if (ReadFile(f
->hin
, &tmp
, 1, &n
, NULL
) && n
> 0)
125 #endif /* CONFOPT_WIN32 */
128 /* read (converting to positive if needed) */
129 if ((c
= fgetc(f
->in
)) < 0 && !feof(f
->in
))
137 static int put_buf(const char *ptr
, int s
, const struct mpdm_file
*f
)
138 /* writes s bytes in the buffer in ptr to f */
142 if (f
->hout
!= NULL
) {
145 if (WriteFile(f
->hout
, ptr
, s
, &n
, NULL
) && n
> 0)
149 #endif /* CONFOPT_WIN32 */
152 s
= fwrite(ptr
, s
, 1, f
->out
);
158 static int put_char(int c
, const struct mpdm_file
*f
)
159 /* writes a character in a file structure */
163 if (put_buf(&tmp
, 1, f
) != 1)
170 static wchar_t *read_mbs(const struct mpdm_file
*f
, int *s
)
171 /* reads a multibyte string from a mpdm_file into a dynamic string */
178 while ((c
= get_char(f
)) != EOF
) {
184 if (i
== sizeof(tmp
) - 1) {
185 /* out of space; start allocating */
186 if ((auxptr
= mpdm_poke(auxptr
, &n
, tmp
, i
, sizeof(char))) == NULL
)
193 /* is there something to return? */
199 /* auxiliary space used; concat all */
200 if ((auxptr
= mpdm_poke(auxptr
, &n
, tmp
, i
, sizeof(char))) == NULL
)
203 /* do the conversion */
204 ptr
= mpdm_mbstowcs(auxptr
, s
, -1);
209 ptr
= mpdm_mbstowcs(tmp
, s
, -1);
216 static int write_wcs(const struct mpdm_file
*f
, const wchar_t * str
)
217 /* writes a wide string to an struct mpdm_file */
222 ptr
= mpdm_wcstombs(str
, &s
);
223 s
= put_buf(ptr
, s
, f
);
232 static wchar_t *read_iconv(const struct mpdm_file
*f
, int *s
)
233 /* reads a multibyte string transforming with iconv */
242 /* resets the decoder */
243 iconv(f
->ic_dec
, NULL
, NULL
, NULL
, NULL
);
245 while ((c
= get_char(f
)) != EOF
) {
251 /* too big? shouldn't happen */
252 if (i
== sizeof(tmp
))
257 ol
= sizeof(wchar_t);
261 if (iconv(f
->ic_dec
, &iptr
, &il
, &optr
, &ol
) == (size_t) -1) {
262 /* found incomplete multibyte character */
266 /* otherwise, return '?' */
272 if ((ptr
= mpdm_poke(ptr
, s
, &wc
, 1, sizeof(wchar_t))) == NULL
)
275 /* if it's an end of line, finish */
281 ptr
= mpdm_poke(ptr
, s
, L
"", 1, sizeof(wchar_t));
289 static int write_iconv(const struct mpdm_file
*f
, const wchar_t * str
)
290 /* writes a wide string to a stream using iconv */
295 /* resets the encoder */
296 iconv(f
->ic_enc
, NULL
, NULL
, NULL
, NULL
);
298 /* convert char by char */
299 for (; *str
!= L
'\0'; str
++) {
304 il
= sizeof(wchar_t);
310 if (iconv(f
->ic_enc
, &iptr
, &il
, &optr
, &ol
) == (size_t) -1) {
311 /* error converting; convert a '?' instead */
314 il
= sizeof(wchar_t);
319 iconv(f
->ic_enc
, &iptr
, &il
, &optr
, &ol
);
322 for (n
= 0; n
< (int)(sizeof(tmp
) - ol
); n
++, cnt
++) {
323 if (put_char(tmp
[n
], f
) == EOF
)
332 #endif /* CONFOPT_ICONV */
334 #define UTF8_BYTE() if((c = get_char(f)) == EOF) break
336 static wchar_t *read_utf8(const struct mpdm_file
*f
, int *s
)
337 /* crappy, ad-hoc utf8 reader */
353 if ((c
& 0xe0) == 0xe0) {
354 wc
= (c
& 0x1f) << 12;
356 wc
|= (c
& 0x3f) << 6;
361 wc
= (c
& 0x3f) << 6;
367 if ((ptr
= mpdm_poke(ptr
, s
, &wc
, 1, sizeof(wchar_t))) == NULL
)
370 /* if it's an end of line, finish */
376 ptr
= mpdm_poke(ptr
, s
, L
"", 1, sizeof(wchar_t));
384 static int write_utf8(const struct mpdm_file
*f
, const wchar_t * str
)
385 /* crappy, ad-hoc utf8 writer */
390 /* convert char by char */
391 for (; (wc
= *str
) != L
'\0'; str
++) {
393 put_char((int) wc
, f
);
396 put_char((int) (0xc0 | (wc
>> 6)), f
);
397 put_char((int) (0x80 | (wc
& 0x3f)), f
);
401 put_char((int) (0xe0 | (wc
>> 12)), f
);
402 put_char((int) (0x80 | ((wc
>> 6) & 0x3f)), f
);
403 put_char((int) (0x80 | (wc
& 0x3f)), f
);
414 static wchar_t *read_utf8_bom(struct mpdm_file
*f
, int *s
)
415 /* utf-8 reader with BOM detection */
422 if (get_char(f
) == 0xef && get_char(f
) == 0xbb && get_char(f
) == 0xbf)
429 mpdm_hset_s(mpdm_root(), L
"DETECTED_ENCODING", MPDM_LS(enc
));
431 /* we're utf-8 from now on */
432 f
->f_read
= read_utf8
;
434 return f
->f_read(f
, s
);
438 static int write_utf8_bom(struct mpdm_file
*f
, const wchar_t * str
)
439 /* crappy, ad-hoc utf-8 writer with BOM */
446 /* we're utf-8 from now on */
447 f
->f_write
= write_utf8
;
449 return f
->f_write(f
, str
);
453 static wchar_t *read_iso8859_1(const struct mpdm_file
*f
, int *s
)
454 /* crappy, ad-hoc iso8859-1 reader */
462 while ((c
= get_char(f
)) != EOF
) {
466 if ((ptr
= mpdm_poke(ptr
, s
, &wc
, 1, sizeof(wchar_t))) == NULL
)
469 /* if it's an end of line, finish */
475 ptr
= mpdm_poke(ptr
, s
, L
"", 1, sizeof(wchar_t));
483 static int write_iso8859_1(const struct mpdm_file
*f
, const wchar_t * str
)
484 /* crappy, ad-hoc iso8859-1 writer */
489 /* convert char by char */
490 for (; (wc
= *str
) != L
'\0'; str
++)
491 put_char(wc
<= 0xff ? (int) wc
: '?', f
);
497 static wchar_t *read_utf16ae(const struct mpdm_file
*f
, int *s
, int le
)
498 /* utf16 reader, ANY ending */
509 if ((c1
= get_char(f
)) == EOF
)
512 if ((c2
= get_char(f
)) == EOF
)
521 if ((ptr
= mpdm_poke(ptr
, s
, &wc
, 1, sizeof(wchar_t))) == NULL
)
524 /* if it's an end of line, finish */
530 ptr
= mpdm_poke(ptr
, s
, L
"", 1, sizeof(wchar_t));
538 static int write_utf16ae(const struct mpdm_file
*f
, const wchar_t * str
, int le
)
539 /* utf16 writer, ANY ending */
544 /* convert char by char */
545 for (; (wc
= *str
) != L
'\0'; str
++) {
548 put_char(wc
& 0xff, f
);
549 put_char((wc
& 0xff00) >> 8, f
);
552 put_char((wc
& 0xff00) >> 8, f
);
553 put_char(wc
& 0xff, f
);
561 static wchar_t *read_utf16le(const struct mpdm_file
*f
, int *s
)
563 return read_utf16ae(f
, s
, 1);
567 static int write_utf16le(const struct mpdm_file
*f
, const wchar_t * str
)
569 return write_utf16ae(f
, str
, 1);
573 static wchar_t *read_utf16be(const struct mpdm_file
*f
, int *s
)
575 return read_utf16ae(f
, s
, 0);
579 static int write_utf16be(const struct mpdm_file
*f
, const wchar_t * str
)
581 return write_utf16ae(f
, str
, 0);
585 static wchar_t *read_utf16(struct mpdm_file
*f
, int *s
)
596 if (c1
== 0xff && c2
== 0xfe) {
598 f
->f_read
= read_utf16le
;
601 if (c1
== 0xfe && c2
== 0xff) {
603 f
->f_read
= read_utf16be
;
608 mpdm_hset_s(mpdm_root(), L
"DETECTED_ENCODING", MPDM_LS(enc
));
610 return f
->f_read(f
, s
);
614 static int write_utf16(struct mpdm_file
*f
, const wchar_t * str
)
616 /* store the LE signature */
620 /* we're 16le from now on */
621 f
->f_write
= write_utf16le
;
623 return f
->f_write(f
, str
);
627 static wchar_t *read_utf32ae(const struct mpdm_file
*f
, int *s
, int le
)
628 /* utf32 reader, ANY ending */
639 if ((c1
= get_char(f
)) == EOF
)
642 if ((c2
= get_char(f
)) == EOF
)
645 if ((c3
= get_char(f
)) == EOF
)
648 if ((c4
= get_char(f
)) == EOF
)
652 wc
= c1
| (c2
<< 8) | (c3
<< 16) | (c4
<< 24);
654 wc
= c4
| (c3
<< 8) | (c2
<< 16) | (c1
<< 24);
657 if ((ptr
= mpdm_poke(ptr
, s
, &wc
, 1, sizeof(wchar_t))) == NULL
)
660 /* if it's an end of line, finish */
666 ptr
= mpdm_poke(ptr
, s
, L
"", 1, sizeof(wchar_t));
674 static int write_utf32ae(const struct mpdm_file
*f
, const wchar_t * str
, int le
)
675 /* utf32 writer, ANY ending */
680 /* convert char by char */
681 for (; (wc
= *str
) != L
'\0'; str
++) {
684 put_char((wc
& 0x000000ff), f
);
685 put_char((wc
& 0x0000ff00) >> 8, f
);
686 put_char((wc
& 0x00ff0000) >> 16, f
);
687 put_char((wc
& 0xff000000) >> 24, f
);
690 put_char((wc
& 0xff000000) >> 24, f
);
691 put_char((wc
& 0x00ff0000) >> 16, f
);
692 put_char((wc
& 0x0000ff00) >> 8, f
);
693 put_char((wc
& 0x000000ff), f
);
701 static wchar_t *read_utf32le(const struct mpdm_file
*f
, int *s
)
703 return read_utf32ae(f
, s
, 1);
707 static int write_utf32le(const struct mpdm_file
*f
, const wchar_t * str
)
709 return write_utf32ae(f
, str
, 1);
713 static wchar_t *read_utf32be(const struct mpdm_file
*f
, int *s
)
715 return read_utf32ae(f
, s
, 0);
719 static int write_utf32be(const struct mpdm_file
*f
, const wchar_t * str
)
721 return write_utf32ae(f
, str
, 0);
725 static wchar_t *read_utf32(struct mpdm_file
*f
, int *s
)
738 if (c1
== 0xff && c2
== 0xfe && c3
== 0 && c4
== 0) {
740 f
->f_read
= read_utf32le
;
743 if (c1
== 0 && c2
== 0 && c3
== 0xfe && c4
== 0xff) {
745 f
->f_read
= read_utf32be
;
750 mpdm_hset_s(mpdm_root(), L
"DETECTED_ENCODING", MPDM_LS(enc
));
752 return f
->f_read(f
, s
);
756 static int write_utf32(struct mpdm_file
*f
, const wchar_t * str
)
758 /* store the LE signature */
764 /* we're 32le from now on */
765 f
->f_write
= write_utf32le
;
767 return f
->f_write(f
, str
);
771 static wchar_t *read_auto(struct mpdm_file
*f
, int *s
)
772 /* autodetects different encodings based on the BOM */
776 /* by default, multibyte reading */
777 f
->f_read
= read_mbs
;
779 /* not reading from a FILE? no autodetection possible */
786 /* can be utf32le or utf16le */
787 if (get_char(f
) == 0xfe) {
788 /* if next 2 chars are 0x00, it's utf32; otherwise utf16 */
789 if (get_char(f
) == 0x00 && get_char(f
) == 0x00) {
791 f
->f_read
= read_utf32le
;
795 /* rewind to 3rd character */
799 f
->f_read
= read_utf16le
;
807 if (get_char(f
) == 0x00 && get_char(f
) == 0xfe && get_char(f
) == 0xff) {
809 f
->f_read
= read_utf32be
;
816 if (get_char(f
) == 0xff) {
818 f
->f_read
= read_utf16be
;
824 /* can be utf8 with BOM */
825 if (get_char(f
) == 0xbb && get_char(f
) == 0xbf) {
827 f
->f_read
= read_utf8
;
832 /* none of the above; restart */
837 mpdm_hset_s(mpdm_root(), L
"DETECTED_ENCODING", MPDM_LS(enc
));
839 return f
->f_read(f
, s
);
843 static mpdm_t
new_mpdm_file(void)
844 /* creates a new file value */
847 struct mpdm_file
*fs
;
850 if ((fs
= malloc(sizeof(struct mpdm_file
))) == NULL
)
853 memset(fs
, '\0', sizeof(struct mpdm_file
));
855 /* default I/O functions */
856 fs
->f_read
= read_auto
;
857 fs
->f_write
= write_wcs
;
860 /* no iconv encodings by default */
861 fs
->ic_enc
= fs
->ic_dec
= (iconv_t
) -1;
864 if ((v
= mpdm_new(MPDM_FILE
| MPDM_FREE
, fs
, sizeof(struct mpdm_file
))) == NULL
) {
869 if ((e
= mpdm_hget_s(mpdm_root(), L
"ENCODING")) != NULL
) {
871 wchar_t *enc
= mpdm_string(e
);
874 mpdm_t cs
= MPDM_2MBS(e
->data
);
876 if ((fs
->ic_enc
= iconv_open((char *) cs
->data
, "WCHAR_T")) != (iconv_t
) -1 &&
877 (fs
->ic_dec
= iconv_open("WCHAR_T", (char *) cs
->data
)) != (iconv_t
) -1) {
879 fs
->f_read
= read_iconv
;
880 fs
->f_write
= write_iconv
;
884 #endif /* CONFOPT_ICONV */
886 if (wcscmp(enc
, L
"utf-8") == 0) {
887 fs
->f_read
= read_utf8_bom
;
888 fs
->f_write
= write_utf8
;
891 if (wcscmp(enc
, L
"utf-8bom") == 0) {
892 fs
->f_read
= read_utf8_bom
;
893 fs
->f_write
= write_utf8_bom
;
896 if (wcscmp(enc
, L
"iso8859-1") == 0) {
897 fs
->f_read
= read_iso8859_1
;
898 fs
->f_write
= write_iso8859_1
;
901 if (wcscmp(enc
, L
"utf-16le") == 0) {
902 fs
->f_read
= read_utf16le
;
903 fs
->f_write
= write_utf16le
;
906 if (wcscmp(enc
, L
"utf-16be") == 0) {
907 fs
->f_read
= read_utf16be
;
908 fs
->f_write
= write_utf16be
;
911 if (wcscmp(enc
, L
"utf-16") == 0) {
912 fs
->f_read
= read_utf16
;
913 fs
->f_write
= write_utf16
;
916 if (wcscmp(enc
, L
"utf-32le") == 0) {
917 fs
->f_read
= read_utf32le
;
918 fs
->f_write
= write_utf32le
;
921 if (wcscmp(enc
, L
"utf-32be") == 0) {
922 fs
->f_read
= read_utf32be
;
923 fs
->f_write
= write_utf32be
;
926 if (wcscmp(enc
, L
"utf-32") == 0) {
927 fs
->f_read
= read_utf32
;
928 fs
->f_write
= write_utf32
;
936 static void destroy_mpdm_file(mpdm_t v
)
937 /* destroys and file value */
939 struct mpdm_file
*fs
= (struct mpdm_file
*)v
->data
;
943 if (fs
->ic_enc
!= (iconv_t
) - 1) {
944 iconv_close(fs
->ic_enc
);
945 fs
->ic_enc
= (iconv_t
) - 1;
948 if (fs
->ic_dec
!= (iconv_t
) - 1) {
949 iconv_close(fs
->ic_dec
);
950 fs
->ic_dec
= (iconv_t
) - 1;
962 wchar_t *mpdm_read_mbs(FILE * f
, int *s
)
963 /* reads a multibyte string from a stream into a dynamic string */
967 /* reset the structure */
968 memset(&fs
, '\0', sizeof(fs
));
971 return read_mbs(&fs
, s
);
975 int mpdm_write_wcs(FILE * f
, const wchar_t * str
)
976 /* writes a wide string to a stream */
980 /* reset the structure */
981 memset(&fs
, '\0', sizeof(fs
));
984 return write_wcs(&fs
, str
);
988 mpdm_t
mpdm_new_f(FILE * f
)
989 /* creates a new file value from a FILE * */
996 if ((v
= new_mpdm_file()) != NULL
) {
997 struct mpdm_file
*fs
= (struct mpdm_file
*)v
->data
;
998 fs
->in
= fs
->out
= f
;
1006 * mpdm_open - Opens a file.
1007 * @filename: the file name
1008 * @mode: an fopen-like mode string
1010 * Opens a file. If @filename can be open in the specified @mode, an
1011 * mpdm_t value will be returned containing the file descriptor, or NULL
1015 mpdm_t
mpdm_open(const mpdm_t filename
, const mpdm_t mode
)
1021 if (filename
== NULL
|| mode
== NULL
)
1024 /* convert to mbs,s */
1025 fn
= MPDM_2MBS(filename
->data
);
1026 m
= MPDM_2MBS(mode
->data
);
1028 if ((f
= fopen((char *) fn
->data
, (char *) m
->data
)) == NULL
)
1031 #if defined(CONFOPT_SYS_STAT_H) && defined(S_ISDIR) && defined(EISDIR)
1034 /* test if the open file is a directory */
1035 if (fstat(fileno(f
), &s
) != -1 && S_ISDIR(s
.st_mode
)) {
1036 /* it's a directory; fail */
1050 * mpdm_close - Closes a file descriptor.
1051 * @fd: the value containing the file descriptor
1053 * Closes the file descriptor.
1056 mpdm_t
mpdm_close(mpdm_t fd
)
1058 struct mpdm_file
*fs
= (struct mpdm_file
*)fd
->data
;
1060 if ((fd
->flags
& MPDM_FILE
) && fs
!= NULL
) {
1064 if (fs
->out
!= fs
->in
&& fs
->out
!= NULL
)
1067 destroy_mpdm_file(fd
);
1075 * mpdm_read - Reads a line from a file descriptor.
1076 * @fd: the value containing the file descriptor
1078 * Reads a line from @fd. Returns the line, or NULL on EOF.
1080 * [Character Set Conversion]
1082 mpdm_t
mpdm_read(const mpdm_t fd
)
1087 const struct mpdm_file
*fs
= fd
->data
;
1092 ptr
= fs
->f_read(fs
, &s
);
1095 v
= MPDM_ENS(ptr
, s
);
1101 mpdm_t
mpdm_getchar(const mpdm_t fd
)
1105 const struct mpdm_file
*fs
= fd
->data
;
1107 if (fs
== NULL
|| (c
= get_char(fs
)) == EOF
)
1110 /* get the char as-is */
1111 tmp
[0] = (wchar_t) c
;
1118 mpdm_t
mpdm_putchar(const mpdm_t fd
, const mpdm_t c
)
1120 const struct mpdm_file
*fs
= fd
->data
;
1121 const wchar_t *ptr
= mpdm_string(c
);
1123 if (fs
== NULL
|| put_char(*ptr
, fs
) == -1)
1131 * mpdm_write - Writes a value into a file.
1132 * @fd: the file descriptor.
1133 * @v: the value to be written.
1135 * Writes the @v string value into @fd, using the current encoding.
1137 * [Character Set Conversion]
1139 int mpdm_write(const mpdm_t fd
, const mpdm_t v
)
1141 const struct mpdm_file
*fs
= fd
->data
;
1147 ret
= fs
->f_write(fs
, mpdm_string(v
));
1153 int mpdm_fseek(const mpdm_t fd
, long offset
, int whence
)
1155 const struct mpdm_file
*fs
= fd
->data
;
1157 return fseek(fs
->in
, offset
, whence
);
1161 long mpdm_ftell(const mpdm_t fd
)
1163 const struct mpdm_file
*fs
= fd
->data
;
1165 return ftell(fs
->in
);
1169 FILE * mpdm_get_filehandle(const mpdm_t fd
)
1173 if (fd
->flags
& MPDM_FILE
) {
1174 const struct mpdm_file
*fs
= fd
->data
;
1183 mpdm_t mpdm_bread(mpdm_t fd, int size)
1188 int mpdm_bwrite(mpdm_tfd, mpdm_t v, int size)
1194 static mpdm_t
embedded_encodings(void)
1200 L
"iso8859-1", L
"iso8859-1",
1201 L
"iso-8859-1", NULL
,
1204 L
"utf-16le", L
"utf-16le",
1207 L
"utf-16be", L
"utf-16be",
1210 L
"utf-16", L
"utf-16",
1214 L
"utf-32le", L
"utf-32le",
1217 L
"utf-32be", L
"utf-32be",
1220 L
"utf-32", L
"utf-32",
1224 L
"utf-8bom", L
"utf-8bom",
1229 if ((e
= mpdm_hget_s(mpdm_root(), L
"EMBEDDED_ENCODINGS")) == NULL
) {
1235 for (n
= 0; e2e
[n
] != NULL
; n
+= 2) {
1236 mpdm_t v
= MPDM_S(e2e
[n
]);
1238 if (e2e
[n
+ 1] != NULL
)
1241 mpdm_hset(e
, v
, MPDM_S(p
));
1242 mpdm_hset(e
, mpdm_ulc(v
, 1), MPDM_S(p
));
1245 mpdm_hset_s(mpdm_root(), L
"EMBEDDED_ENCODINGS", e
);
1253 * mpdm_encoding - Sets the current charset encoding for files.
1254 * @charset: the charset name.
1256 * Sets the current charset encoding for files. Future opened
1257 * files will be assumed to be encoded with @charset, which can
1258 * be any of the supported charset names (utf-8, iso-8859-1, etc.),
1259 * and converted on each read / write. If charset is NULL, it
1260 * is reverted to default charset conversion (i.e. the one defined
1262 * Returns a negative number if @charset is unsupported, or zero
1263 * if no errors were found.
1265 * [Character Set Conversion]
1267 int mpdm_encoding(mpdm_t charset
)
1270 mpdm_t e
= embedded_encodings();
1273 /* NULL encoding? done */
1274 if (mpdm_size(charset
) == 0) {
1275 mpdm_hset_s(mpdm_root(), L
"ENCODING", NULL
);
1279 #ifdef CONFOPT_ICONV
1282 mpdm_t cs
= MPDM_2MBS(charset
->data
);
1284 /* tries to create an iconv encoder and decoder for this charset */
1286 if ((ic
= iconv_open("WCHAR_T", (char *) cs
->data
)) == (iconv_t
) - 1)
1291 if ((ic
= iconv_open((char *) cs
->data
, "WCHAR_T")) == (iconv_t
) - 1)
1296 /* got a valid encoding */
1302 #endif /* CONFOPT_ICONV */
1304 if (ret
!= 0 && (v
= mpdm_hget(e
, charset
)) != NULL
)
1308 mpdm_hset_s(mpdm_root(), L
"ENCODING", v
);
1315 * mpdm_unlink - Deletes a file.
1316 * @filename: file name to be deleted
1321 int mpdm_unlink(const mpdm_t filename
)
1326 /* convert to mbs */
1327 fn
= MPDM_2MBS(filename
->data
);
1329 if ((ret
= unlink((char *) fn
->data
)) == -1)
1337 * mpdm_stat - Gives status from a file.
1338 * @filename: file name to get the status from
1340 * Returns a 14 element array of the status (permissions, onwer, etc.)
1341 * from the desired @filename, or NULL if the file cannot be accessed.
1344 * The values are: 0, device number of filesystem; 1, inode number;
1345 * 2, file mode; 3, number of hard links to the file; 4, uid; 5, gid;
1346 * 6, device identifier; 7, total size of file in bytes; 8, atime;
1347 * 9, mtime; 10, ctime; 11, preferred block size for system I/O;
1348 * 12, number of blocks allocated and 13, canonicalized file name.
1349 * Not all elements have necesarily meaningful values, as most are
1353 mpdm_t
mpdm_stat(const mpdm_t filename
)
1357 #ifdef CONFOPT_SYS_STAT_H
1361 fn
= MPDM_2MBS(filename
->data
);
1363 if (stat((char *) fn
->data
, &s
) != -1) {
1366 mpdm_aset(r
, MPDM_I(s
.st_dev
), 0);
1367 mpdm_aset(r
, MPDM_I(s
.st_ino
), 1);
1368 mpdm_aset(r
, MPDM_I(s
.st_mode
), 2);
1369 mpdm_aset(r
, MPDM_I(s
.st_nlink
), 3);
1370 mpdm_aset(r
, MPDM_I(s
.st_uid
), 4);
1371 mpdm_aset(r
, MPDM_I(s
.st_gid
), 5);
1372 mpdm_aset(r
, MPDM_I(s
.st_rdev
), 6);
1373 mpdm_aset(r
, MPDM_I(s
.st_size
), 7);
1374 mpdm_aset(r
, MPDM_I(s
.st_atime
), 8);
1375 mpdm_aset(r
, MPDM_I(s
.st_mtime
), 9);
1376 mpdm_aset(r
, MPDM_I(s
.st_ctime
), 10);
1377 mpdm_aset(r
, MPDM_I(0), 11); /* s.st_blksize */
1378 mpdm_aset(r
, MPDM_I(0), 12); /* s.st_blocks */
1380 #ifdef CONFOPT_CANONICALIZE_FILE_NAME
1385 if ((ptr
= canonicalize_file_name(
1386 (char *)fn
->data
)) != NULL
) {
1387 mpdm_aset(r
, MPDM_MBS(ptr
), 13);
1393 #ifdef CONFOPT_REALPATH
1397 if (realpath((char *)fn
->data
, tmp
) != NULL
)
1398 mpdm_aset(r
, MPDM_MBS(tmp
), 13);
1402 #ifdef CONFOPT_FULLPATH
1404 char tmp
[_MAX_PATH
+ 1];
1406 if (_fullpath(tmp
, (char *)fn
->data
, _MAX_PATH
) != NULL
)
1407 mpdm_aset(r
, MPDM_MBS(tmp
), 13);
1415 #endif /* CONFOPT_SYS_STAT_H */
1422 * mpdm_chmod - Changes a file's permissions.
1423 * @filename: the file name
1424 * @perms: permissions (element 2 from mpdm_stat())
1426 * Changes the permissions for a file.
1429 int mpdm_chmod(const mpdm_t filename
, mpdm_t perms
)
1433 mpdm_t fn
= MPDM_2MBS(filename
->data
);
1435 if ((r
= chmod((char *) fn
->data
, mpdm_ival(perms
))) == -1)
1443 * mpdm_chdir - Changes the working directory
1444 * @dir: the new path
1446 * Changes the working directory
1449 int mpdm_chdir(const mpdm_t dir
)
1453 mpdm_t fn
= MPDM_2MBS(dir
->data
);
1455 if ((r
= chdir((char *) fn
->data
)) == -1)
1463 * mpdm_chown - Changes a file's owner.
1464 * @filename: the file name
1465 * @uid: user id (element 4 from mpdm_stat())
1466 * @gid: group id (element 5 from mpdm_stat())
1468 * Changes the owner and group id's for a file.
1471 int mpdm_chown(const mpdm_t filename
, mpdm_t uid
, mpdm_t gid
)
1475 #ifdef CONFOPT_CHOWN
1477 mpdm_t fn
= MPDM_2MBS(filename
->data
);
1479 if ((r
= chown((char *) fn
->data
, mpdm_ival(uid
), mpdm_ival(gid
))) == -1)
1482 #endif /* CONFOPT_CHOWN */
1489 * mpdm_glob - Executes a file globbing.
1490 * @spec: Globbing spec
1491 * @base: Optional base directory
1493 * Executes a file globbing. @spec is system-dependent, but usually
1494 * the * and ? metacharacters work everywhere. @base can contain a
1495 * directory; if that's the case, the output strings will include it.
1496 * In any case, each returned value will be suitable for a call to
1499 * Returns an array of files that match the globbing (can be an empty
1500 * array if no file matches), or NULL if globbing is unsupported.
1503 mpdm_t
mpdm_glob(const mpdm_t spec
, const mpdm_t base
)
1509 #ifdef CONFOPT_WIN32
1518 if (mpdm_size(base
))
1519 sp
= mpdm_strcat(base
, MPDM_LS(L
"/"));
1521 sp
= mpdm_strcat(sp
, mpdm_size(spec
) == 0 ? MPDM_LS(L
"*.*") : spec
);
1523 /* delete repeated directory delimiters */
1524 sp
= mpdm_sregex(MPDM_LS(L
"@[\\/]+@g"), sp
, MPDM_LS(L
"/"), 0);
1526 sp
= MPDM_2MBS(sp
->data
);
1532 if ((h
= FindFirstFile((char *) sp
->data
, &fd
)) != INVALID_HANDLE_VALUE
) {
1533 /* if spec includes a directory, store in s */
1534 if ((ptr
= strrchr((char *) sp
->data
, '/')) != NULL
) {
1536 s
= MPDM_MBS(sp
->data
);
1540 /* ignore . and .. */
1541 if (strcmp(fd
.cFileName
, ".") == 0 || strcmp(fd
.cFileName
, "..") == 0)
1544 /* concat base directory and file names */
1545 w
= mpdm_strcat(s
, MPDM_MBS(fd
.cFileName
));
1547 /* if it's a directory, add a / */
1548 if (fd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) {
1549 w
= mpdm_strcat(w
, MPDM_LS(L
"/"));
1555 while (FindNextFile(h
, &fd
));
1564 /* glob.h support */
1568 /* build full path */
1569 if (mpdm_size(base
))
1570 v
= mpdm_strcat(base
, MPDM_LS(L
"/"));
1572 v
= mpdm_strcat(v
, mpdm_size(spec
) == 0 ? MPDM_LS(L
"*") : spec
);
1574 /* delete repeated directory delimiters */
1575 v
= mpdm_sregex(MPDM_LS(L
"@/{2,}@g"), v
, MPDM_LS(L
"/"), 0);
1577 v
= MPDM_2MBS(v
->data
);
1581 globbuf
.gl_offs
= 1;
1587 if (glob(ptr
, GLOB_MARK
, NULL
, &globbuf
) == 0) {
1590 for (n
= 0; globbuf
.gl_pathv
[n
] != NULL
; n
++) {
1591 char *ptr
= globbuf
.gl_pathv
[n
];
1592 mpdm_t t
= MPDM_MBS(ptr
);
1594 /* if last char is /, add to directories */
1595 if (ptr
[strlen(ptr
) - 1] == '/')
1606 /* no win32 nor glob.h; try workaround */
1614 d
= mpdm_sort(d
, 1);
1615 f
= mpdm_sort(f
, 1);
1617 /* transfer all data in d and f */
1618 for (n
= 0; n
< mpdm_size(d
); n
++)
1619 mpdm_push(v
, mpdm_aget(d
, n
));
1620 for (n
= 0; n
< mpdm_size(f
); n
++)
1621 mpdm_push(v
, mpdm_aget(f
, n
));
1628 #ifdef CONFOPT_WIN32
1630 static void win32_pipe(HANDLE
* h
, int n
)
1632 SECURITY_ATTRIBUTES sa
;
1635 memset(&sa
, '\0', sizeof(sa
));
1636 sa
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
1637 sa
.bInheritHandle
= TRUE
;
1638 sa
.lpSecurityDescriptor
= NULL
;
1640 cp
= GetCurrentProcess();
1642 CreatePipe(&h
[0], &h
[1], &sa
, 0);
1643 DuplicateHandle(cp
, h
[n
], cp
, &t
, 0, FALSE
, DUPLICATE_SAME_ACCESS
);
1649 static int sysdep_popen(mpdm_t v
, char *prg
, int rw
)
1650 /* win32-style pipe */
1654 PROCESS_INFORMATION pi
;
1657 struct mpdm_file
*fs
= v
->data
;
1660 pr
[0] = pr
[1] = pw
[0] = pw
[1] = NULL
;
1667 /* spawn new process */
1668 memset(&pi
, '\0', sizeof(pi
));
1669 memset(&si
, '\0', sizeof(si
));
1671 si
.cb
= sizeof(STARTUPINFO
);
1672 si
.hStdError
= pr
[1];
1673 si
.hStdOutput
= pr
[1];
1674 si
.hStdInput
= pw
[0];
1675 si
.dwFlags
|= STARTF_USESTDHANDLES
;
1677 ret
= CreateProcess(NULL
, prg
, NULL
, NULL
, TRUE
, 0, NULL
, NULL
, &si
, &pi
);
1691 static int sysdep_pclose(const mpdm_t v
)
1693 const struct mpdm_file
*fs
= v
->data
;
1695 if (fs
->hin
!= NULL
)
1696 CloseHandle(fs
->hin
);
1698 if (fs
->hout
!= NULL
)
1699 CloseHandle(fs
->hout
);
1701 /* how to know process exit code? */
1706 #else /* CONFOPT_WIN32 */
1708 static int sysdep_popen(mpdm_t v
, char *prg
, int rw
)
1709 /* unix-style pipe open */
1712 struct mpdm_file
*fs
= (struct mpdm_file
*)v
->data
;
1715 pr
[0] = pr
[1] = pw
[0] = pw
[1] = -1;
1735 /* redirect stderr to stdout */
1739 /* run the program */
1740 execlp("/bin/sh", "/bin/sh", "-c", prg
, NULL
);
1741 execlp(prg
, prg
, NULL
);
1743 /* still here? exec failed; close pipes and exit */
1749 /* create the pipes as non-buffered streams */
1751 fs
->in
= fdopen(pr
[0], "r");
1752 setvbuf(fs
->in
, NULL
, _IONBF
, 0);
1757 fs
->out
= fdopen(pw
[1], "w");
1758 setvbuf(fs
->out
, NULL
, _IONBF
, 0);
1766 static int sysdep_pclose(const mpdm_t v
)
1767 /* unix-style pipe close */
1770 const struct mpdm_file
*fs
= v
->data
;
1775 if (fs
->out
!= fs
->in
&& fs
->out
!= NULL
)
1784 #endif /* CONFOPT_WIN32 */
1788 * mpdm_popen - Opens a pipe.
1789 * @prg: the program to pipe
1790 * @mode: an fopen-like mode string
1792 * Opens a pipe to a program. If @prg can be open in the specified @mode, an
1793 * mpdm_t value will be returned containing the file descriptor, or NULL
1797 mpdm_t
mpdm_popen(const mpdm_t prg
, const mpdm_t mode
)
1803 if (prg
== NULL
|| mode
== NULL
)
1806 if ((v
= new_mpdm_file()) == NULL
)
1809 /* convert to mbs,s */
1810 pr
= MPDM_2MBS(prg
->data
);
1811 md
= MPDM_2MBS(mode
->data
);
1814 m
= (char *) md
->data
;
1822 rw
= 0x03; /* r+ or w+ */
1824 if (!sysdep_popen(v
, (char *) pr
->data
, rw
)) {
1825 destroy_mpdm_file(v
);
1834 * mpdm_pclose - Closes a pipe.
1835 * @fd: the value containing the file descriptor
1840 mpdm_t
mpdm_pclose(mpdm_t fd
)
1844 if ((fd
->flags
& MPDM_FILE
) && fd
->data
!= NULL
) {
1845 r
= MPDM_I(sysdep_pclose(fd
));
1846 destroy_mpdm_file(fd
);
1854 * mpdm_home_dir - Returns the home user directory.
1856 * Returns a system-dependent directory where the user can write
1857 * documents and create subdirectories.
1860 mpdm_t
mpdm_home_dir(void)
1866 #ifdef CONFOPT_WIN32
1870 /* get the 'My Documents' folder */
1871 SHGetSpecialFolderLocation(NULL
, CSIDL_PERSONAL
, &pidl
);
1872 SHGetPathFromIDList(pidl
, tmp
);
1877 #ifdef CONFOPT_PWD_H
1881 /* get home dir from /etc/passwd entry */
1882 if (tmp
[0] == '\0' && (p
= getpwuid(getpid())) != NULL
) {
1883 strcpy(tmp
, p
->pw_dir
);
1889 /* still none? try the ENV variable $HOME */
1890 if (tmp
[0] == '\0' && (ptr
= getenv("HOME")) != NULL
) {
1903 * mpdm_app_dir - Returns the applications directory.
1905 * Returns a system-dependent directory where the applications store
1906 * their private data, as components or resources.
1909 mpdm_t
mpdm_app_dir(void)
1913 #ifdef CONFOPT_WIN32
1919 /* get the 'Program Files' folder (can fail) */
1921 if (SHGetSpecialFolderLocation(NULL
, CSIDL_PROGRAM_FILES
, &pidl
) == S_OK
)
1922 SHGetPathFromIDList(pidl
, tmp
);
1924 /* if it's still empty, get from the registry */
1925 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
,
1926 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
1927 0, KEY_QUERY_VALUE
, &hkey
) == ERROR_SUCCESS
) {
1928 int n
= sizeof(tmp
);
1930 if (RegQueryValueEx(hkey
, "ProgramFilesDir",
1931 NULL
, NULL
, tmp
, (LPDWORD
) & n
) != ERROR_SUCCESS
)
1935 if (tmp
[0] != '\0') {
1941 /* still none? get the configured directory */
1943 r
= MPDM_MBS(CONFOPT_PREFIX
"/share/");