3 MPDM - Minimum Profit Data Manager
4 Copyright (C) 2003/2010 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
) (struct mpdm_file
*, int *);
81 int (*f_write
) (struct mpdm_file
*, const wchar_t *);
86 #endif /* CONFOPT_ICONV */
92 #endif /* CONFOPT_WIN32 */
102 static void store_syserr(void)
103 /* stores the system error inside the global ERRNO */
105 mpdm_hset_s(mpdm_root(), L
"ERRNO", MPDM_MBS(strerror(errno
)));
109 static int get_char(struct mpdm_file
*f
)
110 /* reads a character from a file structure */
116 if (f
->hin
!= NULL
) {
120 if (ReadFile(f
->hin
, &tmp
, 1, &n
, NULL
) && n
> 0)
124 #endif /* CONFOPT_WIN32 */
127 /* read (converting to positive if needed) */
128 if ((c
= fgetc(f
->in
)) < 0 && !feof(f
->in
))
136 static int put_buf(const char *ptr
, int s
, struct mpdm_file
*f
)
137 /* writes s bytes in the buffer in ptr to f */
141 if (f
->hout
!= NULL
) {
144 if (WriteFile(f
->hout
, ptr
, s
, &n
, NULL
) && n
> 0)
148 #endif /* CONFOPT_WIN32 */
151 s
= fwrite(ptr
, s
, 1, f
->out
);
157 static int put_char(int c
, struct mpdm_file
*f
)
158 /* writes a character in a file structure */
162 if (put_buf(&tmp
, 1, f
) != 1)
169 static wchar_t *read_mbs(struct mpdm_file
*f
, int *s
)
170 /* reads a multibyte string from a mpdm_file into a dynamic string */
177 while ((c
= get_char(f
)) != EOF
) {
183 if (i
== sizeof(tmp
) - 1) {
184 /* out of space; start allocating */
186 mpdm_poke(auxptr
, &n
, tmp
, i
, sizeof(char))) == NULL
)
193 /* is there something to return? */
199 /* auxiliary space used; concat all */
201 mpdm_poke(auxptr
, &n
, tmp
, i
, sizeof(char))) == NULL
)
204 /* do the conversion */
205 ptr
= mpdm_mbstowcs(auxptr
, s
, -1);
210 ptr
= mpdm_mbstowcs(tmp
, s
, -1);
217 static int write_wcs(struct mpdm_file
*f
, const wchar_t * str
)
218 /* writes a wide string to an struct mpdm_file */
223 ptr
= mpdm_wcstombs(str
, &s
);
224 s
= put_buf(ptr
, s
, f
);
233 static wchar_t *read_iconv(struct mpdm_file
*f
, int *s
)
234 /* reads a multibyte string transforming with iconv */
243 /* resets the decoder */
244 iconv(f
->ic_dec
, NULL
, NULL
, NULL
, NULL
);
246 while ((c
= get_char(f
)) != EOF
) {
252 /* too big? shouldn't happen */
253 if (i
== sizeof(tmp
))
258 ol
= sizeof(wchar_t);
262 if (iconv(f
->ic_dec
, &iptr
, &il
, &optr
, &ol
) == (size_t) - 1) {
263 /* found incomplete multibyte character */
267 /* otherwise, return '?' */
273 if ((ptr
= mpdm_poke(ptr
, s
, &wc
, 1, sizeof(wchar_t))) == NULL
)
276 /* if it's an end of line, finish */
282 ptr
= mpdm_poke(ptr
, s
, L
"", 1, sizeof(wchar_t));
290 static int write_iconv(struct mpdm_file
*f
, const wchar_t * str
)
291 /* writes a wide string to a stream using iconv */
296 /* resets the encoder */
297 iconv(f
->ic_enc
, NULL
, NULL
, NULL
, NULL
);
299 /* convert char by char */
300 for (; *str
!= L
'\0'; str
++) {
305 il
= sizeof(wchar_t);
311 if (iconv(f
->ic_enc
, &iptr
, &il
, &optr
, &ol
) == (size_t) - 1) {
312 /* error converting; convert a '?' instead */
315 il
= sizeof(wchar_t);
320 iconv(f
->ic_enc
, &iptr
, &il
, &optr
, &ol
);
323 for (n
= 0; n
< (int) (sizeof(tmp
) - ol
); n
++, cnt
++) {
324 if (put_char(tmp
[n
], f
) == EOF
)
333 #endif /* CONFOPT_ICONV */
335 #define UTF8_BYTE() if((c = get_char(f)) == EOF) break
337 static wchar_t *read_utf8(struct mpdm_file
*f
, int *s
)
354 if ((c
& 0xe0) == 0xe0) {
355 wc
= (c
& 0x1f) << 12;
357 wc
|= (c
& 0x3f) << 6;
362 wc
= (c
& 0x3f) << 6;
368 if ((ptr
= mpdm_poke(ptr
, s
, &wc
, 1, sizeof(wchar_t))) == NULL
)
371 /* if it's an end of line, finish */
377 ptr
= mpdm_poke(ptr
, s
, L
"", 1, sizeof(wchar_t));
385 static int write_utf8(struct mpdm_file
*f
, const wchar_t * str
)
391 /* convert char by char */
392 for (; (wc
= *str
) != L
'\0'; str
++) {
394 put_char((int) wc
, f
);
397 put_char((int) (0xc0 | (wc
>> 6)), f
);
398 put_char((int) (0x80 | (wc
& 0x3f)), f
);
402 put_char((int) (0xe0 | (wc
>> 12)), f
);
403 put_char((int) (0x80 | ((wc
>> 6) & 0x3f)), f
);
404 put_char((int) (0x80 | (wc
& 0x3f)), f
);
415 static wchar_t *read_utf8_bom(struct mpdm_file
*f
, int *s
)
416 /* utf-8 reader with BOM detection */
423 if (get_char(f
) == 0xef && get_char(f
) == 0xbb && get_char(f
) == 0xbf)
427 fseek(f
->in
, 0, SEEK_SET
);
430 mpdm_hset_s(mpdm_root(), L
"DETECTED_ENCODING", MPDM_LS(enc
));
432 /* we're utf-8 from now on */
433 f
->f_read
= read_utf8
;
435 return f
->f_read(f
, s
);
439 static int write_utf8_bom(struct mpdm_file
*f
, const wchar_t * str
)
440 /* utf-8 writer with BOM */
447 /* we're utf-8 from now on */
448 f
->f_write
= write_utf8
;
450 return f
->f_write(f
, str
);
454 static wchar_t *read_iso8859_1(struct mpdm_file
*f
, int *s
)
455 /* iso8859-1 reader */
463 while ((c
= get_char(f
)) != EOF
) {
467 if ((ptr
= mpdm_poke(ptr
, s
, &wc
, 1, sizeof(wchar_t))) == NULL
)
470 /* if it's an end of line, finish */
476 ptr
= mpdm_poke(ptr
, s
, L
"", 1, sizeof(wchar_t));
484 static int write_iso8859_1(struct mpdm_file
*f
, const wchar_t * str
)
485 /* iso8859-1 writer */
490 /* convert char by char */
491 for (; (wc
= *str
) != L
'\0'; str
++)
492 put_char(wc
<= 0xff ? (int) wc
: '?', f
);
498 static wchar_t *read_utf16ae(struct mpdm_file
*f
, int *s
, int le
)
499 /* utf16 reader, ANY ending */
510 if ((c1
= get_char(f
)) == EOF
)
513 if ((c2
= get_char(f
)) == EOF
)
522 if ((ptr
= mpdm_poke(ptr
, s
, &wc
, 1, sizeof(wchar_t))) == NULL
)
525 /* if it's an end of line, finish */
531 ptr
= mpdm_poke(ptr
, s
, L
"", 1, sizeof(wchar_t));
539 static int write_utf16ae(struct mpdm_file
*f
, const wchar_t * str
, int le
)
540 /* utf16 writer, ANY ending */
545 /* convert char by char */
546 for (; (wc
= *str
) != L
'\0'; str
++) {
549 put_char(wc
& 0xff, f
);
550 put_char((wc
& 0xff00) >> 8, f
);
553 put_char((wc
& 0xff00) >> 8, f
);
554 put_char(wc
& 0xff, f
);
562 static wchar_t *read_utf16le(struct mpdm_file
*f
, int *s
)
564 return read_utf16ae(f
, s
, 1);
568 static int write_utf16le(struct mpdm_file
*f
, const wchar_t * str
)
570 return write_utf16ae(f
, str
, 1);
574 static wchar_t *read_utf16be(struct mpdm_file
*f
, int *s
)
576 return read_utf16ae(f
, s
, 0);
580 static int write_utf16be(struct mpdm_file
*f
, const wchar_t * str
)
582 return write_utf16ae(f
, str
, 0);
586 static wchar_t *read_utf16(struct mpdm_file
*f
, int *s
)
589 wchar_t *enc
= L
"utf-16le";
591 /* assume little-endian */
592 f
->f_read
= read_utf16le
;
598 if (c1
== 0xfe && c2
== 0xff) {
600 f
->f_read
= read_utf16be
;
603 if (c1
!= 0xff || c2
!= 0xfe) {
604 /* no BOM; rewind and hope */
605 fseek(f
->in
, 0, SEEK_SET
);
608 mpdm_hset_s(mpdm_root(), L
"DETECTED_ENCODING", MPDM_LS(enc
));
610 return f
->f_read(f
, s
);
614 static int write_utf16le_bom(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 int write_utf16be_bom(struct mpdm_file
*f
, const wchar_t * str
)
629 /* store the BE signature */
633 /* we're 16be from now on */
634 f
->f_write
= write_utf16be
;
636 return f
->f_write(f
, str
);
640 static wchar_t *read_utf32ae(struct mpdm_file
*f
, int *s
, int le
)
641 /* utf32 reader, ANY ending */
652 if ((c1
= get_char(f
)) == EOF
)
655 if ((c2
= get_char(f
)) == EOF
)
658 if ((c3
= get_char(f
)) == EOF
)
661 if ((c4
= get_char(f
)) == EOF
)
665 wc
= c1
| (c2
<< 8) | (c3
<< 16) | (c4
<< 24);
667 wc
= c4
| (c3
<< 8) | (c2
<< 16) | (c1
<< 24);
670 if ((ptr
= mpdm_poke(ptr
, s
, &wc
, 1, sizeof(wchar_t))) == NULL
)
673 /* if it's an end of line, finish */
679 ptr
= mpdm_poke(ptr
, s
, L
"", 1, sizeof(wchar_t));
687 static int write_utf32ae(struct mpdm_file
*f
, const wchar_t * str
, int le
)
688 /* utf32 writer, ANY ending */
693 /* convert char by char */
694 for (; (wc
= *str
) != L
'\0'; str
++) {
697 put_char((wc
& 0x000000ff), f
);
698 put_char((wc
& 0x0000ff00) >> 8, f
);
699 put_char((wc
& 0x00ff0000) >> 16, f
);
700 put_char((wc
& 0xff000000) >> 24, f
);
703 put_char((wc
& 0xff000000) >> 24, f
);
704 put_char((wc
& 0x00ff0000) >> 16, f
);
705 put_char((wc
& 0x0000ff00) >> 8, f
);
706 put_char((wc
& 0x000000ff), f
);
714 static wchar_t *read_utf32le(struct mpdm_file
*f
, int *s
)
716 return read_utf32ae(f
, s
, 1);
720 static int write_utf32le(struct mpdm_file
*f
, const wchar_t * str
)
722 return write_utf32ae(f
, str
, 1);
726 static wchar_t *read_utf32be(struct mpdm_file
*f
, int *s
)
728 return read_utf32ae(f
, s
, 0);
732 static int write_utf32be(struct mpdm_file
*f
, const wchar_t * str
)
734 return write_utf32ae(f
, str
, 0);
738 static wchar_t *read_utf32(struct mpdm_file
*f
, int *s
)
741 wchar_t *enc
= L
"utf-32le";
743 f
->f_read
= read_utf32le
;
751 if (c1
== 0 && c2
== 0 && c3
== 0xfe && c4
== 0xff) {
753 f
->f_read
= read_utf32be
;
755 if (c1
!= 0xff || c2
!= 0xfe || c3
!= 0 || c4
!= 0) {
756 /* no BOM; assume le and hope */
757 fseek(f
->in
, 0, SEEK_SET
);
760 mpdm_hset_s(mpdm_root(), L
"DETECTED_ENCODING", MPDM_LS(enc
));
762 return f
->f_read(f
, s
);
766 static int write_utf32le_bom(struct mpdm_file
*f
, const wchar_t * str
)
768 /* store the LE signature */
774 /* we're 32le from now on */
775 f
->f_write
= write_utf32le
;
777 return f
->f_write(f
, str
);
781 static int write_utf32be_bom(struct mpdm_file
*f
, const wchar_t * str
)
783 /* store the BE signature */
789 /* we're 32be from now on */
790 f
->f_write
= write_utf32be
;
792 return f
->f_write(f
, str
);
796 static wchar_t *read_auto(struct mpdm_file
*f
, int *s
)
797 /* autodetects different encodings based on the BOM */
801 /* by default, multibyte reading */
802 f
->f_read
= read_mbs
;
804 /* ensure seeking is possible */
805 if (f
->in
!= NULL
&& fseek(f
->in
, 0, SEEK_CUR
) != -1) {
811 /* can be utf32le or utf16le */
812 if (get_char(f
) == 0xfe) {
813 /* if next 2 chars are 0x00, it's utf32; otherwise utf16 */
814 if (get_char(f
) == 0x00 && get_char(f
) == 0x00) {
816 f
->f_read
= read_utf32le
;
820 /* rewind to 3rd character */
821 fseek(f
->in
, 2, SEEK_SET
);
824 f
->f_read
= read_utf16le
;
832 if (get_char(f
) == 0x00 && get_char(f
) == 0xfe
833 && get_char(f
) == 0xff) {
835 f
->f_read
= read_utf32be
;
842 if (get_char(f
) == 0xff) {
844 f
->f_read
= read_utf16be
;
850 /* can be utf8 with BOM */
851 if (get_char(f
) == 0xbb && get_char(f
) == 0xbf) {
853 f
->f_read
= read_utf8
;
858 /* try if a first bunch of chars are valid UTF-8 */
863 while (--n
&& (c
= get_char(f
)) != EOF
) {
864 if ((c
& 0xc0) == 0x80) {
865 if ((p
& 0xc0) == 0xc0)
868 if ((p
& 0x80) == 0x00) {
874 if ((p
& 0xc0) == 0xc0) {
883 /* invalid utf-8; fall back to 8bit */
885 f
->f_read
= read_iso8859_1
;
889 /* utf-8 sequences found */
891 f
->f_read
= read_utf8
;
894 /* 7 bit ASCII: do nothing */
897 /* none of the above; restart */
898 fseek(f
->in
, 0, SEEK_SET
);
902 mpdm_hset_s(mpdm_root(), L
"DETECTED_ENCODING", MPDM_LS(enc
));
904 return f
->f_read(f
, s
);
908 static mpdm_t
new_mpdm_file(void)
909 /* creates a new file value */
912 struct mpdm_file
*fs
;
915 if ((fs
= malloc(sizeof(struct mpdm_file
))) == NULL
)
918 memset(fs
, '\0', sizeof(struct mpdm_file
));
920 /* default I/O functions */
921 fs
->f_read
= read_auto
;
922 fs
->f_write
= write_wcs
;
925 /* no iconv encodings by default */
926 fs
->ic_enc
= fs
->ic_dec
= (iconv_t
) - 1;
930 mpdm_new(MPDM_FILE
| MPDM_FREE
, fs
,
931 sizeof(struct mpdm_file
))) == NULL
) {
936 e
= mpdm_hget_s(mpdm_root(), L
"ENCODING");
938 if (mpdm_size(e
) == 0)
939 e
= mpdm_hget_s(mpdm_root(), L
"TEMP_ENCODING");
943 wchar_t *enc
= mpdm_string(e
);
945 if (wcscmp(enc
, L
"utf-8") == 0) {
946 fs
->f_read
= read_utf8_bom
;
947 fs
->f_write
= write_utf8
;
950 if (wcscmp(enc
, L
"utf-8bom") == 0) {
951 fs
->f_read
= read_utf8_bom
;
952 fs
->f_write
= write_utf8_bom
;
955 if (wcscmp(enc
, L
"iso8859-1") == 0 ||
956 wcscmp(enc
, L
"8bit") == 0) {
957 fs
->f_read
= read_iso8859_1
;
958 fs
->f_write
= write_iso8859_1
;
961 if (wcscmp(enc
, L
"utf-16le") == 0) {
962 fs
->f_read
= read_utf16le
;
963 fs
->f_write
= write_utf16le_bom
;
966 if (wcscmp(enc
, L
"utf-16be") == 0) {
967 fs
->f_read
= read_utf16be
;
968 fs
->f_write
= write_utf16be_bom
;
971 if (wcscmp(enc
, L
"utf-16") == 0) {
972 fs
->f_read
= read_utf16
;
973 fs
->f_write
= write_utf16le_bom
;
976 if (wcscmp(enc
, L
"utf-32le") == 0) {
977 fs
->f_read
= read_utf32le
;
978 fs
->f_write
= write_utf32le_bom
;
981 if (wcscmp(enc
, L
"utf-32be") == 0) {
982 fs
->f_read
= read_utf32be
;
983 fs
->f_write
= write_utf32be_bom
;
986 if (wcscmp(enc
, L
"utf-32") == 0) {
987 fs
->f_read
= read_utf32
;
988 fs
->f_write
= write_utf32le_bom
;
992 mpdm_t cs
= MPDM_2MBS(e
->data
);
995 iconv_open((char *) cs
->data
, "WCHAR_T")) != (iconv_t
) - 1
997 iconv_open("WCHAR_T",
998 (char *) cs
->data
)) != (iconv_t
) - 1) {
1000 fs
->f_read
= read_iconv
;
1001 fs
->f_write
= write_iconv
;
1003 #endif /* CONFOPT_ICONV */
1006 mpdm_hset_s(mpdm_root(), L
"TEMP_ENCODING", NULL
);
1013 static void destroy_mpdm_file(mpdm_t v
)
1014 /* destroys and file value */
1016 struct mpdm_file
*fs
= (struct mpdm_file
*) v
->data
;
1019 #ifdef CONFOPT_ICONV
1020 if (fs
->ic_enc
!= (iconv_t
) - 1) {
1021 iconv_close(fs
->ic_enc
);
1022 fs
->ic_enc
= (iconv_t
) - 1;
1025 if (fs
->ic_dec
!= (iconv_t
) - 1) {
1026 iconv_close(fs
->ic_dec
);
1027 fs
->ic_dec
= (iconv_t
) - 1;
1039 wchar_t *mpdm_read_mbs(FILE * f
, int *s
)
1040 /* reads a multibyte string from a stream into a dynamic string */
1042 struct mpdm_file fs
;
1044 /* reset the structure */
1045 memset(&fs
, '\0', sizeof(fs
));
1048 return read_mbs(&fs
, s
);
1052 int mpdm_write_wcs(FILE * f
, const wchar_t * str
)
1053 /* writes a wide string to a stream */
1055 struct mpdm_file fs
;
1057 /* reset the structure */
1058 memset(&fs
, '\0', sizeof(fs
));
1061 return write_wcs(&fs
, str
);
1065 mpdm_t
mpdm_new_f(FILE * f
)
1066 /* creates a new file value from a FILE * */
1073 if ((v
= new_mpdm_file()) != NULL
) {
1074 struct mpdm_file
*fs
= (struct mpdm_file
*) v
->data
;
1075 fs
->in
= fs
->out
= f
;
1083 * mpdm_open - Opens a file.
1084 * @filename: the file name
1085 * @mode: an fopen-like mode string
1087 * Opens a file. If @filename can be open in the specified @mode, an
1088 * mpdm_t value will be returned containing the file descriptor, or NULL
1091 * If the file is open for reading, some charset detection methods are
1092 * used. If any of them is successful, its name is stored in the
1093 * DETECTED_ENCODING element of the mpdm_root() hash. This value is
1094 * suitable to be copied over ENCODING or TEMP_ENCODING.
1096 * If the file is open for writing, the encoding to be used is read from
1097 * the ENCODING element of mpdm_root() and, if not set, from the
1098 * TEMP_ENCODING one. The latter will always be deleted afterwards.
1101 mpdm_t
mpdm_open(const mpdm_t filename
, const mpdm_t mode
)
1110 if (filename
!= NULL
&& mode
!= NULL
) {
1112 /* convert to mbs,s */
1113 fn
= mpdm_ref(MPDM_2MBS(filename
->data
));
1114 m
= mpdm_ref(MPDM_2MBS(mode
->data
));
1116 if ((f
= fopen((char *) fn
->data
, (char *) m
->data
)) == NULL
)
1119 #if defined(CONFOPT_SYS_STAT_H) && defined(S_ISDIR) && defined(EISDIR)
1122 /* test if the open file is a directory */
1123 if (fstat(fileno(f
), &s
) != -1 && S_ISDIR(s
.st_mode
)) {
1124 /* it's a directory; fail */
1138 mpdm_unref(filename
);
1145 * mpdm_close - Closes a file descriptor.
1146 * @fd: the value containing the file descriptor
1148 * Closes the file descriptor.
1151 mpdm_t
mpdm_close(mpdm_t fd
)
1153 struct mpdm_file
*fs
= (struct mpdm_file
*) fd
->data
;
1157 if ((fd
->flags
& MPDM_FILE
) && fs
!= NULL
) {
1161 if (fs
->out
!= fs
->in
&& fs
->out
!= NULL
)
1164 destroy_mpdm_file(fd
);
1167 fd
= mpdm_unref(fd
);
1174 * mpdm_read - Reads a line from a file descriptor.
1175 * @fd: the value containing the file descriptor
1177 * Reads a line from @fd. Returns the line, or NULL on EOF.
1179 * [Character Set Conversion]
1181 mpdm_t
mpdm_read(const mpdm_t fd
)
1186 struct mpdm_file
*fs
= (struct mpdm_file
*) fd
->data
;
1191 ptr
= fs
->f_read(fs
, &s
);
1194 v
= MPDM_ENS(ptr
, s
);
1200 mpdm_t
mpdm_getchar(const mpdm_t fd
)
1205 struct mpdm_file
*fs
= (struct mpdm_file
*) fd
->data
;
1207 if (fs
!= NULL
&& (c
= get_char(fs
)) != EOF
) {
1208 /* get the char as-is */
1209 tmp
[0] = (wchar_t) c
;
1219 int mpdm_putchar(const mpdm_t fd
, const mpdm_t c
)
1221 struct mpdm_file
*fs
= (struct mpdm_file
*) fd
->data
;
1222 const wchar_t *ptr
= mpdm_string(c
);
1227 if (fs
== NULL
|| put_char(*ptr
, fs
) == -1)
1237 * mpdm_write - Writes a value into a file.
1238 * @fd: the file descriptor.
1239 * @v: the value to be written.
1241 * Writes the @v string value into @fd, using the current encoding.
1243 * [Character Set Conversion]
1245 int mpdm_write(const mpdm_t fd
, const mpdm_t v
)
1247 struct mpdm_file
*fs
= (struct mpdm_file
*) fd
->data
;
1253 ret
= fs
->f_write(fs
, mpdm_string(v
));
1261 int mpdm_fseek(const mpdm_t fd
, long offset
, int whence
)
1263 struct mpdm_file
*fs
= (struct mpdm_file
*) fd
->data
;
1265 return fseek(fs
->in
, offset
, whence
);
1269 long mpdm_ftell(const mpdm_t fd
)
1271 struct mpdm_file
*fs
= (struct mpdm_file
*) fd
->data
;
1273 return ftell(fs
->in
);
1277 FILE *mpdm_get_filehandle(const mpdm_t fd
)
1281 if (fd
->flags
& MPDM_FILE
&& fd
->data
!= NULL
) {
1282 struct mpdm_file
*fs
= (struct mpdm_file
*) fd
->data
;
1291 mpdm_t mpdm_bread(mpdm_t fd, int size)
1296 int mpdm_bwrite(mpdm_tfd, mpdm_t v, int size)
1302 static mpdm_t
embedded_encodings(void)
1308 L
"iso8859-1", L
"iso8859-1",
1309 L
"iso-8859-1", NULL
,
1313 L
"utf-16le", L
"utf-16le",
1316 L
"utf-16be", L
"utf-16be",
1319 L
"utf-16", L
"utf-16",
1323 L
"utf-32le", L
"utf-32le",
1326 L
"utf-32be", L
"utf-32be",
1329 L
"utf-32", L
"utf-32",
1333 L
"utf-8bom", L
"utf-8bom",
1338 if ((e
= mpdm_hget_s(mpdm_root(), L
"EMBEDDED_ENCODINGS")) == NULL
) {
1342 e
= mpdm_ref(MPDM_H(0));
1344 for (n
= 0; e2e
[n
] != NULL
; n
+= 2) {
1345 mpdm_t v
= MPDM_S(e2e
[n
]);
1347 if (e2e
[n
+ 1] != NULL
)
1348 p
= MPDM_S(e2e
[n
+ 1]);
1351 mpdm_hset(e
, mpdm_ulc(v
, 1), p
);
1354 mpdm_hset_s(mpdm_root(), L
"EMBEDDED_ENCODINGS", e
);
1364 * mpdm_encoding - Sets the current charset encoding for files.
1365 * @charset: the charset name.
1367 * Sets the current charset encoding for files. Future opened
1368 * files will be assumed to be encoded with @charset, which can
1369 * be any of the supported charset names (utf-8, iso-8859-1, etc.),
1370 * and converted on each read / write. If charset is NULL, it
1371 * is reverted to default charset conversion (i.e. the one defined
1374 * This function stores the @charset value into the ENCODING item
1375 * of the mpdm_root() hash.
1377 * Returns a negative number if @charset is unsupported, or zero
1378 * if no errors were found.
1380 * [Character Set Conversion]
1382 int mpdm_encoding(mpdm_t charset
)
1385 mpdm_t e
= embedded_encodings();
1390 /* NULL encoding? done */
1391 if (mpdm_size(charset
) == 0) {
1392 mpdm_hset_s(mpdm_root(), L
"ENCODING", NULL
);
1396 #ifdef CONFOPT_ICONV
1399 mpdm_t cs
= mpdm_ref(MPDM_2MBS(charset
->data
));
1401 /* tries to create an iconv encoder and decoder for this charset */
1404 iconv_open("WCHAR_T", (char *) cs
->data
)) == (iconv_t
) - 1)
1410 iconv_open((char *) cs
->data
,
1411 "WCHAR_T")) == (iconv_t
) - 1)
1416 /* got a valid encoding */
1424 #endif /* CONFOPT_ICONV */
1426 if (ret
!= 0 && (v
= mpdm_hget(e
, charset
)) != NULL
)
1430 mpdm_hset_s(mpdm_root(), L
"ENCODING", v
);
1432 mpdm_unref(charset
);
1439 * mpdm_unlink - Deletes a file.
1440 * @filename: file name to be deleted
1445 int mpdm_unlink(const mpdm_t filename
)
1452 /* convert to mbs */
1453 fn
= mpdm_ref(MPDM_2MBS(filename
->data
));
1455 if ((ret
= unlink((char *) fn
->data
)) == -1)
1459 mpdm_unref(filename
);
1466 * mpdm_stat - Gives status from a file.
1467 * @filename: file name to get the status from
1469 * Returns a 14 element array of the status (permissions, onwer, etc.)
1470 * from the desired @filename, or NULL if the file cannot be accessed.
1473 * The values are: 0, device number of filesystem; 1, inode number;
1474 * 2, file mode; 3, number of hard links to the file; 4, uid; 5, gid;
1475 * 6, device identifier; 7, total size of file in bytes; 8, atime;
1476 * 9, mtime; 10, ctime; 11, preferred block size for system I/O;
1477 * 12, number of blocks allocated and 13, canonicalized file name.
1478 * Not all elements have necesarily meaningful values, as most are
1482 mpdm_t
mpdm_stat(const mpdm_t filename
)
1488 #ifdef CONFOPT_SYS_STAT_H
1492 fn
= mpdm_ref(MPDM_2MBS(filename
->data
));
1494 if (stat((char *) fn
->data
, &s
) != -1) {
1499 mpdm_aset(r
, MPDM_I(s
.st_dev
), 0);
1500 mpdm_aset(r
, MPDM_I(s
.st_ino
), 1);
1501 mpdm_aset(r
, MPDM_I(s
.st_mode
), 2);
1502 mpdm_aset(r
, MPDM_I(s
.st_nlink
), 3);
1503 mpdm_aset(r
, MPDM_I(s
.st_uid
), 4);
1504 mpdm_aset(r
, MPDM_I(s
.st_gid
), 5);
1505 mpdm_aset(r
, MPDM_I(s
.st_rdev
), 6);
1506 mpdm_aset(r
, MPDM_I(s
.st_size
), 7);
1507 mpdm_aset(r
, MPDM_I(s
.st_atime
), 8);
1508 mpdm_aset(r
, MPDM_I(s
.st_mtime
), 9);
1509 mpdm_aset(r
, MPDM_I(s
.st_ctime
), 10);
1510 mpdm_aset(r
, MPDM_I(0), 11); /* s.st_blksize */
1511 mpdm_aset(r
, MPDM_I(0), 12); /* s.st_blocks */
1513 #ifdef CONFOPT_CANONICALIZE_FILE_NAME
1518 if ((ptr
= canonicalize_file_name((char *) fn
->data
)) != NULL
) {
1519 mpdm_aset(r
, MPDM_MBS(ptr
), 13);
1525 #ifdef CONFOPT_REALPATH
1529 if (realpath((char *) fn
->data
, tmp
) != NULL
)
1530 mpdm_aset(r
, MPDM_MBS(tmp
), 13);
1534 #ifdef CONFOPT_FULLPATH
1536 char tmp
[_MAX_PATH
+ 1];
1538 if (_fullpath(tmp
, (char *) fn
->data
, _MAX_PATH
) != NULL
)
1539 mpdm_aset(r
, MPDM_MBS(tmp
), 13);
1550 #endif /* CONFOPT_SYS_STAT_H */
1552 mpdm_unref(filename
);
1559 * mpdm_chmod - Changes a file's permissions.
1560 * @filename: the file name
1561 * @perms: permissions (element 2 from mpdm_stat())
1563 * Changes the permissions for a file.
1566 int mpdm_chmod(const mpdm_t filename
, mpdm_t perms
)
1573 mpdm_t fn
= mpdm_ref(MPDM_2MBS(filename
->data
));
1575 if ((r
= chmod((char *) fn
->data
, mpdm_ival(perms
))) == -1)
1580 mpdm_unref(filename
);
1587 * mpdm_chdir - Changes the working directory
1588 * @dir: the new path
1590 * Changes the working directory
1593 int mpdm_chdir(const mpdm_t dir
)
1598 mpdm_t fn
= mpdm_ref(MPDM_2MBS(dir
->data
));
1600 if ((r
= chdir((char *) fn
->data
)) == -1)
1611 * mpdm_chown - Changes a file's owner.
1612 * @filename: the file name
1613 * @uid: user id (element 4 from mpdm_stat())
1614 * @gid: group id (element 5 from mpdm_stat())
1616 * Changes the owner and group id's for a file.
1619 int mpdm_chown(const mpdm_t filename
, mpdm_t uid
, mpdm_t gid
)
1627 #ifdef CONFOPT_CHOWN
1629 mpdm_t fn
= mpdm_ref(MPDM_2MBS(filename
->data
));
1632 chown((char *) fn
->data
, mpdm_ival(uid
), mpdm_ival(gid
))) == -1)
1637 #endif /* CONFOPT_CHOWN */
1641 mpdm_unref(filename
);
1648 * mpdm_glob - Executes a file globbing.
1649 * @spec: Globbing spec
1650 * @base: Optional base directory
1652 * Executes a file globbing. @spec is system-dependent, but usually
1653 * the * and ? metacharacters work everywhere. @base can contain a
1654 * directory; if that's the case, the output strings will include it.
1655 * In any case, each returned value will be suitable for a call to
1658 * Returns an array of files that match the globbing (can be an empty
1659 * array if no file matches), or NULL if globbing is unsupported.
1662 mpdm_t
mpdm_glob(const mpdm_t spec
, const mpdm_t base
)
1671 #ifdef CONFOPT_WIN32
1681 if (mpdm_size(base
))
1682 sp
= mpdm_strcat_s(base
, L
"/");
1687 if (mpdm_size(spec
) == 0)
1688 sp
= mpdm_strcat_s(w
, L
"*.*");
1690 sp
= mpdm_strcat(w
, spec
);
1694 /* delete repeated directory delimiters */
1696 sp
= mpdm_sregex(w
, MPDM_LS(L
"@[\\/]+@g"), MPDM_LS(L
"/"), 0);
1700 sp
= MPDM_2MBS(w
->data
);
1704 d
= mpdm_ref(MPDM_A(0));
1705 f
= mpdm_ref(MPDM_A(0));
1709 FindFirstFile((char *) sp
->data
, &fd
)) != INVALID_HANDLE_VALUE
) {
1710 /* if spec includes a directory, store in s */
1711 if ((ptr
= strrchr((char *) sp
->data
, '/')) != NULL
) {
1713 s
= MPDM_MBS(sp
->data
);
1717 /* ignore . and .. */
1718 if (strcmp(fd
.cFileName
, ".") == 0
1719 || strcmp(fd
.cFileName
, "..") == 0)
1722 /* concat base directory and file names */
1723 w
= mpdm_strcat(s
, MPDM_MBS(fd
.cFileName
));
1725 /* if it's a directory, add a / */
1726 if (fd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) {
1727 mpdm_t t
= mpdm_ref(w
);
1728 w
= mpdm_strcat_s(t
, L
"/");
1736 while (FindNextFile(h
, &fd
));
1747 /* glob.h support */
1752 /* build full path */
1753 if (mpdm_size(base
))
1754 v
= mpdm_strcat_s(base
, L
"/");
1758 if (mpdm_size(spec
) == 0)
1759 v
= mpdm_strcat_s(w
, L
"*");
1761 v
= mpdm_strcat(w
, spec
);
1765 /* delete repeated directory delimiters */
1767 v
= mpdm_sregex(w
, MPDM_LS(L
"@/{2,}@g"), MPDM_LS(L
"/"), 0);
1771 v
= MPDM_2MBS(w
->data
);
1776 globbuf
.gl_offs
= 1;
1779 d
= mpdm_ref(MPDM_A(0));
1780 f
= mpdm_ref(MPDM_A(0));
1782 if (glob(ptr
, GLOB_MARK
, NULL
, &globbuf
) == 0) {
1785 for (n
= 0; globbuf
.gl_pathv
[n
] != NULL
; n
++) {
1786 char *ptr
= globbuf
.gl_pathv
[n
];
1787 mpdm_t t
= MPDM_MBS(ptr
);
1789 /* if last char is /, add to directories */
1790 if (ptr
[strlen(ptr
) - 1] == '/')
1801 /* no win32 nor glob.h; try workaround */
1814 /* transfer all data in d and f */
1815 for (n
= 0; n
< mpdm_size(d
); n
++)
1816 mpdm_push(v
, mpdm_aget(d
, n
));
1817 for (n
= 0; n
< mpdm_size(f
); n
++)
1818 mpdm_push(v
, mpdm_aget(f
, n
));
1833 #ifdef CONFOPT_WIN32
1835 static void win32_pipe(HANDLE
* h
, int n
)
1837 SECURITY_ATTRIBUTES sa
;
1840 memset(&sa
, '\0', sizeof(sa
));
1841 sa
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
1842 sa
.bInheritHandle
= TRUE
;
1843 sa
.lpSecurityDescriptor
= NULL
;
1845 cp
= GetCurrentProcess();
1847 CreatePipe(&h
[0], &h
[1], &sa
, 0);
1848 DuplicateHandle(cp
, h
[n
], cp
, &t
, 0, FALSE
, DUPLICATE_SAME_ACCESS
);
1854 static int sysdep_popen(mpdm_t v
, char *prg
, int rw
)
1855 /* win32-style pipe */
1859 PROCESS_INFORMATION pi
;
1862 struct mpdm_file
*fs
= (struct mpdm_file
*) v
->data
;
1865 pr
[0] = pr
[1] = pw
[0] = pw
[1] = NULL
;
1872 /* spawn new process */
1873 memset(&pi
, '\0', sizeof(pi
));
1874 memset(&si
, '\0', sizeof(si
));
1876 si
.cb
= sizeof(STARTUPINFO
);
1877 si
.hStdError
= pr
[1];
1878 si
.hStdOutput
= pr
[1];
1879 si
.hStdInput
= pw
[0];
1880 si
.dwFlags
|= STARTF_USESTDHANDLES
;
1882 ret
= CreateProcess(NULL
, prg
, NULL
, NULL
, TRUE
, 0, NULL
, NULL
, &si
, &pi
);
1891 fs
->process
= pi
.hProcess
;
1897 static int sysdep_pclose(const mpdm_t v
)
1899 struct mpdm_file
*fs
= (struct mpdm_file
*) v
->data
;
1902 if (fs
->hin
!= NULL
)
1903 CloseHandle(fs
->hin
);
1905 if (fs
->hout
!= NULL
)
1906 CloseHandle(fs
->hout
);
1908 /* waits until the process terminates */
1909 WaitForSingleObject(fs
->process
, 1000);
1910 GetExitCodeProcess(fs
->process
, &out
);
1916 #else /* CONFOPT_WIN32 */
1918 static int sysdep_popen(mpdm_t v
, char *prg
, int rw
)
1919 /* unix-style pipe open */
1922 struct mpdm_file
*fs
= (struct mpdm_file
*) v
->data
;
1925 pr
[0] = pr
[1] = pw
[0] = pw
[1] = -1;
1945 /* redirect stderr to stdout */
1949 /* run the program */
1950 execlp("/bin/sh", "/bin/sh", "-c", prg
, NULL
);
1951 execlp(prg
, prg
, NULL
);
1953 /* still here? exec failed; close pipes and exit */
1959 /* create the pipes as non-buffered streams */
1961 fs
->in
= fdopen(pr
[0], "r");
1962 setvbuf(fs
->in
, NULL
, _IONBF
, 0);
1967 fs
->out
= fdopen(pw
[1], "w");
1968 setvbuf(fs
->out
, NULL
, _IONBF
, 0);
1976 static int sysdep_pclose(const mpdm_t v
)
1977 /* unix-style pipe close */
1980 struct mpdm_file
*fs
= (struct mpdm_file
*) v
->data
;
1985 if (fs
->out
!= fs
->in
&& fs
->out
!= NULL
)
1994 #endif /* CONFOPT_WIN32 */
1998 * mpdm_popen - Opens a pipe.
1999 * @prg: the program to pipe
2000 * @mode: an fopen-like mode string
2002 * Opens a pipe to a program. If @prg can be open in the specified @mode, an
2003 * mpdm_t value will be returned containing the file descriptor, or NULL
2007 mpdm_t
mpdm_popen(const mpdm_t prg
, const mpdm_t mode
)
2016 if (prg
!= NULL
&& mode
!= NULL
) {
2018 v
= new_mpdm_file();
2020 /* convert to mbs,s */
2021 pr
= mpdm_ref(MPDM_2MBS(prg
->data
));
2022 md
= mpdm_ref(MPDM_2MBS(mode
->data
));
2025 m
= (char *) md
->data
;
2033 rw
= 0x03; /* r+ or w+ */
2035 if (!sysdep_popen(v
, (char *) pr
->data
, rw
)) {
2036 destroy_mpdm_file(v
);
2037 mpdm_unref(mpdm_ref(v
));
2055 * mpdm_popen2 - Opens a pipe and returns 2 descriptors.
2056 * @prg: the program to pipe
2058 * Opens a read-write pipe and returns an array of two descriptors,
2059 * one for reading and one for writing. If @prg could not be piped to,
2063 mpdm_t
mpdm_popen2(const mpdm_t prg
)
2068 if ((i
= mpdm_popen(prg
, MPDM_AS(L
"r+"))) != NULL
) {
2069 struct mpdm_file
*ifs
;
2070 struct mpdm_file
*ofs
;
2072 o
= MPDM_C(i
->flags
, (void *)i
->data
, i
->size
);
2074 ifs
= (struct mpdm_file
*)i
->data
;
2075 ofs
= (struct mpdm_file
*)o
->data
;
2080 #ifdef CONFOPT_WIN32
2081 ofs
->hin
= ifs
->hout
;
2085 p
= mpdm_ref(MPDM_A(2));
2096 * mpdm_pclose - Closes a pipe.
2097 * @fd: the value containing the file descriptor
2102 mpdm_t
mpdm_pclose(mpdm_t fd
)
2108 if ((fd
->flags
& MPDM_FILE
) && fd
->data
!= NULL
) {
2109 r
= MPDM_I(sysdep_pclose(fd
));
2110 destroy_mpdm_file(fd
);
2120 * mpdm_home_dir - Returns the home user directory.
2122 * Returns a system-dependent directory where the user can write
2123 * documents and create subdirectories.
2126 mpdm_t
mpdm_home_dir(void)
2134 #ifdef CONFOPT_WIN32
2138 /* get the 'My Documents' folder */
2139 SHGetSpecialFolderLocation(NULL
, CSIDL_PERSONAL
, &pidl
);
2140 SHGetPathFromIDList(pidl
, tmp
);
2145 #ifdef CONFOPT_PWD_H
2149 /* get home dir from /etc/passwd entry */
2150 if (tmp
[0] == '\0' && (p
= getpwuid(getpid())) != NULL
) {
2151 strcpy(tmp
, p
->pw_dir
);
2157 /* still none? try the ENV variable $HOME */
2158 if (tmp
[0] == '\0' && (ptr
= getenv("HOME")) != NULL
) {
2171 * mpdm_app_dir - Returns the applications directory.
2173 * Returns a system-dependent directory where the applications store
2174 * their private data, as components or resources.
2177 mpdm_t
mpdm_app_dir(void)
2181 #ifdef CONFOPT_WIN32
2187 /* get the 'Program Files' folder (can fail) */
2189 if (SHGetSpecialFolderLocation(NULL
, CSIDL_PROGRAM_FILES
, &pidl
) ==
2191 SHGetPathFromIDList(pidl
, tmp
);
2193 /* if it's still empty, get from the registry */
2194 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
,
2195 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
2196 0, KEY_QUERY_VALUE
, &hkey
) == ERROR_SUCCESS
) {
2197 int n
= sizeof(tmp
);
2199 if (RegQueryValueEx(hkey
, "ProgramFilesDir",
2201 (LPDWORD
) & n
) != ERROR_SUCCESS
)
2205 if (tmp
[0] != '\0') {
2211 /* still none? get the configured directory */
2213 r
= MPDM_MBS(CONFOPT_PREFIX
"/share/");