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 */
91 #endif /* CONFOPT_WIN32 */
101 static void store_syserr(void)
102 /* stores the system error inside the global ERRNO */
104 mpdm_hset_s(mpdm_root(), L
"ERRNO", MPDM_MBS(strerror(errno
)));
108 static int get_char(struct mpdm_file
*f
)
109 /* reads a character from a file structure */
115 if (f
->hin
!= NULL
) {
119 if (ReadFile(f
->hin
, &tmp
, 1, &n
, NULL
) && n
> 0)
123 #endif /* CONFOPT_WIN32 */
126 /* read (converting to positive if needed) */
127 if ((c
= fgetc(f
->in
)) < 0 && !feof(f
->in
))
135 static int put_buf(const char *ptr
, int s
, struct mpdm_file
*f
)
136 /* writes s bytes in the buffer in ptr to f */
140 if (f
->hout
!= NULL
) {
143 if (WriteFile(f
->hout
, ptr
, s
, &n
, NULL
) && n
> 0)
147 #endif /* CONFOPT_WIN32 */
150 s
= fwrite(ptr
, s
, 1, f
->out
);
156 static int put_char(int c
, struct mpdm_file
*f
)
157 /* writes a character in a file structure */
161 if (put_buf(&tmp
, 1, f
) != 1)
168 static wchar_t *read_mbs(struct mpdm_file
*f
, int *s
)
169 /* reads a multibyte string from a mpdm_file into a dynamic string */
176 while ((c
= get_char(f
)) != EOF
) {
182 if (i
== sizeof(tmp
) - 1) {
183 /* out of space; start allocating */
185 mpdm_poke(auxptr
, &n
, tmp
, i
, sizeof(char))) == NULL
)
192 /* is there something to return? */
198 /* auxiliary space used; concat all */
200 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(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(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(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(struct mpdm_file
*f
, int *s
)
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(struct mpdm_file
*f
, const wchar_t * str
)
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)
426 fseek(f
->in
, 0, SEEK_SET
);
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 /* 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(struct mpdm_file
*f
, int *s
)
454 /* 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(struct mpdm_file
*f
, const wchar_t * str
)
484 /* 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(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(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(struct mpdm_file
*f
, int *s
)
563 return read_utf16ae(f
, s
, 1);
567 static int write_utf16le(struct mpdm_file
*f
, const wchar_t * str
)
569 return write_utf16ae(f
, str
, 1);
573 static wchar_t *read_utf16be(struct mpdm_file
*f
, int *s
)
575 return read_utf16ae(f
, s
, 0);
579 static int write_utf16be(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
)
588 wchar_t *enc
= L
"utf-16le";
590 /* assume little-endian */
591 f
->f_read
= read_utf16le
;
597 if (c1
== 0xfe && c2
== 0xff) {
599 f
->f_read
= read_utf16be
;
602 if (c1
!= 0xff || c2
!= 0xfe) {
603 /* no BOM; rewind and hope */
604 fseek(f
->in
, 0, SEEK_SET
);
607 mpdm_hset_s(mpdm_root(), L
"DETECTED_ENCODING", MPDM_LS(enc
));
609 return f
->f_read(f
, s
);
613 static int write_utf16le_bom(struct mpdm_file
*f
, const wchar_t * str
)
615 /* store the LE signature */
619 /* we're 16le from now on */
620 f
->f_write
= write_utf16le
;
622 return f
->f_write(f
, str
);
626 static int write_utf16be_bom(struct mpdm_file
*f
, const wchar_t * str
)
628 /* store the BE signature */
632 /* we're 16be from now on */
633 f
->f_write
= write_utf16be
;
635 return f
->f_write(f
, str
);
639 static wchar_t *read_utf32ae(struct mpdm_file
*f
, int *s
, int le
)
640 /* utf32 reader, ANY ending */
651 if ((c1
= get_char(f
)) == EOF
)
654 if ((c2
= get_char(f
)) == EOF
)
657 if ((c3
= get_char(f
)) == EOF
)
660 if ((c4
= get_char(f
)) == EOF
)
664 wc
= c1
| (c2
<< 8) | (c3
<< 16) | (c4
<< 24);
666 wc
= c4
| (c3
<< 8) | (c2
<< 16) | (c1
<< 24);
669 if ((ptr
= mpdm_poke(ptr
, s
, &wc
, 1, sizeof(wchar_t))) == NULL
)
672 /* if it's an end of line, finish */
678 ptr
= mpdm_poke(ptr
, s
, L
"", 1, sizeof(wchar_t));
686 static int write_utf32ae(struct mpdm_file
*f
, const wchar_t * str
, int le
)
687 /* utf32 writer, ANY ending */
692 /* convert char by char */
693 for (; (wc
= *str
) != L
'\0'; str
++) {
696 put_char((wc
& 0x000000ff), f
);
697 put_char((wc
& 0x0000ff00) >> 8, f
);
698 put_char((wc
& 0x00ff0000) >> 16, f
);
699 put_char((wc
& 0xff000000) >> 24, f
);
702 put_char((wc
& 0xff000000) >> 24, f
);
703 put_char((wc
& 0x00ff0000) >> 16, f
);
704 put_char((wc
& 0x0000ff00) >> 8, f
);
705 put_char((wc
& 0x000000ff), f
);
713 static wchar_t *read_utf32le(struct mpdm_file
*f
, int *s
)
715 return read_utf32ae(f
, s
, 1);
719 static int write_utf32le(struct mpdm_file
*f
, const wchar_t * str
)
721 return write_utf32ae(f
, str
, 1);
725 static wchar_t *read_utf32be(struct mpdm_file
*f
, int *s
)
727 return read_utf32ae(f
, s
, 0);
731 static int write_utf32be(struct mpdm_file
*f
, const wchar_t * str
)
733 return write_utf32ae(f
, str
, 0);
737 static wchar_t *read_utf32(struct mpdm_file
*f
, int *s
)
740 wchar_t *enc
= L
"utf-32le";
742 f
->f_read
= read_utf32le
;
750 if (c1
== 0 && c2
== 0 && c3
== 0xfe && c4
== 0xff) {
752 f
->f_read
= read_utf32be
;
754 if (c1
!= 0xff || c2
!= 0xfe || c3
!= 0 || c4
!= 0) {
755 /* no BOM; assume le and hope */
756 fseek(f
->in
, 0, SEEK_SET
);
759 mpdm_hset_s(mpdm_root(), L
"DETECTED_ENCODING", MPDM_LS(enc
));
761 return f
->f_read(f
, s
);
765 static int write_utf32le_bom(struct mpdm_file
*f
, const wchar_t * str
)
767 /* store the LE signature */
773 /* we're 32le from now on */
774 f
->f_write
= write_utf32le
;
776 return f
->f_write(f
, str
);
780 static int write_utf32be_bom(struct mpdm_file
*f
, const wchar_t * str
)
782 /* store the BE signature */
788 /* we're 32be from now on */
789 f
->f_write
= write_utf32be
;
791 return f
->f_write(f
, str
);
795 static wchar_t *read_auto(struct mpdm_file
*f
, int *s
)
796 /* autodetects different encodings based on the BOM */
800 /* by default, multibyte reading */
801 f
->f_read
= read_mbs
;
803 /* ensure seeking is possible */
804 if (f
->in
!= NULL
&& fseek(f
->in
, 0, SEEK_CUR
) != -1) {
810 /* can be utf32le or utf16le */
811 if (get_char(f
) == 0xfe) {
812 /* if next 2 chars are 0x00, it's utf32; otherwise utf16 */
813 if (get_char(f
) == 0x00 && get_char(f
) == 0x00) {
815 f
->f_read
= read_utf32le
;
819 /* rewind to 3rd character */
820 fseek(f
->in
, 2, SEEK_SET
);
823 f
->f_read
= read_utf16le
;
831 if (get_char(f
) == 0x00 && get_char(f
) == 0xfe
832 && get_char(f
) == 0xff) {
834 f
->f_read
= read_utf32be
;
841 if (get_char(f
) == 0xff) {
843 f
->f_read
= read_utf16be
;
849 /* can be utf8 with BOM */
850 if (get_char(f
) == 0xbb && get_char(f
) == 0xbf) {
852 f
->f_read
= read_utf8
;
857 /* try if a first bunch of chars are valid UTF-8 */
862 while (--n
&& (c
= get_char(f
)) != EOF
) {
863 if ((c
& 0xc0) == 0x80) {
864 if ((p
& 0xc0) == 0xc0)
867 if ((p
& 0x80) == 0x00) {
873 if ((p
& 0xc0) == 0xc0) {
882 /* invalid utf-8; fall back to 8bit */
884 f
->f_read
= read_iso8859_1
;
888 /* utf-8 sequences found */
890 f
->f_read
= read_utf8
;
893 /* 7 bit ASCII: do nothing */
896 /* none of the above; restart */
897 fseek(f
->in
, 0, SEEK_SET
);
901 mpdm_hset_s(mpdm_root(), L
"DETECTED_ENCODING", MPDM_LS(enc
));
903 return f
->f_read(f
, s
);
907 static mpdm_t
new_mpdm_file(void)
908 /* creates a new file value */
911 struct mpdm_file
*fs
;
914 if ((fs
= malloc(sizeof(struct mpdm_file
))) == NULL
)
917 memset(fs
, '\0', sizeof(struct mpdm_file
));
919 /* default I/O functions */
920 fs
->f_read
= read_auto
;
921 fs
->f_write
= write_wcs
;
924 /* no iconv encodings by default */
925 fs
->ic_enc
= fs
->ic_dec
= (iconv_t
) - 1;
929 mpdm_new(MPDM_FILE
| MPDM_FREE
, fs
,
930 sizeof(struct mpdm_file
))) == NULL
) {
935 e
= mpdm_hget_s(mpdm_root(), L
"ENCODING");
937 if (mpdm_size(e
) == 0)
938 e
= mpdm_hget_s(mpdm_root(), L
"TEMP_ENCODING");
942 wchar_t *enc
= mpdm_string(e
);
944 if (wcscmp(enc
, L
"utf-8") == 0) {
945 fs
->f_read
= read_utf8_bom
;
946 fs
->f_write
= write_utf8
;
949 if (wcscmp(enc
, L
"utf-8bom") == 0) {
950 fs
->f_read
= read_utf8_bom
;
951 fs
->f_write
= write_utf8_bom
;
954 if (wcscmp(enc
, L
"iso8859-1") == 0 ||
955 wcscmp(enc
, L
"8bit") == 0) {
956 fs
->f_read
= read_iso8859_1
;
957 fs
->f_write
= write_iso8859_1
;
960 if (wcscmp(enc
, L
"utf-16le") == 0) {
961 fs
->f_read
= read_utf16le
;
962 fs
->f_write
= write_utf16le_bom
;
965 if (wcscmp(enc
, L
"utf-16be") == 0) {
966 fs
->f_read
= read_utf16be
;
967 fs
->f_write
= write_utf16be_bom
;
970 if (wcscmp(enc
, L
"utf-16") == 0) {
971 fs
->f_read
= read_utf16
;
972 fs
->f_write
= write_utf16le_bom
;
975 if (wcscmp(enc
, L
"utf-32le") == 0) {
976 fs
->f_read
= read_utf32le
;
977 fs
->f_write
= write_utf32le_bom
;
980 if (wcscmp(enc
, L
"utf-32be") == 0) {
981 fs
->f_read
= read_utf32be
;
982 fs
->f_write
= write_utf32be_bom
;
985 if (wcscmp(enc
, L
"utf-32") == 0) {
986 fs
->f_read
= read_utf32
;
987 fs
->f_write
= write_utf32le_bom
;
991 mpdm_t cs
= MPDM_2MBS(e
->data
);
994 iconv_open((char *) cs
->data
, "WCHAR_T")) != (iconv_t
) - 1
996 iconv_open("WCHAR_T",
997 (char *) cs
->data
)) != (iconv_t
) - 1) {
999 fs
->f_read
= read_iconv
;
1000 fs
->f_write
= write_iconv
;
1002 #endif /* CONFOPT_ICONV */
1005 mpdm_hset_s(mpdm_root(), L
"TEMP_ENCODING", NULL
);
1012 static void destroy_mpdm_file(mpdm_t v
)
1013 /* destroys and file value */
1015 struct mpdm_file
*fs
= (struct mpdm_file
*) v
->data
;
1018 #ifdef CONFOPT_ICONV
1019 if (fs
->ic_enc
!= (iconv_t
) - 1) {
1020 iconv_close(fs
->ic_enc
);
1021 fs
->ic_enc
= (iconv_t
) - 1;
1024 if (fs
->ic_dec
!= (iconv_t
) - 1) {
1025 iconv_close(fs
->ic_dec
);
1026 fs
->ic_dec
= (iconv_t
) - 1;
1038 wchar_t *mpdm_read_mbs(FILE * f
, int *s
)
1039 /* reads a multibyte string from a stream into a dynamic string */
1041 struct mpdm_file fs
;
1043 /* reset the structure */
1044 memset(&fs
, '\0', sizeof(fs
));
1047 return read_mbs(&fs
, s
);
1051 int mpdm_write_wcs(FILE * f
, const wchar_t * str
)
1052 /* writes a wide string to a stream */
1054 struct mpdm_file fs
;
1056 /* reset the structure */
1057 memset(&fs
, '\0', sizeof(fs
));
1060 return write_wcs(&fs
, str
);
1064 mpdm_t
mpdm_new_f(FILE * f
)
1065 /* creates a new file value from a FILE * */
1072 if ((v
= new_mpdm_file()) != NULL
) {
1073 struct mpdm_file
*fs
= (struct mpdm_file
*) v
->data
;
1074 fs
->in
= fs
->out
= f
;
1082 * mpdm_open - Opens a file.
1083 * @filename: the file name
1084 * @mode: an fopen-like mode string
1086 * Opens a file. If @filename can be open in the specified @mode, an
1087 * mpdm_t value will be returned containing the file descriptor, or NULL
1090 * If the file is open for reading, some charset detection methods are
1091 * used. If any of them is successful, its name is stored in the
1092 * DETECTED_ENCODING element of the mpdm_root() hash. This value is
1093 * suitable to be copied over ENCODING or TEMP_ENCODING.
1095 * If the file is open for writing, the encoding to be used is read from
1096 * the ENCODING element of mpdm_root() and, if not set, from the
1097 * TEMP_ENCODING one. The latter will always be deleted afterwards.
1100 mpdm_t
mpdm_open(const mpdm_t filename
, const mpdm_t mode
)
1109 if (filename
!= NULL
&& mode
!= NULL
) {
1111 /* convert to mbs,s */
1112 fn
= mpdm_ref(MPDM_2MBS(filename
->data
));
1113 m
= mpdm_ref(MPDM_2MBS(mode
->data
));
1115 if ((f
= fopen((char *) fn
->data
, (char *) m
->data
)) == NULL
)
1118 #if defined(CONFOPT_SYS_STAT_H) && defined(S_ISDIR) && defined(EISDIR)
1121 /* test if the open file is a directory */
1122 if (fstat(fileno(f
), &s
) != -1 && S_ISDIR(s
.st_mode
)) {
1123 /* it's a directory; fail */
1137 mpdm_unref(filename
);
1144 * mpdm_close - Closes a file descriptor.
1145 * @fd: the value containing the file descriptor
1147 * Closes the file descriptor.
1150 mpdm_t
mpdm_close(mpdm_t fd
)
1152 struct mpdm_file
*fs
= (struct mpdm_file
*) fd
->data
;
1156 if ((fd
->flags
& MPDM_FILE
) && fs
!= NULL
) {
1160 if (fs
->out
!= fs
->in
&& fs
->out
!= NULL
)
1163 destroy_mpdm_file(fd
);
1166 fd
= mpdm_unref(fd
);
1173 * mpdm_read - Reads a line from a file descriptor.
1174 * @fd: the value containing the file descriptor
1176 * Reads a line from @fd. Returns the line, or NULL on EOF.
1178 * [Character Set Conversion]
1180 mpdm_t
mpdm_read(const mpdm_t fd
)
1185 struct mpdm_file
*fs
= (struct mpdm_file
*) fd
->data
;
1190 ptr
= fs
->f_read(fs
, &s
);
1193 v
= MPDM_ENS(ptr
, s
);
1199 mpdm_t
mpdm_getchar(const mpdm_t fd
)
1204 struct mpdm_file
*fs
= (struct mpdm_file
*) fd
->data
;
1206 if (fs
!= NULL
&& (c
= get_char(fs
)) != EOF
) {
1207 /* get the char as-is */
1208 tmp
[0] = (wchar_t) c
;
1218 int mpdm_putchar(const mpdm_t fd
, const mpdm_t c
)
1220 struct mpdm_file
*fs
= (struct mpdm_file
*) fd
->data
;
1221 const wchar_t *ptr
= mpdm_string(c
);
1226 if (fs
== NULL
|| put_char(*ptr
, fs
) == -1)
1236 * mpdm_write - Writes a value into a file.
1237 * @fd: the file descriptor.
1238 * @v: the value to be written.
1240 * Writes the @v string value into @fd, using the current encoding.
1242 * [Character Set Conversion]
1244 int mpdm_write(const mpdm_t fd
, const mpdm_t v
)
1246 struct mpdm_file
*fs
= (struct mpdm_file
*) fd
->data
;
1252 ret
= fs
->f_write(fs
, mpdm_string(v
));
1260 int mpdm_fseek(const mpdm_t fd
, long offset
, int whence
)
1262 struct mpdm_file
*fs
= (struct mpdm_file
*) fd
->data
;
1264 return fseek(fs
->in
, offset
, whence
);
1268 long mpdm_ftell(const mpdm_t fd
)
1270 struct mpdm_file
*fs
= (struct mpdm_file
*) fd
->data
;
1272 return ftell(fs
->in
);
1276 FILE *mpdm_get_filehandle(const mpdm_t fd
)
1280 if (fd
->flags
& MPDM_FILE
&& fd
->data
!= NULL
) {
1281 struct mpdm_file
*fs
= (struct mpdm_file
*) fd
->data
;
1290 mpdm_t mpdm_bread(mpdm_t fd, int size)
1295 int mpdm_bwrite(mpdm_tfd, mpdm_t v, int size)
1301 static mpdm_t
embedded_encodings(void)
1307 L
"iso8859-1", L
"iso8859-1",
1308 L
"iso-8859-1", NULL
,
1312 L
"utf-16le", L
"utf-16le",
1315 L
"utf-16be", L
"utf-16be",
1318 L
"utf-16", L
"utf-16",
1322 L
"utf-32le", L
"utf-32le",
1325 L
"utf-32be", L
"utf-32be",
1328 L
"utf-32", L
"utf-32",
1332 L
"utf-8bom", L
"utf-8bom",
1337 if ((e
= mpdm_hget_s(mpdm_root(), L
"EMBEDDED_ENCODINGS")) == NULL
) {
1341 e
= mpdm_ref(MPDM_H(0));
1343 for (n
= 0; e2e
[n
] != NULL
; n
+= 2) {
1344 mpdm_t v
= MPDM_S(e2e
[n
]);
1346 if (e2e
[n
+ 1] != NULL
)
1347 p
= MPDM_S(e2e
[n
+ 1]);
1350 mpdm_hset(e
, mpdm_ulc(v
, 1), p
);
1353 mpdm_hset_s(mpdm_root(), L
"EMBEDDED_ENCODINGS", e
);
1363 * mpdm_encoding - Sets the current charset encoding for files.
1364 * @charset: the charset name.
1366 * Sets the current charset encoding for files. Future opened
1367 * files will be assumed to be encoded with @charset, which can
1368 * be any of the supported charset names (utf-8, iso-8859-1, etc.),
1369 * and converted on each read / write. If charset is NULL, it
1370 * is reverted to default charset conversion (i.e. the one defined
1373 * This function stores the @charset value into the ENCODING item
1374 * of the mpdm_root() hash.
1376 * Returns a negative number if @charset is unsupported, or zero
1377 * if no errors were found.
1379 * [Character Set Conversion]
1381 int mpdm_encoding(mpdm_t charset
)
1384 mpdm_t e
= embedded_encodings();
1389 /* NULL encoding? done */
1390 if (mpdm_size(charset
) == 0) {
1391 mpdm_hset_s(mpdm_root(), L
"ENCODING", NULL
);
1395 #ifdef CONFOPT_ICONV
1398 mpdm_t cs
= mpdm_ref(MPDM_2MBS(charset
->data
));
1400 /* tries to create an iconv encoder and decoder for this charset */
1403 iconv_open("WCHAR_T", (char *) cs
->data
)) == (iconv_t
) - 1)
1409 iconv_open((char *) cs
->data
,
1410 "WCHAR_T")) == (iconv_t
) - 1)
1415 /* got a valid encoding */
1423 #endif /* CONFOPT_ICONV */
1425 if (ret
!= 0 && (v
= mpdm_hget(e
, charset
)) != NULL
)
1429 mpdm_hset_s(mpdm_root(), L
"ENCODING", v
);
1431 mpdm_unref(charset
);
1438 * mpdm_unlink - Deletes a file.
1439 * @filename: file name to be deleted
1444 int mpdm_unlink(const mpdm_t filename
)
1451 /* convert to mbs */
1452 fn
= mpdm_ref(MPDM_2MBS(filename
->data
));
1454 if ((ret
= unlink((char *) fn
->data
)) == -1)
1458 mpdm_unref(filename
);
1465 * mpdm_stat - Gives status from a file.
1466 * @filename: file name to get the status from
1468 * Returns a 14 element array of the status (permissions, onwer, etc.)
1469 * from the desired @filename, or NULL if the file cannot be accessed.
1472 * The values are: 0, device number of filesystem; 1, inode number;
1473 * 2, file mode; 3, number of hard links to the file; 4, uid; 5, gid;
1474 * 6, device identifier; 7, total size of file in bytes; 8, atime;
1475 * 9, mtime; 10, ctime; 11, preferred block size for system I/O;
1476 * 12, number of blocks allocated and 13, canonicalized file name.
1477 * Not all elements have necesarily meaningful values, as most are
1481 mpdm_t
mpdm_stat(const mpdm_t filename
)
1487 #ifdef CONFOPT_SYS_STAT_H
1491 fn
= mpdm_ref(MPDM_2MBS(filename
->data
));
1493 if (stat((char *) fn
->data
, &s
) != -1) {
1498 mpdm_aset(r
, MPDM_I(s
.st_dev
), 0);
1499 mpdm_aset(r
, MPDM_I(s
.st_ino
), 1);
1500 mpdm_aset(r
, MPDM_I(s
.st_mode
), 2);
1501 mpdm_aset(r
, MPDM_I(s
.st_nlink
), 3);
1502 mpdm_aset(r
, MPDM_I(s
.st_uid
), 4);
1503 mpdm_aset(r
, MPDM_I(s
.st_gid
), 5);
1504 mpdm_aset(r
, MPDM_I(s
.st_rdev
), 6);
1505 mpdm_aset(r
, MPDM_I(s
.st_size
), 7);
1506 mpdm_aset(r
, MPDM_I(s
.st_atime
), 8);
1507 mpdm_aset(r
, MPDM_I(s
.st_mtime
), 9);
1508 mpdm_aset(r
, MPDM_I(s
.st_ctime
), 10);
1509 mpdm_aset(r
, MPDM_I(0), 11); /* s.st_blksize */
1510 mpdm_aset(r
, MPDM_I(0), 12); /* s.st_blocks */
1512 #ifdef CONFOPT_CANONICALIZE_FILE_NAME
1517 if ((ptr
= canonicalize_file_name((char *) fn
->data
)) != NULL
) {
1518 mpdm_aset(r
, MPDM_MBS(ptr
), 13);
1524 #ifdef CONFOPT_REALPATH
1528 if (realpath((char *) fn
->data
, tmp
) != NULL
)
1529 mpdm_aset(r
, MPDM_MBS(tmp
), 13);
1533 #ifdef CONFOPT_FULLPATH
1535 char tmp
[_MAX_PATH
+ 1];
1537 if (_fullpath(tmp
, (char *) fn
->data
, _MAX_PATH
) != NULL
)
1538 mpdm_aset(r
, MPDM_MBS(tmp
), 13);
1549 #endif /* CONFOPT_SYS_STAT_H */
1551 mpdm_unref(filename
);
1558 * mpdm_chmod - Changes a file's permissions.
1559 * @filename: the file name
1560 * @perms: permissions (element 2 from mpdm_stat())
1562 * Changes the permissions for a file.
1565 int mpdm_chmod(const mpdm_t filename
, mpdm_t perms
)
1572 mpdm_t fn
= mpdm_ref(MPDM_2MBS(filename
->data
));
1574 if ((r
= chmod((char *) fn
->data
, mpdm_ival(perms
))) == -1)
1579 mpdm_unref(filename
);
1586 * mpdm_chdir - Changes the working directory
1587 * @dir: the new path
1589 * Changes the working directory
1592 int mpdm_chdir(const mpdm_t dir
)
1597 mpdm_t fn
= mpdm_ref(MPDM_2MBS(dir
->data
));
1599 if ((r
= chdir((char *) fn
->data
)) == -1)
1610 * mpdm_chown - Changes a file's owner.
1611 * @filename: the file name
1612 * @uid: user id (element 4 from mpdm_stat())
1613 * @gid: group id (element 5 from mpdm_stat())
1615 * Changes the owner and group id's for a file.
1618 int mpdm_chown(const mpdm_t filename
, mpdm_t uid
, mpdm_t gid
)
1626 #ifdef CONFOPT_CHOWN
1628 mpdm_t fn
= mpdm_ref(MPDM_2MBS(filename
->data
));
1631 chown((char *) fn
->data
, mpdm_ival(uid
), mpdm_ival(gid
))) == -1)
1636 #endif /* CONFOPT_CHOWN */
1640 mpdm_unref(filename
);
1647 * mpdm_glob - Executes a file globbing.
1648 * @spec: Globbing spec
1649 * @base: Optional base directory
1651 * Executes a file globbing. @spec is system-dependent, but usually
1652 * the * and ? metacharacters work everywhere. @base can contain a
1653 * directory; if that's the case, the output strings will include it.
1654 * In any case, each returned value will be suitable for a call to
1657 * Returns an array of files that match the globbing (can be an empty
1658 * array if no file matches), or NULL if globbing is unsupported.
1661 mpdm_t
mpdm_glob(const mpdm_t spec
, const mpdm_t base
)
1670 #ifdef CONFOPT_WIN32
1680 if (mpdm_size(base
))
1681 sp
= mpdm_strcat_s(base
, L
"/");
1686 if (mpdm_size(spec
) == 0)
1687 sp
= mpdm_strcat_s(w
, L
"*.*");
1689 sp
= mpdm_strcat(w
, spec
);
1693 /* delete repeated directory delimiters */
1695 sp
= mpdm_sregex(w
, MPDM_LS(L
"@[\\/]+@g"), MPDM_LS(L
"/"), 0);
1699 sp
= MPDM_2MBS(w
->data
);
1703 d
= mpdm_ref(MPDM_A(0));
1704 f
= mpdm_ref(MPDM_A(0));
1708 FindFirstFile((char *) sp
->data
, &fd
)) != INVALID_HANDLE_VALUE
) {
1709 /* if spec includes a directory, store in s */
1710 if ((ptr
= strrchr((char *) sp
->data
, '/')) != NULL
) {
1712 s
= MPDM_MBS(sp
->data
);
1716 /* ignore . and .. */
1717 if (strcmp(fd
.cFileName
, ".") == 0
1718 || strcmp(fd
.cFileName
, "..") == 0)
1721 /* concat base directory and file names */
1722 w
= mpdm_strcat(s
, MPDM_MBS(fd
.cFileName
));
1724 /* if it's a directory, add a / */
1725 if (fd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) {
1726 mpdm_t t
= mpdm_ref(w
);
1727 w
= mpdm_strcat_s(t
, L
"/");
1735 while (FindNextFile(h
, &fd
));
1746 /* glob.h support */
1751 /* build full path */
1752 if (mpdm_size(base
))
1753 v
= mpdm_strcat_s(base
, L
"/");
1757 if (mpdm_size(spec
) == 0)
1758 v
= mpdm_strcat_s(w
, L
"*");
1760 v
= mpdm_strcat(w
, spec
);
1764 /* delete repeated directory delimiters */
1766 v
= mpdm_sregex(w
, MPDM_LS(L
"@/{2,}@g"), MPDM_LS(L
"/"), 0);
1770 v
= MPDM_2MBS(w
->data
);
1775 globbuf
.gl_offs
= 1;
1778 d
= mpdm_ref(MPDM_A(0));
1779 f
= mpdm_ref(MPDM_A(0));
1781 if (glob(ptr
, GLOB_MARK
, NULL
, &globbuf
) == 0) {
1784 for (n
= 0; globbuf
.gl_pathv
[n
] != NULL
; n
++) {
1785 char *ptr
= globbuf
.gl_pathv
[n
];
1786 mpdm_t t
= MPDM_MBS(ptr
);
1788 /* if last char is /, add to directories */
1789 if (ptr
[strlen(ptr
) - 1] == '/')
1800 /* no win32 nor glob.h; try workaround */
1813 /* transfer all data in d and f */
1814 for (n
= 0; n
< mpdm_size(d
); n
++)
1815 mpdm_push(v
, mpdm_aget(d
, n
));
1816 for (n
= 0; n
< mpdm_size(f
); n
++)
1817 mpdm_push(v
, mpdm_aget(f
, n
));
1832 #ifdef CONFOPT_WIN32
1834 static void win32_pipe(HANDLE
* h
, int n
)
1836 SECURITY_ATTRIBUTES sa
;
1839 memset(&sa
, '\0', sizeof(sa
));
1840 sa
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
1841 sa
.bInheritHandle
= TRUE
;
1842 sa
.lpSecurityDescriptor
= NULL
;
1844 cp
= GetCurrentProcess();
1846 CreatePipe(&h
[0], &h
[1], &sa
, 0);
1847 DuplicateHandle(cp
, h
[n
], cp
, &t
, 0, FALSE
, DUPLICATE_SAME_ACCESS
);
1853 static int sysdep_popen(mpdm_t v
, char *prg
, int rw
)
1854 /* win32-style pipe */
1858 PROCESS_INFORMATION pi
;
1861 struct mpdm_file
*fs
= (struct mpdm_file
*) v
->data
;
1864 pr
[0] = pr
[1] = pw
[0] = pw
[1] = NULL
;
1871 /* spawn new process */
1872 memset(&pi
, '\0', sizeof(pi
));
1873 memset(&si
, '\0', sizeof(si
));
1875 si
.cb
= sizeof(STARTUPINFO
);
1876 si
.hStdError
= pr
[1];
1877 si
.hStdOutput
= pr
[1];
1878 si
.hStdInput
= pw
[0];
1879 si
.dwFlags
|= STARTF_USESTDHANDLES
;
1882 CreateProcess(NULL
, prg
, NULL
, NULL
, TRUE
, 0, NULL
, NULL
, &si
,
1897 static int sysdep_pclose(const mpdm_t v
)
1899 struct mpdm_file
*fs
= (struct mpdm_file
*) v
->data
;
1901 if (fs
->hin
!= NULL
)
1902 CloseHandle(fs
->hin
);
1904 if (fs
->hout
!= NULL
)
1905 CloseHandle(fs
->hout
);
1907 /* how to know process exit code? */
1912 #else /* CONFOPT_WIN32 */
1914 static int sysdep_popen(mpdm_t v
, char *prg
, int rw
)
1915 /* unix-style pipe open */
1918 struct mpdm_file
*fs
= (struct mpdm_file
*) v
->data
;
1921 pr
[0] = pr
[1] = pw
[0] = pw
[1] = -1;
1941 /* redirect stderr to stdout */
1945 /* run the program */
1946 execlp("/bin/sh", "/bin/sh", "-c", prg
, NULL
);
1947 execlp(prg
, prg
, NULL
);
1949 /* still here? exec failed; close pipes and exit */
1955 /* create the pipes as non-buffered streams */
1957 fs
->in
= fdopen(pr
[0], "r");
1958 setvbuf(fs
->in
, NULL
, _IONBF
, 0);
1963 fs
->out
= fdopen(pw
[1], "w");
1964 setvbuf(fs
->out
, NULL
, _IONBF
, 0);
1972 static int sysdep_pclose(const mpdm_t v
)
1973 /* unix-style pipe close */
1976 struct mpdm_file
*fs
= (struct mpdm_file
*) v
->data
;
1981 if (fs
->out
!= fs
->in
&& fs
->out
!= NULL
)
1990 #endif /* CONFOPT_WIN32 */
1994 * mpdm_popen - Opens a pipe.
1995 * @prg: the program to pipe
1996 * @mode: an fopen-like mode string
1998 * Opens a pipe to a program. If @prg can be open in the specified @mode, an
1999 * mpdm_t value will be returned containing the file descriptor, or NULL
2003 mpdm_t
mpdm_popen(const mpdm_t prg
, const mpdm_t mode
)
2012 if (prg
!= NULL
&& mode
!= NULL
) {
2014 v
= new_mpdm_file();
2016 /* convert to mbs,s */
2017 pr
= mpdm_ref(MPDM_2MBS(prg
->data
));
2018 md
= mpdm_ref(MPDM_2MBS(mode
->data
));
2021 m
= (char *) md
->data
;
2029 rw
= 0x03; /* r+ or w+ */
2031 if (!sysdep_popen(v
, (char *) pr
->data
, rw
)) {
2032 destroy_mpdm_file(v
);
2033 mpdm_unref(mpdm_ref(v
));
2051 * mpdm_popen2 - Opens a pipe and returns 2 descriptors.
2052 * @prg: the program to pipe
2054 * Opens a read-write pipe and returns an array of two descriptors,
2055 * one for reading and one for writing. If @prg could not be piped to,
2059 mpdm_t
mpdm_popen2(const mpdm_t prg
)
2064 if ((i
= mpdm_popen(prg
, MPDM_LS(L
"r+"))) != NULL
) {
2065 struct mpdm_file
*ifs
;
2066 struct mpdm_file
*ofs
;
2068 o
= MPDM_C(i
->flags
, (void *)i
->data
, i
->size
);
2070 ifs
= (struct mpdm_file
*)i
->data
;
2071 ofs
= (struct mpdm_file
*)o
->data
;
2076 #ifdef CONFOPT_WIN32
2077 ofs
->hin
= ifs
->hout
;
2081 p
= mpdm_ref(MPDM_A(2));
2092 * mpdm_pclose - Closes a pipe.
2093 * @fd: the value containing the file descriptor
2098 mpdm_t
mpdm_pclose(mpdm_t fd
)
2104 if ((fd
->flags
& MPDM_FILE
) && fd
->data
!= NULL
) {
2105 r
= MPDM_I(sysdep_pclose(fd
));
2106 destroy_mpdm_file(fd
);
2109 fd
= mpdm_unref(fd
);
2116 * mpdm_home_dir - Returns the home user directory.
2118 * Returns a system-dependent directory where the user can write
2119 * documents and create subdirectories.
2122 mpdm_t
mpdm_home_dir(void)
2128 #ifdef CONFOPT_WIN32
2132 /* get the 'My Documents' folder */
2133 SHGetSpecialFolderLocation(NULL
, CSIDL_PERSONAL
, &pidl
);
2134 SHGetPathFromIDList(pidl
, tmp
);
2139 #ifdef CONFOPT_PWD_H
2143 /* get home dir from /etc/passwd entry */
2144 if (tmp
[0] == '\0' && (p
= getpwuid(getpid())) != NULL
) {
2145 strcpy(tmp
, p
->pw_dir
);
2151 /* still none? try the ENV variable $HOME */
2152 if (tmp
[0] == '\0' && (ptr
= getenv("HOME")) != NULL
) {
2165 * mpdm_app_dir - Returns the applications directory.
2167 * Returns a system-dependent directory where the applications store
2168 * their private data, as components or resources.
2171 mpdm_t
mpdm_app_dir(void)
2175 #ifdef CONFOPT_WIN32
2181 /* get the 'Program Files' folder (can fail) */
2183 if (SHGetSpecialFolderLocation(NULL
, CSIDL_PROGRAM_FILES
, &pidl
) ==
2185 SHGetPathFromIDList(pidl
, tmp
);
2187 /* if it's still empty, get from the registry */
2188 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
,
2189 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
2190 0, KEY_QUERY_VALUE
, &hkey
) == ERROR_SUCCESS
) {
2191 int n
= sizeof(tmp
);
2193 if (RegQueryValueEx(hkey
, "ProgramFilesDir",
2195 (LPDWORD
) & n
) != ERROR_SUCCESS
)
2199 if (tmp
[0] != '\0') {
2205 /* still none? get the configured directory */
2207 r
= MPDM_MBS(CONFOPT_PREFIX
"/share/");