New encoding 'utf-8bom'.
[mpdm.git] / mpdm_f.c
blob5690e30989f21f483b2a52aa0ef280fa0360a853
1 /*
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
26 #include "config.h"
28 #ifdef CONFOPT_CANONICALIZE_FILE_NAME
29 #define _GNU_SOURCE
30 #endif
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <wchar.h>
37 #ifdef CONFOPT_UNISTD_H
38 #include <unistd.h>
39 #endif
41 #ifdef CONFOPT_GLOB_H
42 #include <glob.h>
43 #endif
45 #ifdef CONFOPT_WIN32
47 #include <windows.h>
48 #include <commctrl.h>
49 #include <shlobj.h>
51 #endif
53 #ifdef CONFOPT_SYS_TYPES_H
54 #include <sys/types.h>
55 #endif
57 #ifdef CONFOPT_SYS_WAIT_H
58 #include <sys/wait.h>
59 #endif
61 #ifdef CONFOPT_SYS_STAT_H
62 #include <sys/stat.h>
63 #endif
65 #ifdef CONFOPT_PWD_H
66 #include <pwd.h>
67 #endif
69 #include "mpdm.h"
71 #ifdef CONFOPT_ICONV
72 #include <iconv.h>
73 #endif
75 /* file structure */
76 struct mpdm_file {
77 FILE *in;
78 FILE *out;
80 wchar_t * (* f_read) (const struct mpdm_file *, int *);
81 int (* f_write)(const struct mpdm_file *, const wchar_t *);
83 #ifdef CONFOPT_ICONV
84 iconv_t ic_enc;
85 iconv_t ic_dec;
86 #endif /* CONFOPT_ICONV */
88 #ifdef CONFOPT_WIN32
89 HANDLE hin;
90 HANDLE hout;
91 #endif /* CONFOPT_WIN32 */
94 #include <errno.h>
95 extern int errno;
98 /*******************
99 Code
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 */
113 int c = EOF;
115 #ifdef CONFOPT_WIN32
117 if (f->hin != NULL) {
118 char tmp;
119 DWORD n;
121 if (ReadFile(f->hin, &tmp, 1, &n, NULL) && n > 0)
122 c = (int) tmp;
125 #endif /* CONFOPT_WIN32 */
127 if (f->in != NULL) {
128 /* read (converting to positive if needed) */
129 if ((c = fgetc(f->in)) < 0 && !feof(f->in))
130 c += 256;
133 return c;
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 */
140 #ifdef CONFOPT_WIN32
142 if (f->hout != NULL) {
143 DWORD n;
145 if (WriteFile(f->hout, ptr, s, &n, NULL) && n > 0)
146 s = n;
148 else
149 #endif /* CONFOPT_WIN32 */
151 if (f->out != NULL)
152 s = fwrite(ptr, s, 1, f->out);
154 return s;
158 static int put_char(int c, const struct mpdm_file *f)
159 /* writes a character in a file structure */
161 char tmp = c;
163 if (put_buf(&tmp, 1, f) != 1)
164 c = EOF;
166 return c;
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 */
173 wchar_t *ptr = NULL;
174 char *auxptr = NULL;
175 char tmp[100];
176 int c, i = 0, n = 0;
178 while ((c = get_char(f)) != EOF) {
179 tmp[i++] = c;
181 if (c == '\n')
182 break;
184 if (i == sizeof(tmp) - 1) {
185 /* out of space; start allocating */
186 if ((auxptr = mpdm_poke(auxptr, &n, tmp, i, sizeof(char))) == NULL)
187 return NULL;
189 i = 0;
193 /* is there something to return? */
194 if (i || n) {
195 /* NULL-terminate */
196 tmp[i++] = '\0';
198 if (n) {
199 /* auxiliary space used; concat all */
200 if ((auxptr = mpdm_poke(auxptr, &n, tmp, i, sizeof(char))) == NULL)
201 return NULL;
203 /* do the conversion */
204 ptr = mpdm_mbstowcs(auxptr, s, -1);
206 free(auxptr);
208 else
209 ptr = mpdm_mbstowcs(tmp, s, -1);
212 return ptr;
216 static int write_wcs(const struct mpdm_file *f, const wchar_t * str)
217 /* writes a wide string to an struct mpdm_file */
219 int s;
220 char *ptr;
222 ptr = mpdm_wcstombs(str, &s);
223 s = put_buf(ptr, s, f);
224 free(ptr);
226 return s;
230 #ifdef CONFOPT_ICONV
232 static wchar_t *read_iconv(const struct mpdm_file *f, int *s)
233 /* reads a multibyte string transforming with iconv */
235 char tmp[128];
236 wchar_t *ptr = NULL;
237 int c, i;
238 wchar_t wc;
240 *s = i = 0;
242 /* resets the decoder */
243 iconv(f->ic_dec, NULL, NULL, NULL, NULL);
245 while ((c = get_char(f)) != EOF) {
246 size_t il, ol;
247 char *iptr, *optr;
249 tmp[i++] = c;
251 /* too big? shouldn't happen */
252 if (i == sizeof(tmp))
253 break;
255 il = i;
256 iptr = tmp;
257 ol = sizeof(wchar_t);
258 optr = (char *) &wc;
260 /* write to file */
261 if (iconv(f->ic_dec, &iptr, &il, &optr, &ol) == (size_t) -1) {
262 /* found incomplete multibyte character */
263 if (errno == EINVAL)
264 continue;
266 /* otherwise, return '?' */
267 wc = L'?';
270 i = 0;
272 if ((ptr = mpdm_poke(ptr, s, &wc, 1, sizeof(wchar_t))) == NULL)
273 break;
275 /* if it's an end of line, finish */
276 if (wc == L'\n')
277 break;
280 if (ptr != NULL) {
281 ptr = mpdm_poke(ptr, s, L"", 1, sizeof(wchar_t));
282 (*s)--;
285 return ptr;
289 static int write_iconv(const struct mpdm_file *f, const wchar_t * str)
290 /* writes a wide string to a stream using iconv */
292 char tmp[128];
293 int cnt = 0;
295 /* resets the encoder */
296 iconv(f->ic_enc, NULL, NULL, NULL, NULL);
298 /* convert char by char */
299 for (; *str != L'\0'; str++) {
300 size_t il, ol;
301 char *iptr, *optr;
302 int n;
304 il = sizeof(wchar_t);
305 iptr = (char *) str;
306 ol = sizeof(tmp);
307 optr = tmp;
309 /* write to file */
310 if (iconv(f->ic_enc, &iptr, &il, &optr, &ol) == (size_t) -1) {
311 /* error converting; convert a '?' instead */
312 wchar_t q = L'?';
314 il = sizeof(wchar_t);
315 iptr = (char *) &q;
316 ol = sizeof(tmp);
317 optr = tmp;
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)
324 return -1;
328 return cnt;
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 */
339 wchar_t *ptr = NULL;
340 wchar_t wc;
341 int c;
343 *s = 0;
345 for (;;) {
346 wc = L'\0';
348 UTF8_BYTE();
350 if ((c & 0x80) == 0)
351 wc = c;
352 else
353 if ((c & 0xe0) == 0xe0) {
354 wc = (c & 0x1f) << 12;
355 UTF8_BYTE();
356 wc |= (c & 0x3f) << 6;
357 UTF8_BYTE();
358 wc |= (c & 0x3f);
360 else {
361 wc = (c & 0x3f) << 6;
362 UTF8_BYTE();
363 wc |= (c & 0x3f);
366 /* store */
367 if ((ptr = mpdm_poke(ptr, s, &wc, 1, sizeof(wchar_t))) == NULL)
368 break;
370 /* if it's an end of line, finish */
371 if (wc == L'\n')
372 break;
375 if (ptr != NULL) {
376 ptr = mpdm_poke(ptr, s, L"", 1, sizeof(wchar_t));
377 (*s)--;
380 return ptr;
384 static int write_utf8(const struct mpdm_file *f, const wchar_t * str)
385 /* crappy, ad-hoc utf8 writer */
387 int cnt = 0;
388 wchar_t wc;
390 /* convert char by char */
391 for (; (wc = *str) != L'\0'; str++) {
392 if (wc < 0x80)
393 put_char((int) wc, f);
394 else
395 if (wc < 0x800) {
396 put_char((int) (0xc0 | (wc >> 6)), f);
397 put_char((int) (0x80 | (wc & 0x3f)), f);
398 cnt++;
400 else {
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);
404 cnt += 2;
407 cnt++;
410 return cnt;
414 static wchar_t *read_utf8_bom(struct mpdm_file *f, int *s)
415 /* utf-8 reader with BOM detection */
417 wchar_t *enc = L"";
419 f->f_read = NULL;
421 /* autodetection */
422 if (get_char(f) == 0xef && get_char(f) == 0xbb && get_char(f) == 0xbf)
423 enc = L"utf-8bom";
424 else {
425 enc = L"utf-8";
426 fseek(f->in, 0, 0);
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 */
441 /* store the BOM */
442 put_char(0xef, f);
443 put_char(0xbb, f);
444 put_char(0xbf, f);
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 */
456 wchar_t *ptr = NULL;
457 wchar_t wc;
458 int c;
460 *s = 0;
462 while ((c = get_char(f)) != EOF) {
463 wc = c;
465 /* store */
466 if ((ptr = mpdm_poke(ptr, s, &wc, 1, sizeof(wchar_t))) == NULL)
467 break;
469 /* if it's an end of line, finish */
470 if (wc == L'\n')
471 break;
474 if (ptr != NULL) {
475 ptr = mpdm_poke(ptr, s, L"", 1, sizeof(wchar_t));
476 (*s)--;
479 return ptr;
483 static int write_iso8859_1(const struct mpdm_file *f, const wchar_t * str)
484 /* crappy, ad-hoc iso8859-1 writer */
486 int cnt = 0;
487 wchar_t wc;
489 /* convert char by char */
490 for (; (wc = *str) != L'\0'; str++)
491 put_char(wc <= 0xff ? (int) wc : '?', f);
493 return cnt;
497 static wchar_t *read_utf16ae(const struct mpdm_file *f, int *s, int le)
498 /* utf16 reader, ANY ending */
500 wchar_t *ptr = NULL;
501 wchar_t wc;
502 int c1, c2;
504 *s = 0;
506 for (;;) {
507 wc = L'\0';
509 if ((c1 = get_char(f)) == EOF)
510 break;
512 if ((c2 = get_char(f)) == EOF)
513 break;
515 if (le)
516 wc = c1 | (c2 << 8);
517 else
518 wc = c2 | (c1 << 8);
520 /* store */
521 if ((ptr = mpdm_poke(ptr, s, &wc, 1, sizeof(wchar_t))) == NULL)
522 break;
524 /* if it's an end of line, finish */
525 if (wc == L'\n')
526 break;
529 if (ptr != NULL) {
530 ptr = mpdm_poke(ptr, s, L"", 1, sizeof(wchar_t));
531 (*s)--;
534 return ptr;
538 static int write_utf16ae(const struct mpdm_file *f, const wchar_t * str, int le)
539 /* utf16 writer, ANY ending */
541 int cnt = 0;
542 wchar_t wc;
544 /* convert char by char */
545 for (; (wc = *str) != L'\0'; str++) {
547 if (le) {
548 put_char(wc & 0xff, f);
549 put_char((wc & 0xff00) >> 8, f);
551 else {
552 put_char((wc & 0xff00) >> 8, f);
553 put_char(wc & 0xff, f);
557 return cnt;
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)
587 int c1, c2;
588 wchar_t *enc = L"";
590 f->f_read = NULL;
592 /* autodetection */
593 c1 = get_char(f);
594 c2 = get_char(f);
596 if (c1 == 0xff && c2 == 0xfe) {
597 enc = L"utf-16le";
598 f->f_read = read_utf16le;
600 else
601 if (c1 == 0xfe && c2 == 0xff) {
602 enc = L"utf-16be";
603 f->f_read = read_utf16be;
605 else
606 return NULL;
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 */
617 put_char(0xff, f);
618 put_char(0xfe, f);
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 */
630 wchar_t *ptr = NULL;
631 wchar_t wc;
632 int c1, c2, c3, c4;
634 *s = 0;
636 for (;;) {
637 wc = L'\0';
639 if ((c1 = get_char(f)) == EOF)
640 break;
642 if ((c2 = get_char(f)) == EOF)
643 break;
645 if ((c3 = get_char(f)) == EOF)
646 break;
648 if ((c4 = get_char(f)) == EOF)
649 break;
651 if (le)
652 wc = c1 | (c2 << 8) | (c3 << 16) | (c4 << 24);
653 else
654 wc = c4 | (c3 << 8) | (c2 << 16) | (c1 << 24);
656 /* store */
657 if ((ptr = mpdm_poke(ptr, s, &wc, 1, sizeof(wchar_t))) == NULL)
658 break;
660 /* if it's an end of line, finish */
661 if (wc == L'\n')
662 break;
665 if (ptr != NULL) {
666 ptr = mpdm_poke(ptr, s, L"", 1, sizeof(wchar_t));
667 (*s)--;
670 return ptr;
674 static int write_utf32ae(const struct mpdm_file *f, const wchar_t * str, int le)
675 /* utf32 writer, ANY ending */
677 int cnt = 0;
678 wchar_t wc;
680 /* convert char by char */
681 for (; (wc = *str) != L'\0'; str++) {
683 if (le) {
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);
689 else {
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);
697 return cnt;
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)
727 int c1, c2, c3, c4;
728 wchar_t *enc = L"";
730 f->f_read = NULL;
732 /* autodetection */
733 c1 = get_char(f);
734 c2 = get_char(f);
735 c3 = get_char(f);
736 c4 = get_char(f);
738 if (c1 == 0xff && c2 == 0xfe && c3 == 0 && c4 == 0) {
739 enc = L"utf-32le";
740 f->f_read = read_utf32le;
742 else
743 if (c1 == 0 && c2 == 0 && c3 == 0xfe && c4 == 0xff) {
744 enc = L"utf-32be";
745 f->f_read = read_utf32be;
747 else
748 return NULL;
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 */
759 put_char(0xff, f);
760 put_char(0xfe, f);
761 put_char(0, f);
762 put_char(0, f);
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 */
774 wchar_t *enc = L"";
776 /* by default, multibyte reading */
777 f->f_read = read_mbs;
779 /* not reading from a FILE? no autodetection possible */
780 if (f->in != NULL) {
781 int c;
783 c = get_char(f);
785 if (c == 0xff) {
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) {
790 enc = L"utf-32le";
791 f->f_read = read_utf32le;
792 goto got_encoding;
794 else {
795 /* rewind to 3rd character */
796 fseek(f->in, 2, 0);
798 enc = L"utf-16le";
799 f->f_read = read_utf16le;
800 goto got_encoding;
804 else
805 if (c == 0x00) {
806 /* can be utf32be */
807 if (get_char(f) == 0x00 && get_char(f) == 0xfe && get_char(f) == 0xff) {
808 enc = L"utf-32be";
809 f->f_read = read_utf32be;
810 goto got_encoding;
813 else
814 if (c == 0xfe) {
815 /* can be utf16be */
816 if (get_char(f) == 0xff) {
817 enc = L"utf-16be";
818 f->f_read = read_utf16be;
819 goto got_encoding;
822 else
823 if (c == 0xef) {
824 /* can be utf8 with BOM */
825 if (get_char(f) == 0xbb && get_char(f) == 0xbf) {
826 enc = L"utf-8bom";
827 f->f_read = read_utf8;
828 goto got_encoding;
832 /* none of the above; restart */
833 fseek(f->in, 0, 0);
836 got_encoding:
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 */
846 mpdm_t v = NULL;
847 struct mpdm_file *fs;
848 mpdm_t e;
850 if ((fs = malloc(sizeof(struct mpdm_file))) == NULL)
851 return 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;
859 #ifdef CONFOPT_ICONV
860 /* no iconv encodings by default */
861 fs->ic_enc = fs->ic_dec = (iconv_t) -1;
862 #endif
864 if ((v = mpdm_new(MPDM_FILE | MPDM_FREE, fs, sizeof(struct mpdm_file))) == NULL) {
865 free(fs);
866 return NULL;
869 if ((e = mpdm_hget_s(mpdm_root(), L"ENCODING")) != NULL) {
871 wchar_t *enc = mpdm_string(e);
873 #ifdef CONFOPT_ICONV
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;
882 return v;
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;
890 else
891 if (wcscmp(enc, L"utf-8bom") == 0) {
892 fs->f_read = read_utf8_bom;
893 fs->f_write = write_utf8_bom;
895 else
896 if (wcscmp(enc, L"iso8859-1") == 0) {
897 fs->f_read = read_iso8859_1;
898 fs->f_write = write_iso8859_1;
900 else
901 if (wcscmp(enc, L"utf-16le") == 0) {
902 fs->f_read = read_utf16le;
903 fs->f_write = write_utf16le;
905 else
906 if (wcscmp(enc, L"utf-16be") == 0) {
907 fs->f_read = read_utf16be;
908 fs->f_write = write_utf16be;
910 else
911 if (wcscmp(enc, L"utf-16") == 0) {
912 fs->f_read = read_utf16;
913 fs->f_write = write_utf16;
915 else
916 if (wcscmp(enc, L"utf-32le") == 0) {
917 fs->f_read = read_utf32le;
918 fs->f_write = write_utf32le;
920 else
921 if (wcscmp(enc, L"utf-32be") == 0) {
922 fs->f_read = read_utf32be;
923 fs->f_write = write_utf32be;
925 else
926 if (wcscmp(enc, L"utf-32") == 0) {
927 fs->f_read = read_utf32;
928 fs->f_write = write_utf32;
932 return v;
936 static void destroy_mpdm_file(mpdm_t v)
937 /* destroys and file value */
939 struct mpdm_file *fs = (struct mpdm_file *)v->data;
941 if (fs != NULL) {
942 #ifdef CONFOPT_ICONV
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;
952 #endif
954 free(fs);
955 v->data = NULL;
960 /** interface **/
962 wchar_t *mpdm_read_mbs(FILE * f, int *s)
963 /* reads a multibyte string from a stream into a dynamic string */
965 struct mpdm_file fs;
967 /* reset the structure */
968 memset(&fs, '\0', sizeof(fs));
969 fs.in = f;
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 */
978 struct mpdm_file fs;
980 /* reset the structure */
981 memset(&fs, '\0', sizeof(fs));
982 fs.out = f;
984 return write_wcs(&fs, str);
988 mpdm_t mpdm_new_f(FILE * f)
989 /* creates a new file value from a FILE * */
991 mpdm_t v = NULL;
993 if (f == NULL)
994 return NULL;
996 if ((v = new_mpdm_file()) != NULL) {
997 struct mpdm_file *fs = (struct mpdm_file *)v->data;
998 fs->in = fs->out = f;
1001 return v;
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
1012 * otherwise.
1013 * [File Management]
1015 mpdm_t mpdm_open(const mpdm_t filename, const mpdm_t mode)
1017 FILE *f;
1018 mpdm_t fn;
1019 mpdm_t m;
1021 if (filename == NULL || mode == NULL)
1022 return 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)
1029 store_syserr();
1030 else {
1031 #if defined(CONFOPT_SYS_STAT_H) && defined(S_ISDIR) && defined(EISDIR)
1032 struct stat s;
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 */
1037 errno = EISDIR;
1038 store_syserr();
1039 fclose(f);
1040 f = NULL;
1042 #endif
1045 return MPDM_F(f);
1050 * mpdm_close - Closes a file descriptor.
1051 * @fd: the value containing the file descriptor
1053 * Closes the file descriptor.
1054 * [File Management]
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) {
1061 if (fs->in != NULL)
1062 fclose(fs->in);
1064 if (fs->out != fs->in && fs->out != NULL)
1065 fclose(fs->out);
1067 destroy_mpdm_file(fd);
1070 return NULL;
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.
1079 * [File Management]
1080 * [Character Set Conversion]
1082 mpdm_t mpdm_read(const mpdm_t fd)
1084 mpdm_t v = NULL;
1085 wchar_t *ptr;
1086 int s;
1087 const struct mpdm_file *fs = fd->data;
1089 if (fs == NULL)
1090 return NULL;
1092 ptr = fs->f_read(fs, &s);
1094 if (ptr != NULL)
1095 v = MPDM_ENS(ptr, s);
1097 return v;
1101 mpdm_t mpdm_getchar(const mpdm_t fd)
1103 int c;
1104 wchar_t tmp[2];
1105 const struct mpdm_file *fs = fd->data;
1107 if (fs == NULL || (c = get_char(fs)) == EOF)
1108 return NULL;
1110 /* get the char as-is */
1111 tmp[0] = (wchar_t) c;
1112 tmp[1] = L'\0';
1114 return MPDM_S(tmp);
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)
1124 return NULL;
1126 return c;
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.
1136 * [File Management]
1137 * [Character Set Conversion]
1139 int mpdm_write(const mpdm_t fd, const mpdm_t v)
1141 const struct mpdm_file *fs = fd->data;
1142 int ret = -1;
1144 if (fs == NULL)
1145 return -1;
1147 ret = fs->f_write(fs, mpdm_string(v));
1149 return ret;
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)
1171 FILE * f = NULL;
1173 if (fd->flags & MPDM_FILE) {
1174 const struct mpdm_file *fs = fd->data;
1175 f = fs->in;
1178 return f;
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)
1196 mpdm_t e;
1197 wchar_t *e2e[] = {
1198 L"utf-8", L"utf-8",
1199 L"utf8", NULL,
1200 L"iso8859-1", L"iso8859-1",
1201 L"iso-8859-1", NULL,
1202 L"latin1", NULL,
1203 L"latin-1", NULL,
1204 L"utf-16le", L"utf-16le",
1205 L"utf16le", NULL,
1206 L"ucs-2le", NULL,
1207 L"utf-16be", L"utf-16be",
1208 L"utf16be", NULL,
1209 L"ucs-2be", NULL,
1210 L"utf-16", L"utf-16",
1211 L"utf16", NULL,
1212 L"ucs-2", NULL,
1213 L"ucs2", NULL,
1214 L"utf-32le", L"utf-32le",
1215 L"utf32le", NULL,
1216 L"ucs-4le", NULL,
1217 L"utf-32be", L"utf-32be",
1218 L"utf32be", NULL,
1219 L"ucs-4be", NULL,
1220 L"utf-32", L"utf-32",
1221 L"utf32", NULL,
1222 L"ucs-4", NULL,
1223 L"ucs4", NULL,
1224 L"utf-8bom", L"utf-8bom",
1225 L"utf8bom", NULL,
1226 NULL, NULL
1229 if ((e = mpdm_hget_s(mpdm_root(), L"EMBEDDED_ENCODINGS")) == NULL) {
1230 int n;
1231 wchar_t *p = NULL;
1233 e = MPDM_H(0);
1235 for (n = 0; e2e[n] != NULL; n += 2) {
1236 mpdm_t v = MPDM_S(e2e[n]);
1238 if (e2e[n + 1] != NULL)
1239 p = e2e[n + 1];
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);
1248 return 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
1261 * in the locale).
1262 * Returns a negative number if @charset is unsupported, or zero
1263 * if no errors were found.
1264 * [File Management]
1265 * [Character Set Conversion]
1267 int mpdm_encoding(mpdm_t charset)
1269 int ret = -1;
1270 mpdm_t e = embedded_encodings();
1271 mpdm_t v = NULL;
1273 /* NULL encoding? done */
1274 if (mpdm_size(charset) == 0) {
1275 mpdm_hset_s(mpdm_root(), L"ENCODING", NULL);
1276 return 0;
1279 #ifdef CONFOPT_ICONV
1281 iconv_t ic;
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)
1287 ret = -1;
1288 else {
1289 iconv_close(ic);
1291 if ((ic = iconv_open((char *) cs->data, "WCHAR_T")) == (iconv_t) - 1)
1292 ret = -2;
1293 else {
1294 iconv_close(ic);
1296 /* got a valid encoding */
1297 v = charset;
1298 ret = 0;
1302 #endif /* CONFOPT_ICONV */
1304 if (ret != 0 && (v = mpdm_hget(e, charset)) != NULL)
1305 ret = 0;
1307 if (ret == 0)
1308 mpdm_hset_s(mpdm_root(), L"ENCODING", v);
1310 return ret;
1315 * mpdm_unlink - Deletes a file.
1316 * @filename: file name to be deleted
1318 * Deletes a file.
1319 * [File Management]
1321 int mpdm_unlink(const mpdm_t filename)
1323 int ret;
1324 mpdm_t fn;
1326 /* convert to mbs */
1327 fn = MPDM_2MBS(filename->data);
1329 if ((ret = unlink((char *) fn->data)) == -1)
1330 store_syserr();
1332 return ret;
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.
1342 * (man 2 stat).
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
1350 * system-dependent.
1351 * [File Management]
1353 mpdm_t mpdm_stat(const mpdm_t filename)
1355 mpdm_t r = NULL;
1357 #ifdef CONFOPT_SYS_STAT_H
1358 struct stat s;
1359 mpdm_t fn;
1361 fn = MPDM_2MBS(filename->data);
1363 if (stat((char *) fn->data, &s) != -1) {
1364 r = MPDM_A(14);
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
1383 char * ptr;
1385 if ((ptr = canonicalize_file_name(
1386 (char *)fn->data)) != NULL) {
1387 mpdm_aset(r, MPDM_MBS(ptr), 13);
1388 free(ptr);
1391 #endif
1393 #ifdef CONFOPT_REALPATH
1395 char tmp[2048];
1397 if (realpath((char *)fn->data, tmp) != NULL)
1398 mpdm_aset(r, MPDM_MBS(tmp), 13);
1400 #endif
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);
1409 #endif
1412 else
1413 store_syserr();
1415 #endif /* CONFOPT_SYS_STAT_H */
1417 return r;
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.
1427 * [File Management]
1429 int mpdm_chmod(const mpdm_t filename, mpdm_t perms)
1431 int r = -1;
1433 mpdm_t fn = MPDM_2MBS(filename->data);
1435 if ((r = chmod((char *) fn->data, mpdm_ival(perms))) == -1)
1436 store_syserr();
1438 return r;
1443 * mpdm_chdir - Changes the working directory
1444 * @dir: the new path
1446 * Changes the working directory
1447 * [File Management]
1449 int mpdm_chdir(const mpdm_t dir)
1451 int r = -1;
1453 mpdm_t fn = MPDM_2MBS(dir->data);
1455 if ((r = chdir((char *) fn->data)) == -1)
1456 store_syserr();
1458 return r;
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.
1469 * [File Management]
1471 int mpdm_chown(const mpdm_t filename, mpdm_t uid, mpdm_t gid)
1473 int r = -1;
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)
1480 store_syserr();
1482 #endif /* CONFOPT_CHOWN */
1484 return r;
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
1497 * mpdm_open().
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.
1501 * [File Management]
1503 mpdm_t mpdm_glob(const mpdm_t spec, const mpdm_t base)
1505 mpdm_t d = NULL;
1506 mpdm_t f = NULL;
1507 mpdm_t v = NULL;
1509 #ifdef CONFOPT_WIN32
1511 WIN32_FIND_DATA fd;
1512 HANDLE h;
1513 char *ptr;
1514 mpdm_t w;
1515 mpdm_t s = NULL;
1516 mpdm_t sp = NULL;
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);
1528 v = MPDM_A(0);
1529 d = MPDM_A(0);
1530 f = MPDM_A(0);
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) {
1535 *(ptr + 1) = '\0';
1536 s = MPDM_MBS(sp->data);
1539 do {
1540 /* ignore . and .. */
1541 if (strcmp(fd.cFileName, ".") == 0 || strcmp(fd.cFileName, "..") == 0)
1542 continue;
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"/"));
1550 mpdm_push(d, w);
1552 else
1553 mpdm_push(f, w);
1555 while (FindNextFile(h, &fd));
1557 FindClose(h);
1560 #endif
1562 #if CONFOPT_GLOB_H
1564 /* glob.h support */
1565 glob_t globbuf;
1566 const char *ptr;
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);
1579 ptr = v->data;
1581 globbuf.gl_offs = 1;
1583 v = MPDM_A(0);
1584 d = MPDM_A(0);
1585 f = MPDM_A(0);
1587 if (glob(ptr, GLOB_MARK, NULL, &globbuf) == 0) {
1588 int n;
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] == '/')
1596 mpdm_push(d, t);
1597 else
1598 mpdm_push(f, t);
1602 globfree(&globbuf);
1604 #else
1606 /* no win32 nor glob.h; try workaround */
1607 /* ... */
1609 #endif
1611 if (v != NULL) {
1612 int n;
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));
1624 return v;
1628 #ifdef CONFOPT_WIN32
1630 static void win32_pipe(HANDLE * h, int n)
1632 SECURITY_ATTRIBUTES sa;
1633 HANDLE cp, t;
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);
1644 CloseHandle(h[n]);
1645 h[n] = t;
1649 static int sysdep_popen(mpdm_t v, char *prg, int rw)
1650 /* win32-style pipe */
1652 HANDLE pr[2];
1653 HANDLE pw[2];
1654 PROCESS_INFORMATION pi;
1655 STARTUPINFO si;
1656 int ret;
1657 struct mpdm_file *fs = v->data;
1659 /* init all */
1660 pr[0] = pr[1] = pw[0] = pw[1] = NULL;
1662 if (rw & 0x01)
1663 win32_pipe(pr, 0);
1664 if (rw & 0x02)
1665 win32_pipe(pw, 1);
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);
1679 if (rw & 0x01)
1680 CloseHandle(pr[1]);
1681 if (rw & 0x02)
1682 CloseHandle(pw[0]);
1684 fs->hin = pr[0];
1685 fs->hout = pw[1];
1687 return ret;
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? */
1702 return 0;
1706 #else /* CONFOPT_WIN32 */
1708 static int sysdep_popen(mpdm_t v, char *prg, int rw)
1709 /* unix-style pipe open */
1711 int pr[2], pw[2];
1712 struct mpdm_file *fs = (struct mpdm_file *)v->data;
1714 /* init all */
1715 pr[0] = pr[1] = pw[0] = pw[1] = -1;
1717 if (rw & 0x01)
1718 pipe(pr);
1719 if (rw & 0x02)
1720 pipe(pw);
1722 if (fork() == 0) {
1723 /* child process */
1724 if (rw & 0x01) {
1725 close(1);
1726 dup(pr[1]);
1727 close(pr[0]);
1729 if (rw & 0x02) {
1730 close(0);
1731 dup(pw[0]);
1732 close(pw[1]);
1735 /* redirect stderr to stdout */
1736 close(2);
1737 dup(1);
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 */
1744 close(0);
1745 close(1);
1746 exit(0);
1749 /* create the pipes as non-buffered streams */
1750 if (rw & 0x01) {
1751 fs->in = fdopen(pr[0], "r");
1752 setvbuf(fs->in, NULL, _IONBF, 0);
1753 close(pr[1]);
1756 if (rw & 0x02) {
1757 fs->out = fdopen(pw[1], "w");
1758 setvbuf(fs->out, NULL, _IONBF, 0);
1759 close(pw[0]);
1762 return 1;
1766 static int sysdep_pclose(const mpdm_t v)
1767 /* unix-style pipe close */
1769 int s;
1770 const struct mpdm_file *fs = v->data;
1772 if (fs->in != NULL)
1773 fclose(fs->in);
1775 if (fs->out != fs->in && fs->out != NULL)
1776 fclose(fs->out);
1778 wait(&s);
1780 return s;
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
1794 * otherwise.
1795 * [File Management]
1797 mpdm_t mpdm_popen(const mpdm_t prg, const mpdm_t mode)
1799 mpdm_t v, pr, md;
1800 char *m;
1801 int rw = 0;
1803 if (prg == NULL || mode == NULL)
1804 return NULL;
1806 if ((v = new_mpdm_file()) == NULL)
1807 return NULL;
1809 /* convert to mbs,s */
1810 pr = MPDM_2MBS(prg->data);
1811 md = MPDM_2MBS(mode->data);
1813 /* get the mode */
1814 m = (char *) md->data;
1816 /* set the mode */
1817 if (m[0] == 'r')
1818 rw = 0x01;
1819 if (m[0] == 'w')
1820 rw = 0x02;
1821 if (m[1] == '+')
1822 rw = 0x03; /* r+ or w+ */
1824 if (!sysdep_popen(v, (char *) pr->data, rw)) {
1825 destroy_mpdm_file(v);
1826 v = NULL;
1829 return v;
1834 * mpdm_pclose - Closes a pipe.
1835 * @fd: the value containing the file descriptor
1837 * Closes a pipe.
1838 * [File Management]
1840 mpdm_t mpdm_pclose(mpdm_t fd)
1842 mpdm_t r = NULL;
1844 if ((fd->flags & MPDM_FILE) && fd->data != NULL) {
1845 r = MPDM_I(sysdep_pclose(fd));
1846 destroy_mpdm_file(fd);
1849 return r;
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.
1858 * [File Management]
1860 mpdm_t mpdm_home_dir(void)
1862 mpdm_t r = NULL;
1863 char *ptr;
1864 char tmp[512] = "";
1866 #ifdef CONFOPT_WIN32
1868 LPITEMIDLIST pidl;
1870 /* get the 'My Documents' folder */
1871 SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &pidl);
1872 SHGetPathFromIDList(pidl, tmp);
1873 strcat(tmp, "\\");
1875 #endif
1877 #ifdef CONFOPT_PWD_H
1879 struct passwd *p;
1881 /* get home dir from /etc/passwd entry */
1882 if (tmp[0] == '\0' && (p = getpwuid(getpid())) != NULL) {
1883 strcpy(tmp, p->pw_dir);
1884 strcat(tmp, "/");
1887 #endif
1889 /* still none? try the ENV variable $HOME */
1890 if (tmp[0] == '\0' && (ptr = getenv("HOME")) != NULL) {
1891 strcpy(tmp, ptr);
1892 strcat(tmp, "/");
1895 if (tmp[0] != '\0')
1896 r = MPDM_MBS(tmp);
1898 return r;
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.
1907 * [File Management]
1909 mpdm_t mpdm_app_dir(void)
1911 mpdm_t r = NULL;
1913 #ifdef CONFOPT_WIN32
1915 HKEY hkey;
1916 char tmp[MAX_PATH];
1917 LPITEMIDLIST pidl;
1919 /* get the 'Program Files' folder (can fail) */
1920 tmp[0] = '\0';
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)
1932 tmp[0] = '\0';
1935 if (tmp[0] != '\0') {
1936 strcat(tmp, "\\");
1937 r = MPDM_MBS(tmp);
1939 #endif
1941 /* still none? get the configured directory */
1942 if (r == NULL)
1943 r = MPDM_MBS(CONFOPT_PREFIX "/share/");
1945 return r;