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_iso8859_1(const struct mpdm_file
*f
, int *s
)
415 /* crappy, ad-hoc iso8859-1 reader */
423 while ((c
= get_char(f
)) != EOF
) {
427 if ((ptr
= mpdm_poke(ptr
, s
, &wc
, 1, sizeof(wchar_t))) == NULL
)
430 /* if it's an end of line, finish */
436 ptr
= mpdm_poke(ptr
, s
, L
"", 1, sizeof(wchar_t));
444 static int write_iso8859_1(const struct mpdm_file
*f
, const wchar_t * str
)
445 /* crappy, ad-hoc iso8859-1 writer */
450 /* convert char by char */
451 for (; (wc
= *str
) != L
'\0'; str
++)
452 put_char(wc
<= 0xff ? (int) wc
: '?', f
);
458 static wchar_t *read_utf16ae(const struct mpdm_file
*f
, int *s
, int le
)
459 /* utf16 reader, ANY ending */
470 if ((c1
= get_char(f
)) == EOF
)
473 if ((c2
= get_char(f
)) == EOF
)
482 if ((ptr
= mpdm_poke(ptr
, s
, &wc
, 1, sizeof(wchar_t))) == NULL
)
485 /* if it's an end of line, finish */
491 ptr
= mpdm_poke(ptr
, s
, L
"", 1, sizeof(wchar_t));
499 static int write_utf16ae(const struct mpdm_file
*f
, const wchar_t * str
, int le
)
500 /* utf16 writer, ANY ending */
505 /* convert char by char */
506 for (; (wc
= *str
) != L
'\0'; str
++) {
509 put_char(wc
& 0xff, f
);
510 put_char((wc
& 0xff00) >> 8, f
);
513 put_char((wc
& 0xff00) >> 8, f
);
514 put_char(wc
& 0xff, f
);
522 static wchar_t *read_utf16le(const struct mpdm_file
*f
, int *s
)
524 return read_utf16ae(f
, s
, 1);
528 static int write_utf16le(const struct mpdm_file
*f
, const wchar_t * str
)
530 return write_utf16ae(f
, str
, 1);
534 static wchar_t *read_utf16be(const struct mpdm_file
*f
, int *s
)
536 return read_utf16ae(f
, s
, 0);
540 static int write_utf16be(const struct mpdm_file
*f
, const wchar_t * str
)
542 return write_utf16ae(f
, str
, 0);
546 static wchar_t *read_utf16(struct mpdm_file
*f
, int *s
)
556 if (c1
== 0xff && c2
== 0xfe)
557 f
->f_read
= read_utf16le
;
559 if (c1
== 0xfe && c2
== 0xff)
560 f
->f_read
= read_utf16be
;
564 return f
->f_read(f
, s
);
568 static int write_utf16(struct mpdm_file
*f
, const wchar_t * str
)
570 /* store the LE signature */
574 /* we're 16le from now on */
575 f
->f_write
= write_utf16le
;
577 return f
->f_write(f
, str
);
581 static wchar_t *read_utf32ae(const struct mpdm_file
*f
, int *s
, int le
)
582 /* utf32 reader, ANY ending */
593 if ((c1
= get_char(f
)) == EOF
)
596 if ((c2
= get_char(f
)) == EOF
)
599 if ((c3
= get_char(f
)) == EOF
)
602 if ((c4
= get_char(f
)) == EOF
)
606 wc
= c1
| (c2
<< 8) | (c3
<< 16) | (c4
<< 24);
608 wc
= c4
| (c3
<< 8) | (c2
<< 16) | (c1
<< 24);
611 if ((ptr
= mpdm_poke(ptr
, s
, &wc
, 1, sizeof(wchar_t))) == NULL
)
614 /* if it's an end of line, finish */
620 ptr
= mpdm_poke(ptr
, s
, L
"", 1, sizeof(wchar_t));
628 static int write_utf32ae(const struct mpdm_file
*f
, const wchar_t * str
, int le
)
629 /* utf32 writer, ANY ending */
634 /* convert char by char */
635 for (; (wc
= *str
) != L
'\0'; str
++) {
638 put_char((wc
& 0x000000ff), f
);
639 put_char((wc
& 0x0000ff00) >> 8, f
);
640 put_char((wc
& 0x00ff0000) >> 16, f
);
641 put_char((wc
& 0xff000000) >> 24, f
);
644 put_char((wc
& 0xff000000) >> 24, f
);
645 put_char((wc
& 0x00ff0000) >> 16, f
);
646 put_char((wc
& 0x0000ff00) >> 8, f
);
647 put_char((wc
& 0x000000ff), f
);
655 static wchar_t *read_utf32le(const struct mpdm_file
*f
, int *s
)
657 return read_utf32ae(f
, s
, 1);
661 static int write_utf32le(const struct mpdm_file
*f
, const wchar_t * str
)
663 return write_utf32ae(f
, str
, 1);
667 static wchar_t *read_utf32be(const struct mpdm_file
*f
, int *s
)
669 return read_utf32ae(f
, s
, 0);
673 static int write_utf32be(const struct mpdm_file
*f
, const wchar_t * str
)
675 return write_utf32ae(f
, str
, 0);
679 static wchar_t *read_utf32(struct mpdm_file
*f
, int *s
)
691 if (c1
== 0xff && c2
== 0xfe && c3
== 0 && c4
== 0)
692 f
->f_read
= read_utf32le
;
694 if (c1
== 0 && c2
== 0 && c3
== 0xfe && c4
== 0xff)
695 f
->f_read
= read_utf32be
;
699 return f
->f_read(f
, s
);
703 static int write_utf32(struct mpdm_file
*f
, const wchar_t * str
)
705 /* store the LE signature */
711 /* we're 32le from now on */
712 f
->f_write
= write_utf32le
;
714 return f
->f_write(f
, str
);
718 static mpdm_t
new_mpdm_file(void)
719 /* creates a new file value */
722 struct mpdm_file
*fs
;
725 if ((fs
= malloc(sizeof(struct mpdm_file
))) == NULL
)
728 memset(fs
, '\0', sizeof(struct mpdm_file
));
730 /* default I/O functions */
731 fs
->f_read
= read_mbs
;
732 fs
->f_write
= write_wcs
;
735 /* no iconv encodings by default */
736 fs
->ic_enc
= fs
->ic_dec
= (iconv_t
) -1;
739 if ((v
= mpdm_new(MPDM_FILE
| MPDM_FREE
, fs
, sizeof(struct mpdm_file
))) == NULL
) {
744 if ((e
= mpdm_hget_s(mpdm_root(), L
"ENCODING")) != NULL
) {
746 wchar_t *enc
= mpdm_string(e
);
749 mpdm_t cs
= MPDM_2MBS(e
->data
);
751 if ((fs
->ic_enc
= iconv_open((char *) cs
->data
, "WCHAR_T")) != (iconv_t
) -1 &&
752 (fs
->ic_dec
= iconv_open("WCHAR_T", (char *) cs
->data
)) != (iconv_t
) -1) {
754 fs
->f_read
= read_iconv
;
755 fs
->f_write
= write_iconv
;
759 #endif /* CONFOPT_ICONV */
761 if (wcscmp(enc
, L
"utf-8") == 0) {
762 fs
->f_read
= read_utf8
;
763 fs
->f_write
= write_utf8
;
766 if (wcscmp(enc
, L
"iso8859-1") == 0) {
767 fs
->f_read
= read_iso8859_1
;
768 fs
->f_write
= write_iso8859_1
;
771 if (wcscmp(enc
, L
"utf-16le") == 0) {
772 fs
->f_read
= read_utf16le
;
773 fs
->f_write
= write_utf16le
;
776 if (wcscmp(enc
, L
"utf-16be") == 0) {
777 fs
->f_read
= read_utf16be
;
778 fs
->f_write
= write_utf16be
;
781 if (wcscmp(enc
, L
"utf-16") == 0) {
782 fs
->f_read
= read_utf16
;
783 fs
->f_write
= write_utf16
;
786 if (wcscmp(enc
, L
"utf-32le") == 0) {
787 fs
->f_read
= read_utf32le
;
788 fs
->f_write
= write_utf32le
;
791 if (wcscmp(enc
, L
"utf-32be") == 0) {
792 fs
->f_read
= read_utf32be
;
793 fs
->f_write
= write_utf32be
;
796 if (wcscmp(enc
, L
"utf-32") == 0) {
797 fs
->f_read
= read_utf32
;
798 fs
->f_write
= write_utf32
;
806 static void destroy_mpdm_file(mpdm_t v
)
807 /* destroys and file value */
809 struct mpdm_file
*fs
= (struct mpdm_file
*)v
->data
;
813 if (fs
->ic_enc
!= (iconv_t
) - 1) {
814 iconv_close(fs
->ic_enc
);
815 fs
->ic_enc
= (iconv_t
) - 1;
818 if (fs
->ic_dec
!= (iconv_t
) - 1) {
819 iconv_close(fs
->ic_dec
);
820 fs
->ic_dec
= (iconv_t
) - 1;
832 wchar_t *mpdm_read_mbs(FILE * f
, int *s
)
833 /* reads a multibyte string from a stream into a dynamic string */
837 /* reset the structure */
838 memset(&fs
, '\0', sizeof(fs
));
841 return read_mbs(&fs
, s
);
845 int mpdm_write_wcs(FILE * f
, const wchar_t * str
)
846 /* writes a wide string to a stream */
850 /* reset the structure */
851 memset(&fs
, '\0', sizeof(fs
));
854 return write_wcs(&fs
, str
);
858 mpdm_t
mpdm_new_f(FILE * f
)
859 /* creates a new file value from a FILE * */
866 if ((v
= new_mpdm_file()) != NULL
) {
867 struct mpdm_file
*fs
= (struct mpdm_file
*)v
->data
;
868 fs
->in
= fs
->out
= f
;
876 * mpdm_open - Opens a file.
877 * @filename: the file name
878 * @mode: an fopen-like mode string
880 * Opens a file. If @filename can be open in the specified @mode, an
881 * mpdm_t value will be returned containing the file descriptor, or NULL
885 mpdm_t
mpdm_open(const mpdm_t filename
, const mpdm_t mode
)
891 if (filename
== NULL
|| mode
== NULL
)
894 /* convert to mbs,s */
895 fn
= MPDM_2MBS(filename
->data
);
896 m
= MPDM_2MBS(mode
->data
);
898 if ((f
= fopen((char *) fn
->data
, (char *) m
->data
)) == NULL
)
901 #if defined(CONFOPT_SYS_STAT_H) && defined(S_ISDIR) && defined(EISDIR)
904 /* test if the open file is a directory */
905 if (fstat(fileno(f
), &s
) != -1 && S_ISDIR(s
.st_mode
)) {
906 /* it's a directory; fail */
920 * mpdm_close - Closes a file descriptor.
921 * @fd: the value containing the file descriptor
923 * Closes the file descriptor.
926 mpdm_t
mpdm_close(mpdm_t fd
)
928 struct mpdm_file
*fs
= (struct mpdm_file
*)fd
->data
;
930 if ((fd
->flags
& MPDM_FILE
) && fs
!= NULL
) {
934 if (fs
->out
!= fs
->in
&& fs
->out
!= NULL
)
937 destroy_mpdm_file(fd
);
945 * mpdm_read - Reads a line from a file descriptor.
946 * @fd: the value containing the file descriptor
948 * Reads a line from @fd. Returns the line, or NULL on EOF.
950 * [Character Set Conversion]
952 mpdm_t
mpdm_read(const mpdm_t fd
)
957 const struct mpdm_file
*fs
= fd
->data
;
962 ptr
= fs
->f_read(fs
, &s
);
965 v
= MPDM_ENS(ptr
, s
);
971 mpdm_t
mpdm_getchar(const mpdm_t fd
)
975 const struct mpdm_file
*fs
= fd
->data
;
977 if (fs
== NULL
|| (c
= get_char(fs
)) == EOF
)
980 /* get the char as-is */
981 tmp
[0] = (wchar_t) c
;
988 mpdm_t
mpdm_putchar(const mpdm_t fd
, const mpdm_t c
)
990 const struct mpdm_file
*fs
= fd
->data
;
991 const wchar_t *ptr
= mpdm_string(c
);
993 if (fs
== NULL
|| put_char(*ptr
, fs
) == -1)
1001 * mpdm_write - Writes a value into a file.
1002 * @fd: the file descriptor.
1003 * @v: the value to be written.
1005 * Writes the @v string value into @fd, using the current encoding.
1007 * [Character Set Conversion]
1009 int mpdm_write(const mpdm_t fd
, const mpdm_t v
)
1011 const struct mpdm_file
*fs
= fd
->data
;
1017 ret
= fs
->f_write(fs
, mpdm_string(v
));
1023 int mpdm_fseek(const mpdm_t fd
, long offset
, int whence
)
1025 const struct mpdm_file
*fs
= fd
->data
;
1027 return fseek(fs
->in
, offset
, whence
);
1031 long mpdm_ftell(const mpdm_t fd
)
1033 const struct mpdm_file
*fs
= fd
->data
;
1035 return ftell(fs
->in
);
1039 FILE * mpdm_get_filehandle(const mpdm_t fd
)
1043 if (fd
->flags
& MPDM_FILE
) {
1044 const struct mpdm_file
*fs
= fd
->data
;
1053 mpdm_t mpdm_bread(mpdm_t fd, int size)
1058 int mpdm_bwrite(mpdm_tfd, mpdm_t v, int size)
1064 static mpdm_t
embedded_encodings(void)
1070 L
"iso8859-1", L
"iso8859-1",
1071 L
"iso-8859-1", NULL
,
1074 L
"utf-16le", L
"utf-16le",
1077 L
"utf-16be", L
"utf-16be",
1080 L
"utf-16", L
"utf-16",
1084 L
"utf-32le", L
"utf-32le",
1087 L
"utf-32be", L
"utf-32be",
1090 L
"utf-32", L
"utf-32",
1097 if ((e
= mpdm_hget_s(mpdm_root(), L
"EMBEDDED_ENCODINGS")) == NULL
) {
1103 for (n
= 0; e2e
[n
] != NULL
; n
+= 2) {
1104 mpdm_t v
= MPDM_S(e2e
[n
]);
1106 if (e2e
[n
+ 1] != NULL
)
1109 mpdm_hset(e
, v
, MPDM_S(p
));
1110 mpdm_hset(e
, mpdm_ulc(v
, 1), MPDM_S(p
));
1113 mpdm_hset_s(mpdm_root(), L
"EMBEDDED_ENCODINGS", e
);
1121 * mpdm_encoding - Sets the current charset encoding for files.
1122 * @charset: the charset name.
1124 * Sets the current charset encoding for files. Future opened
1125 * files will be assumed to be encoded with @charset, which can
1126 * be any of the supported charset names (utf-8, iso-8859-1, etc.),
1127 * and converted on each read / write. If charset is NULL, it
1128 * is reverted to default charset conversion (i.e. the one defined
1130 * Returns a negative number if @charset is unsupported, or zero
1131 * if no errors were found.
1133 * [Character Set Conversion]
1135 int mpdm_encoding(mpdm_t charset
)
1138 mpdm_t e
= embedded_encodings();
1141 /* NULL encoding? done */
1142 if (charset
== NULL
) {
1143 mpdm_hset_s(mpdm_root(), L
"ENCODING", NULL
);
1147 #ifdef CONFOPT_ICONV
1150 mpdm_t cs
= MPDM_2MBS(charset
->data
);
1152 /* tries to create an iconv encoder and decoder for this charset */
1154 if ((ic
= iconv_open("WCHAR_T", (char *) cs
->data
)) == (iconv_t
) - 1)
1159 if ((ic
= iconv_open((char *) cs
->data
, "WCHAR_T")) == (iconv_t
) - 1)
1164 /* got a valid encoding */
1170 #endif /* CONFOPT_ICONV */
1172 if (ret
!= 0 && (v
= mpdm_hget(e
, charset
)) != NULL
)
1176 mpdm_hset_s(mpdm_root(), L
"ENCODING", v
);
1183 * mpdm_unlink - Deletes a file.
1184 * @filename: file name to be deleted
1189 int mpdm_unlink(const mpdm_t filename
)
1194 /* convert to mbs */
1195 fn
= MPDM_2MBS(filename
->data
);
1197 if ((ret
= unlink((char *) fn
->data
)) == -1)
1205 * mpdm_stat - Gives status from a file.
1206 * @filename: file name to get the status from
1208 * Returns a 14 element array of the status (permissions, onwer, etc.)
1209 * from the desired @filename, or NULL if the file cannot be accessed.
1212 * The values are: 0, device number of filesystem; 1, inode number;
1213 * 2, file mode; 3, number of hard links to the file; 4, uid; 5, gid;
1214 * 6, device identifier; 7, total size of file in bytes; 8, atime;
1215 * 9, mtime; 10, ctime; 11, preferred block size for system I/O;
1216 * 12, number of blocks allocated and 13, canonicalized file name.
1217 * Not all elements have necesarily meaningful values, as most are
1221 mpdm_t
mpdm_stat(const mpdm_t filename
)
1225 #ifdef CONFOPT_SYS_STAT_H
1229 fn
= MPDM_2MBS(filename
->data
);
1231 if (stat((char *) fn
->data
, &s
) != -1) {
1234 mpdm_aset(r
, MPDM_I(s
.st_dev
), 0);
1235 mpdm_aset(r
, MPDM_I(s
.st_ino
), 1);
1236 mpdm_aset(r
, MPDM_I(s
.st_mode
), 2);
1237 mpdm_aset(r
, MPDM_I(s
.st_nlink
), 3);
1238 mpdm_aset(r
, MPDM_I(s
.st_uid
), 4);
1239 mpdm_aset(r
, MPDM_I(s
.st_gid
), 5);
1240 mpdm_aset(r
, MPDM_I(s
.st_rdev
), 6);
1241 mpdm_aset(r
, MPDM_I(s
.st_size
), 7);
1242 mpdm_aset(r
, MPDM_I(s
.st_atime
), 8);
1243 mpdm_aset(r
, MPDM_I(s
.st_mtime
), 9);
1244 mpdm_aset(r
, MPDM_I(s
.st_ctime
), 10);
1245 mpdm_aset(r
, MPDM_I(0), 11); /* s.st_blksize */
1246 mpdm_aset(r
, MPDM_I(0), 12); /* s.st_blocks */
1248 #ifdef CONFOPT_CANONICALIZE_FILE_NAME
1253 if ((ptr
= canonicalize_file_name(
1254 (char *)fn
->data
)) != NULL
) {
1255 mpdm_aset(r
, MPDM_MBS(ptr
), 13);
1261 #ifdef CONFOPT_REALPATH
1265 if (realpath((char *)fn
->data
, tmp
) != NULL
)
1266 mpdm_aset(r
, MPDM_MBS(tmp
), 13);
1274 #endif /* CONFOPT_SYS_STAT_H */
1281 * mpdm_chmod - Changes a file's permissions.
1282 * @filename: the file name
1283 * @perms: permissions (element 2 from mpdm_stat())
1285 * Changes the permissions for a file.
1288 int mpdm_chmod(const mpdm_t filename
, mpdm_t perms
)
1292 mpdm_t fn
= MPDM_2MBS(filename
->data
);
1294 if ((r
= chmod((char *) fn
->data
, mpdm_ival(perms
))) == -1)
1302 * mpdm_chown - Changes a file's owner.
1303 * @filename: the file name
1304 * @uid: user id (element 4 from mpdm_stat())
1305 * @gid: group id (element 5 from mpdm_stat())
1307 * Changes the owner and group id's for a file.
1310 int mpdm_chown(const mpdm_t filename
, mpdm_t uid
, mpdm_t gid
)
1314 #ifdef CONFOPT_CHOWN
1316 mpdm_t fn
= MPDM_2MBS(filename
->data
);
1318 if ((r
= chown((char *) fn
->data
, mpdm_ival(uid
), mpdm_ival(gid
))) == -1)
1321 #endif /* CONFOPT_CHOWN */
1328 * mpdm_glob - Executes a file globbing.
1329 * @spec: Globbing spec
1330 * @base: Optional base directory
1332 * Executes a file globbing. @spec is system-dependent, but usually
1333 * the * and ? metacharacters work everywhere. @base can contain a
1334 * directory; if that's the case, the output strings will include it.
1335 * In any case, each returned value will be suitable for a call to
1338 * Returns an array of files that match the globbing (can be an empty
1339 * array if no file matches), or NULL if globbing is unsupported.
1342 mpdm_t
mpdm_glob(const mpdm_t spec
, const mpdm_t base
)
1348 #ifdef CONFOPT_WIN32
1358 /* convert to mbs */
1360 sp
= MPDM_2MBS(spec
->data
);
1362 sp
= MPDM_2MBS(L
"*.*");
1364 ptr
= (char *) sp
->data
;
1366 /* convert MSDOS dir separators into Unix ones */
1367 for (; *ptr
!= '\0'; ptr
++) {
1376 if ((h
= FindFirstFile((char *) sp
->data
, &fd
)) != INVALID_HANDLE_VALUE
) {
1377 /* if spec includes a directory, store in s */
1378 if ((ptr
= strrchr((char *) sp
->data
, '/')) != NULL
) {
1380 s
= MPDM_MBS(sp
->data
);
1384 /* ignore . and .. */
1385 if (strcmp(fd
.cFileName
, ".") == 0 || strcmp(fd
.cFileName
, "..") == 0)
1388 /* concat base directory and file names */
1389 w
= mpdm_strcat(s
, MPDM_MBS(fd
.cFileName
));
1391 /* if it's a directory, add a / */
1392 if (fd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) {
1393 w
= mpdm_strcat(w
, MPDM_LS(L
"/"));
1399 while (FindNextFile(h
, &fd
));
1408 /* glob.h support */
1412 /* build full path */
1414 v
= mpdm_strcat(base
, MPDM_LS(L
"/"));
1416 v
= mpdm_strcat(v
, mpdm_size(spec
) == 0 ? MPDM_LS(L
"*") : spec
);
1417 v
= MPDM_2MBS(v
->data
);
1421 globbuf
.gl_offs
= 1;
1427 if (glob(ptr
, GLOB_MARK
, NULL
, &globbuf
) == 0) {
1430 for (n
= 0; globbuf
.gl_pathv
[n
] != NULL
; n
++) {
1431 char *ptr
= globbuf
.gl_pathv
[n
];
1432 mpdm_t t
= MPDM_MBS(ptr
);
1434 /* if last char is /, add to directories */
1435 if (ptr
[strlen(ptr
) - 1] == '/')
1446 /* no win32 nor glob.h; try workaround */
1454 d
= mpdm_sort(d
, 1);
1455 f
= mpdm_sort(f
, 1);
1457 /* transfer all data in d and f */
1458 for (n
= 0; n
< mpdm_size(d
); n
++)
1459 mpdm_push(v
, mpdm_aget(d
, n
));
1460 for (n
= 0; n
< mpdm_size(f
); n
++)
1461 mpdm_push(v
, mpdm_aget(f
, n
));
1468 #ifdef CONFOPT_WIN32
1470 static void win32_pipe(HANDLE
* h
, int n
)
1472 SECURITY_ATTRIBUTES sa
;
1475 memset(&sa
, '\0', sizeof(sa
));
1476 sa
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
1477 sa
.bInheritHandle
= TRUE
;
1478 sa
.lpSecurityDescriptor
= NULL
;
1480 cp
= GetCurrentProcess();
1482 CreatePipe(&h
[0], &h
[1], &sa
, 0);
1483 DuplicateHandle(cp
, h
[n
], cp
, &t
, 0, FALSE
, DUPLICATE_SAME_ACCESS
);
1489 static int sysdep_popen(mpdm_t v
, char *prg
, int rw
)
1490 /* win32-style pipe */
1494 PROCESS_INFORMATION pi
;
1497 struct mpdm_file
*fs
= v
->data
;
1500 pr
[0] = pr
[1] = pw
[0] = pw
[1] = NULL
;
1507 /* spawn new process */
1508 memset(&pi
, '\0', sizeof(pi
));
1509 memset(&si
, '\0', sizeof(si
));
1511 si
.cb
= sizeof(STARTUPINFO
);
1512 si
.hStdError
= pr
[1];
1513 si
.hStdOutput
= pr
[1];
1514 si
.hStdInput
= pw
[0];
1515 si
.dwFlags
|= STARTF_USESTDHANDLES
;
1517 ret
= CreateProcess(NULL
, prg
, NULL
, NULL
, TRUE
, 0, NULL
, NULL
, &si
, &pi
);
1531 static int sysdep_pclose(const mpdm_t v
)
1533 const struct mpdm_file
*fs
= v
->data
;
1535 if (fs
->hin
!= NULL
)
1536 CloseHandle(fs
->hin
);
1538 if (fs
->hout
!= NULL
)
1539 CloseHandle(fs
->hout
);
1541 /* how to know process exit code? */
1546 #else /* CONFOPT_WIN32 */
1548 static int sysdep_popen(mpdm_t v
, char *prg
, int rw
)
1549 /* unix-style pipe open */
1552 struct mpdm_file
*fs
= (struct mpdm_file
*)v
->data
;
1555 pr
[0] = pr
[1] = pw
[0] = pw
[1] = -1;
1575 /* redirect stderr to stdout */
1579 /* run the program */
1580 execlp("/bin/sh", "/bin/sh", "-c", prg
, NULL
);
1581 execlp(prg
, prg
, NULL
);
1583 /* still here? exec failed; close pipes and exit */
1589 /* create the pipes as non-buffered streams */
1591 fs
->in
= fdopen(pr
[0], "r");
1592 setvbuf(fs
->in
, NULL
, _IONBF
, 0);
1597 fs
->out
= fdopen(pw
[1], "w");
1598 setvbuf(fs
->out
, NULL
, _IONBF
, 0);
1606 static int sysdep_pclose(const mpdm_t v
)
1607 /* unix-style pipe close */
1610 const struct mpdm_file
*fs
= v
->data
;
1615 if (fs
->out
!= fs
->in
&& fs
->out
!= NULL
)
1624 #endif /* CONFOPT_WIN32 */
1628 * mpdm_popen - Opens a pipe.
1629 * @prg: the program to pipe
1630 * @mode: an fopen-like mode string
1632 * Opens a pipe to a program. If @prg can be open in the specified @mode, an
1633 * mpdm_t value will be returned containing the file descriptor, or NULL
1637 mpdm_t
mpdm_popen(const mpdm_t prg
, const mpdm_t mode
)
1643 if (prg
== NULL
|| mode
== NULL
)
1646 if ((v
= new_mpdm_file()) == NULL
)
1649 /* convert to mbs,s */
1650 pr
= MPDM_2MBS(prg
->data
);
1651 md
= MPDM_2MBS(mode
->data
);
1654 m
= (char *) md
->data
;
1662 rw
= 0x03; /* r+ or w+ */
1664 if (!sysdep_popen(v
, (char *) pr
->data
, rw
)) {
1665 destroy_mpdm_file(v
);
1674 * mpdm_pclose - Closes a pipe.
1675 * @fd: the value containing the file descriptor
1680 mpdm_t
mpdm_pclose(mpdm_t fd
)
1684 if ((fd
->flags
& MPDM_FILE
) && fd
->data
!= NULL
) {
1685 r
= MPDM_I(sysdep_pclose(fd
));
1686 destroy_mpdm_file(fd
);
1694 * mpdm_home_dir - Returns the home user directory.
1696 * Returns a system-dependent directory where the user can write
1697 * documents and create subdirectories.
1700 mpdm_t
mpdm_home_dir(void)
1706 #ifdef CONFOPT_WIN32
1710 /* get the 'My Documents' folder */
1711 SHGetSpecialFolderLocation(NULL
, CSIDL_PERSONAL
, &pidl
);
1712 SHGetPathFromIDList(pidl
, tmp
);
1717 #ifdef CONFOPT_PWD_H
1721 /* get home dir from /etc/passwd entry */
1722 if (tmp
[0] == '\0' && (p
= getpwuid(getpid())) != NULL
) {
1723 strcpy(tmp
, p
->pw_dir
);
1729 /* still none? try the ENV variable $HOME */
1730 if (tmp
[0] == '\0' && (ptr
= getenv("HOME")) != NULL
) {
1743 * mpdm_app_dir - Returns the applications directory.
1745 * Returns a system-dependent directory where the applications store
1746 * their private data, as components or resources.
1749 mpdm_t
mpdm_app_dir(void)
1753 #ifdef CONFOPT_WIN32
1759 /* get the 'Program Files' folder (can fail) */
1761 if (SHGetSpecialFolderLocation(NULL
, CSIDL_PROGRAM_FILES
, &pidl
) == S_OK
)
1762 SHGetPathFromIDList(pidl
, tmp
);
1764 /* if it's still empty, get from the registry */
1765 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
,
1766 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
1767 0, KEY_QUERY_VALUE
, &hkey
) == ERROR_SUCCESS
) {
1768 int n
= sizeof(tmp
);
1770 if (RegQueryValueEx(hkey
, "ProgramFilesDir",
1771 NULL
, NULL
, tmp
, (LPDWORD
) & n
) != ERROR_SUCCESS
)
1775 if (tmp
[0] != '\0') {
1781 /* still none? get the configured directory */
1783 r
= MPDM_MBS(CONFOPT_PREFIX
"/share/");