Updated TODO.
[mpdm.git] / mpdm_f.c
blob1a2577af13e51e91b014e4fea1bc69a004fde144
1 /*
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
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) (struct mpdm_file *, int *);
81 int (*f_write) (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 HANDLE process;
92 #endif /* CONFOPT_WIN32 */
95 #include <errno.h>
96 extern int errno;
99 /** code **/
102 static void store_syserr(void)
103 /* stores the system error inside the global ERRNO */
105 mpdm_hset_s(mpdm_root(), L"ERRNO", MPDM_MBS(strerror(errno)));
109 static int get_char(struct mpdm_file *f)
110 /* reads a character from a file structure */
112 int c = EOF;
114 #ifdef CONFOPT_WIN32
116 if (f->hin != NULL) {
117 char tmp;
118 DWORD n;
120 if (ReadFile(f->hin, &tmp, 1, &n, NULL) && n > 0)
121 c = (int) tmp;
124 #endif /* CONFOPT_WIN32 */
126 if (f->in != NULL) {
127 /* read (converting to positive if needed) */
128 if ((c = fgetc(f->in)) < 0 && !feof(f->in))
129 c += 256;
132 return c;
136 static int put_buf(const char *ptr, int s, struct mpdm_file *f)
137 /* writes s bytes in the buffer in ptr to f */
139 #ifdef CONFOPT_WIN32
141 if (f->hout != NULL) {
142 DWORD n;
144 if (WriteFile(f->hout, ptr, s, &n, NULL) && n > 0)
145 s = n;
147 else
148 #endif /* CONFOPT_WIN32 */
150 if (f->out != NULL)
151 s = fwrite(ptr, s, 1, f->out);
153 return s;
157 static int put_char(int c, struct mpdm_file *f)
158 /* writes a character in a file structure */
160 char tmp = c;
162 if (put_buf(&tmp, 1, f) != 1)
163 c = EOF;
165 return c;
169 static wchar_t *read_mbs(struct mpdm_file *f, int *s)
170 /* reads a multibyte string from a mpdm_file into a dynamic string */
172 wchar_t *ptr = NULL;
173 char *auxptr = NULL;
174 char tmp[100];
175 int c, i = 0, n = 0;
177 while ((c = get_char(f)) != EOF) {
178 tmp[i++] = c;
180 if (c == '\n')
181 break;
183 if (i == sizeof(tmp) - 1) {
184 /* out of space; start allocating */
185 if ((auxptr =
186 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 =
201 mpdm_poke(auxptr, &n, tmp, i, sizeof(char))) == NULL)
202 return NULL;
204 /* do the conversion */
205 ptr = mpdm_mbstowcs(auxptr, s, -1);
207 free(auxptr);
209 else
210 ptr = mpdm_mbstowcs(tmp, s, -1);
213 return ptr;
217 static int write_wcs(struct mpdm_file *f, const wchar_t * str)
218 /* writes a wide string to an struct mpdm_file */
220 int s;
221 char *ptr;
223 ptr = mpdm_wcstombs(str, &s);
224 s = put_buf(ptr, s, f);
225 free(ptr);
227 return s;
231 #ifdef CONFOPT_ICONV
233 static wchar_t *read_iconv(struct mpdm_file *f, int *s)
234 /* reads a multibyte string transforming with iconv */
236 char tmp[128];
237 wchar_t *ptr = NULL;
238 int c, i;
239 wchar_t wc;
241 *s = i = 0;
243 /* resets the decoder */
244 iconv(f->ic_dec, NULL, NULL, NULL, NULL);
246 while ((c = get_char(f)) != EOF) {
247 size_t il, ol;
248 char *iptr, *optr;
250 tmp[i++] = c;
252 /* too big? shouldn't happen */
253 if (i == sizeof(tmp))
254 break;
256 il = i;
257 iptr = tmp;
258 ol = sizeof(wchar_t);
259 optr = (char *) &wc;
261 /* write to file */
262 if (iconv(f->ic_dec, &iptr, &il, &optr, &ol) == (size_t) - 1) {
263 /* found incomplete multibyte character */
264 if (errno == EINVAL)
265 continue;
267 /* otherwise, return '?' */
268 wc = L'?';
271 i = 0;
273 if ((ptr = mpdm_poke(ptr, s, &wc, 1, sizeof(wchar_t))) == NULL)
274 break;
276 /* if it's an end of line, finish */
277 if (wc == L'\n')
278 break;
281 if (ptr != NULL) {
282 ptr = mpdm_poke(ptr, s, L"", 1, sizeof(wchar_t));
283 (*s)--;
286 return ptr;
290 static int write_iconv(struct mpdm_file *f, const wchar_t * str)
291 /* writes a wide string to a stream using iconv */
293 char tmp[128];
294 int cnt = 0;
296 /* resets the encoder */
297 iconv(f->ic_enc, NULL, NULL, NULL, NULL);
299 /* convert char by char */
300 for (; *str != L'\0'; str++) {
301 size_t il, ol;
302 char *iptr, *optr;
303 int n;
305 il = sizeof(wchar_t);
306 iptr = (char *) str;
307 ol = sizeof(tmp);
308 optr = tmp;
310 /* write to file */
311 if (iconv(f->ic_enc, &iptr, &il, &optr, &ol) == (size_t) - 1) {
312 /* error converting; convert a '?' instead */
313 wchar_t q = L'?';
315 il = sizeof(wchar_t);
316 iptr = (char *) &q;
317 ol = sizeof(tmp);
318 optr = tmp;
320 iconv(f->ic_enc, &iptr, &il, &optr, &ol);
323 for (n = 0; n < (int) (sizeof(tmp) - ol); n++, cnt++) {
324 if (put_char(tmp[n], f) == EOF)
325 return -1;
329 return cnt;
333 #endif /* CONFOPT_ICONV */
335 #define UTF8_BYTE() if((c = get_char(f)) == EOF) break
337 static wchar_t *read_utf8(struct mpdm_file *f, int *s)
338 /* utf8 reader */
340 wchar_t *ptr = NULL;
341 wchar_t wc;
342 int c;
344 *s = 0;
346 for (;;) {
347 wc = L'\0';
349 UTF8_BYTE();
351 if ((c & 0x80) == 0)
352 wc = c;
353 else
354 if ((c & 0xe0) == 0xe0) {
355 wc = (c & 0x1f) << 12;
356 UTF8_BYTE();
357 wc |= (c & 0x3f) << 6;
358 UTF8_BYTE();
359 wc |= (c & 0x3f);
361 else {
362 wc = (c & 0x3f) << 6;
363 UTF8_BYTE();
364 wc |= (c & 0x3f);
367 /* store */
368 if ((ptr = mpdm_poke(ptr, s, &wc, 1, sizeof(wchar_t))) == NULL)
369 break;
371 /* if it's an end of line, finish */
372 if (wc == L'\n')
373 break;
376 if (ptr != NULL) {
377 ptr = mpdm_poke(ptr, s, L"", 1, sizeof(wchar_t));
378 (*s)--;
381 return ptr;
385 static int write_utf8(struct mpdm_file *f, const wchar_t * str)
386 /* utf8 writer */
388 int cnt = 0;
389 wchar_t wc;
391 /* convert char by char */
392 for (; (wc = *str) != L'\0'; str++) {
393 if (wc < 0x80)
394 put_char((int) wc, f);
395 else
396 if (wc < 0x800) {
397 put_char((int) (0xc0 | (wc >> 6)), f);
398 put_char((int) (0x80 | (wc & 0x3f)), f);
399 cnt++;
401 else {
402 put_char((int) (0xe0 | (wc >> 12)), f);
403 put_char((int) (0x80 | ((wc >> 6) & 0x3f)), f);
404 put_char((int) (0x80 | (wc & 0x3f)), f);
405 cnt += 2;
408 cnt++;
411 return cnt;
415 static wchar_t *read_utf8_bom(struct mpdm_file *f, int *s)
416 /* utf-8 reader with BOM detection */
418 wchar_t *enc = L"";
420 f->f_read = NULL;
422 /* autodetection */
423 if (get_char(f) == 0xef && get_char(f) == 0xbb && get_char(f) == 0xbf)
424 enc = L"utf-8bom";
425 else {
426 enc = L"utf-8";
427 fseek(f->in, 0, SEEK_SET);
430 mpdm_hset_s(mpdm_root(), L"DETECTED_ENCODING", MPDM_LS(enc));
432 /* we're utf-8 from now on */
433 f->f_read = read_utf8;
435 return f->f_read(f, s);
439 static int write_utf8_bom(struct mpdm_file *f, const wchar_t * str)
440 /* utf-8 writer with BOM */
442 /* store the BOM */
443 put_char(0xef, f);
444 put_char(0xbb, f);
445 put_char(0xbf, f);
447 /* we're utf-8 from now on */
448 f->f_write = write_utf8;
450 return f->f_write(f, str);
454 static wchar_t *read_iso8859_1(struct mpdm_file *f, int *s)
455 /* iso8859-1 reader */
457 wchar_t *ptr = NULL;
458 wchar_t wc;
459 int c;
461 *s = 0;
463 while ((c = get_char(f)) != EOF) {
464 wc = c;
466 /* store */
467 if ((ptr = mpdm_poke(ptr, s, &wc, 1, sizeof(wchar_t))) == NULL)
468 break;
470 /* if it's an end of line, finish */
471 if (wc == L'\n')
472 break;
475 if (ptr != NULL) {
476 ptr = mpdm_poke(ptr, s, L"", 1, sizeof(wchar_t));
477 (*s)--;
480 return ptr;
484 static int write_iso8859_1(struct mpdm_file *f, const wchar_t * str)
485 /* iso8859-1 writer */
487 int cnt = 0;
488 wchar_t wc;
490 /* convert char by char */
491 for (; (wc = *str) != L'\0'; str++)
492 put_char(wc <= 0xff ? (int) wc : '?', f);
494 return cnt;
498 static wchar_t *read_utf16ae(struct mpdm_file *f, int *s, int le)
499 /* utf16 reader, ANY ending */
501 wchar_t *ptr = NULL;
502 wchar_t wc;
503 int c1, c2;
505 *s = 0;
507 for (;;) {
508 wc = L'\0';
510 if ((c1 = get_char(f)) == EOF)
511 break;
513 if ((c2 = get_char(f)) == EOF)
514 break;
516 if (le)
517 wc = c1 | (c2 << 8);
518 else
519 wc = c2 | (c1 << 8);
521 /* store */
522 if ((ptr = mpdm_poke(ptr, s, &wc, 1, sizeof(wchar_t))) == NULL)
523 break;
525 /* if it's an end of line, finish */
526 if (wc == L'\n')
527 break;
530 if (ptr != NULL) {
531 ptr = mpdm_poke(ptr, s, L"", 1, sizeof(wchar_t));
532 (*s)--;
535 return ptr;
539 static int write_utf16ae(struct mpdm_file *f, const wchar_t * str, int le)
540 /* utf16 writer, ANY ending */
542 int cnt = 0;
543 wchar_t wc;
545 /* convert char by char */
546 for (; (wc = *str) != L'\0'; str++) {
548 if (le) {
549 put_char(wc & 0xff, f);
550 put_char((wc & 0xff00) >> 8, f);
552 else {
553 put_char((wc & 0xff00) >> 8, f);
554 put_char(wc & 0xff, f);
558 return cnt;
562 static wchar_t *read_utf16le(struct mpdm_file *f, int *s)
564 return read_utf16ae(f, s, 1);
568 static int write_utf16le(struct mpdm_file *f, const wchar_t * str)
570 return write_utf16ae(f, str, 1);
574 static wchar_t *read_utf16be(struct mpdm_file *f, int *s)
576 return read_utf16ae(f, s, 0);
580 static int write_utf16be(struct mpdm_file *f, const wchar_t * str)
582 return write_utf16ae(f, str, 0);
586 static wchar_t *read_utf16(struct mpdm_file *f, int *s)
588 int c1, c2;
589 wchar_t *enc = L"utf-16le";
591 /* assume little-endian */
592 f->f_read = read_utf16le;
594 /* autodetection */
595 c1 = get_char(f);
596 c2 = get_char(f);
598 if (c1 == 0xfe && c2 == 0xff) {
599 enc = L"utf-16be";
600 f->f_read = read_utf16be;
602 else
603 if (c1 != 0xff || c2 != 0xfe) {
604 /* no BOM; rewind and hope */
605 fseek(f->in, 0, SEEK_SET);
608 mpdm_hset_s(mpdm_root(), L"DETECTED_ENCODING", MPDM_LS(enc));
610 return f->f_read(f, s);
614 static int write_utf16le_bom(struct mpdm_file *f, const wchar_t * str)
616 /* store the LE signature */
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 int write_utf16be_bom(struct mpdm_file *f, const wchar_t * str)
629 /* store the BE signature */
630 put_char(0xfe, f);
631 put_char(0xff, f);
633 /* we're 16be from now on */
634 f->f_write = write_utf16be;
636 return f->f_write(f, str);
640 static wchar_t *read_utf32ae(struct mpdm_file *f, int *s, int le)
641 /* utf32 reader, ANY ending */
643 wchar_t *ptr = NULL;
644 wchar_t wc;
645 int c1, c2, c3, c4;
647 *s = 0;
649 for (;;) {
650 wc = L'\0';
652 if ((c1 = get_char(f)) == EOF)
653 break;
655 if ((c2 = get_char(f)) == EOF)
656 break;
658 if ((c3 = get_char(f)) == EOF)
659 break;
661 if ((c4 = get_char(f)) == EOF)
662 break;
664 if (le)
665 wc = c1 | (c2 << 8) | (c3 << 16) | (c4 << 24);
666 else
667 wc = c4 | (c3 << 8) | (c2 << 16) | (c1 << 24);
669 /* store */
670 if ((ptr = mpdm_poke(ptr, s, &wc, 1, sizeof(wchar_t))) == NULL)
671 break;
673 /* if it's an end of line, finish */
674 if (wc == L'\n')
675 break;
678 if (ptr != NULL) {
679 ptr = mpdm_poke(ptr, s, L"", 1, sizeof(wchar_t));
680 (*s)--;
683 return ptr;
687 static int write_utf32ae(struct mpdm_file *f, const wchar_t * str, int le)
688 /* utf32 writer, ANY ending */
690 int cnt = 0;
691 wchar_t wc;
693 /* convert char by char */
694 for (; (wc = *str) != L'\0'; str++) {
696 if (le) {
697 put_char((wc & 0x000000ff), f);
698 put_char((wc & 0x0000ff00) >> 8, f);
699 put_char((wc & 0x00ff0000) >> 16, f);
700 put_char((wc & 0xff000000) >> 24, f);
702 else {
703 put_char((wc & 0xff000000) >> 24, f);
704 put_char((wc & 0x00ff0000) >> 16, f);
705 put_char((wc & 0x0000ff00) >> 8, f);
706 put_char((wc & 0x000000ff), f);
710 return cnt;
714 static wchar_t *read_utf32le(struct mpdm_file *f, int *s)
716 return read_utf32ae(f, s, 1);
720 static int write_utf32le(struct mpdm_file *f, const wchar_t * str)
722 return write_utf32ae(f, str, 1);
726 static wchar_t *read_utf32be(struct mpdm_file *f, int *s)
728 return read_utf32ae(f, s, 0);
732 static int write_utf32be(struct mpdm_file *f, const wchar_t * str)
734 return write_utf32ae(f, str, 0);
738 static wchar_t *read_utf32(struct mpdm_file *f, int *s)
740 int c1, c2, c3, c4;
741 wchar_t *enc = L"utf-32le";
743 f->f_read = read_utf32le;
745 /* autodetection */
746 c1 = get_char(f);
747 c2 = get_char(f);
748 c3 = get_char(f);
749 c4 = get_char(f);
751 if (c1 == 0 && c2 == 0 && c3 == 0xfe && c4 == 0xff) {
752 enc = L"utf-32be";
753 f->f_read = read_utf32be;
755 if (c1 != 0xff || c2 != 0xfe || c3 != 0 || c4 != 0) {
756 /* no BOM; assume le and hope */
757 fseek(f->in, 0, SEEK_SET);
760 mpdm_hset_s(mpdm_root(), L"DETECTED_ENCODING", MPDM_LS(enc));
762 return f->f_read(f, s);
766 static int write_utf32le_bom(struct mpdm_file *f, const wchar_t * str)
768 /* store the LE signature */
769 put_char(0xff, f);
770 put_char(0xfe, f);
771 put_char(0, f);
772 put_char(0, f);
774 /* we're 32le from now on */
775 f->f_write = write_utf32le;
777 return f->f_write(f, str);
781 static int write_utf32be_bom(struct mpdm_file *f, const wchar_t * str)
783 /* store the BE signature */
784 put_char(0, f);
785 put_char(0, f);
786 put_char(0xfe, f);
787 put_char(0xff, f);
789 /* we're 32be from now on */
790 f->f_write = write_utf32be;
792 return f->f_write(f, str);
796 static wchar_t *read_auto(struct mpdm_file *f, int *s)
797 /* autodetects different encodings based on the BOM */
799 wchar_t *enc = L"";
801 /* by default, multibyte reading */
802 f->f_read = read_mbs;
804 /* ensure seeking is possible */
805 if (f->in != NULL && fseek(f->in, 0, SEEK_CUR) != -1) {
806 int c;
808 c = get_char(f);
810 if (c == 0xff) {
811 /* can be utf32le or utf16le */
812 if (get_char(f) == 0xfe) {
813 /* if next 2 chars are 0x00, it's utf32; otherwise utf16 */
814 if (get_char(f) == 0x00 && get_char(f) == 0x00) {
815 enc = L"utf-32le";
816 f->f_read = read_utf32le;
817 goto got_encoding;
819 else {
820 /* rewind to 3rd character */
821 fseek(f->in, 2, SEEK_SET);
823 enc = L"utf-16le";
824 f->f_read = read_utf16le;
825 goto got_encoding;
829 else
830 if (c == 0x00) {
831 /* can be utf32be */
832 if (get_char(f) == 0x00 && get_char(f) == 0xfe
833 && get_char(f) == 0xff) {
834 enc = L"utf-32be";
835 f->f_read = read_utf32be;
836 goto got_encoding;
839 else
840 if (c == 0xfe) {
841 /* can be utf16be */
842 if (get_char(f) == 0xff) {
843 enc = L"utf-16be";
844 f->f_read = read_utf16be;
845 goto got_encoding;
848 else
849 if (c == 0xef) {
850 /* can be utf8 with BOM */
851 if (get_char(f) == 0xbb && get_char(f) == 0xbf) {
852 enc = L"utf-8bom";
853 f->f_read = read_utf8;
854 goto got_encoding;
857 else {
858 /* try if a first bunch of chars are valid UTF-8 */
859 int p = c;
860 int n = 10000;
861 int u = 0;
863 while (--n && (c = get_char(f)) != EOF) {
864 if ((c & 0xc0) == 0x80) {
865 if ((p & 0xc0) == 0xc0)
866 u++;
867 else
868 if ((p & 0x80) == 0x00) {
869 u = -1;
870 break;
873 else
874 if ((p & 0xc0) == 0xc0) {
875 u = -1;
876 break;
879 p = c;
882 if (u < 0) {
883 /* invalid utf-8; fall back to 8bit */
884 enc = L"8bit";
885 f->f_read = read_iso8859_1;
887 else
888 if (u > 0) {
889 /* utf-8 sequences found */
890 enc = L"utf-8";
891 f->f_read = read_utf8;
894 /* 7 bit ASCII: do nothing */
897 /* none of the above; restart */
898 fseek(f->in, 0, SEEK_SET);
901 got_encoding:
902 mpdm_hset_s(mpdm_root(), L"DETECTED_ENCODING", MPDM_LS(enc));
904 return f->f_read(f, s);
908 static mpdm_t new_mpdm_file(void)
909 /* creates a new file value */
911 mpdm_t v = NULL;
912 struct mpdm_file *fs;
913 mpdm_t e;
915 if ((fs = malloc(sizeof(struct mpdm_file))) == NULL)
916 return NULL;
918 memset(fs, '\0', sizeof(struct mpdm_file));
920 /* default I/O functions */
921 fs->f_read = read_auto;
922 fs->f_write = write_wcs;
924 #ifdef CONFOPT_ICONV
925 /* no iconv encodings by default */
926 fs->ic_enc = fs->ic_dec = (iconv_t) - 1;
927 #endif
929 if ((v =
930 mpdm_new(MPDM_FILE | MPDM_FREE, fs,
931 sizeof(struct mpdm_file))) == NULL) {
932 free(fs);
933 return NULL;
936 e = mpdm_hget_s(mpdm_root(), L"ENCODING");
938 if (mpdm_size(e) == 0)
939 e = mpdm_hget_s(mpdm_root(), L"TEMP_ENCODING");
941 if (mpdm_size(e)) {
943 wchar_t *enc = mpdm_string(e);
945 if (wcscmp(enc, L"utf-8") == 0) {
946 fs->f_read = read_utf8_bom;
947 fs->f_write = write_utf8;
949 else
950 if (wcscmp(enc, L"utf-8bom") == 0) {
951 fs->f_read = read_utf8_bom;
952 fs->f_write = write_utf8_bom;
954 else
955 if (wcscmp(enc, L"iso8859-1") == 0 ||
956 wcscmp(enc, L"8bit") == 0) {
957 fs->f_read = read_iso8859_1;
958 fs->f_write = write_iso8859_1;
960 else
961 if (wcscmp(enc, L"utf-16le") == 0) {
962 fs->f_read = read_utf16le;
963 fs->f_write = write_utf16le_bom;
965 else
966 if (wcscmp(enc, L"utf-16be") == 0) {
967 fs->f_read = read_utf16be;
968 fs->f_write = write_utf16be_bom;
970 else
971 if (wcscmp(enc, L"utf-16") == 0) {
972 fs->f_read = read_utf16;
973 fs->f_write = write_utf16le_bom;
975 else
976 if (wcscmp(enc, L"utf-32le") == 0) {
977 fs->f_read = read_utf32le;
978 fs->f_write = write_utf32le_bom;
980 else
981 if (wcscmp(enc, L"utf-32be") == 0) {
982 fs->f_read = read_utf32be;
983 fs->f_write = write_utf32be_bom;
985 else
986 if (wcscmp(enc, L"utf-32") == 0) {
987 fs->f_read = read_utf32;
988 fs->f_write = write_utf32le_bom;
990 else {
991 #ifdef CONFOPT_ICONV
992 mpdm_t cs = MPDM_2MBS(e->data);
994 if ((fs->ic_enc =
995 iconv_open((char *) cs->data, "WCHAR_T")) != (iconv_t) - 1
996 && (fs->ic_dec =
997 iconv_open("WCHAR_T",
998 (char *) cs->data)) != (iconv_t) - 1) {
1000 fs->f_read = read_iconv;
1001 fs->f_write = write_iconv;
1003 #endif /* CONFOPT_ICONV */
1006 mpdm_hset_s(mpdm_root(), L"TEMP_ENCODING", NULL);
1009 return v;
1013 static void destroy_mpdm_file(mpdm_t v)
1014 /* destroys and file value */
1016 struct mpdm_file *fs = (struct mpdm_file *) v->data;
1018 if (fs != NULL) {
1019 #ifdef CONFOPT_ICONV
1020 if (fs->ic_enc != (iconv_t) - 1) {
1021 iconv_close(fs->ic_enc);
1022 fs->ic_enc = (iconv_t) - 1;
1025 if (fs->ic_dec != (iconv_t) - 1) {
1026 iconv_close(fs->ic_dec);
1027 fs->ic_dec = (iconv_t) - 1;
1029 #endif
1031 free(fs);
1032 v->data = NULL;
1037 /** interface **/
1039 wchar_t *mpdm_read_mbs(FILE * f, int *s)
1040 /* reads a multibyte string from a stream into a dynamic string */
1042 struct mpdm_file fs;
1044 /* reset the structure */
1045 memset(&fs, '\0', sizeof(fs));
1046 fs.in = f;
1048 return read_mbs(&fs, s);
1052 int mpdm_write_wcs(FILE * f, const wchar_t * str)
1053 /* writes a wide string to a stream */
1055 struct mpdm_file fs;
1057 /* reset the structure */
1058 memset(&fs, '\0', sizeof(fs));
1059 fs.out = f;
1061 return write_wcs(&fs, str);
1065 mpdm_t mpdm_new_f(FILE * f)
1066 /* creates a new file value from a FILE * */
1068 mpdm_t v = NULL;
1070 if (f == NULL)
1071 return NULL;
1073 if ((v = new_mpdm_file()) != NULL) {
1074 struct mpdm_file *fs = (struct mpdm_file *) v->data;
1075 fs->in = fs->out = f;
1078 return v;
1083 * mpdm_open - Opens a file.
1084 * @filename: the file name
1085 * @mode: an fopen-like mode string
1087 * Opens a file. If @filename can be open in the specified @mode, an
1088 * mpdm_t value will be returned containing the file descriptor, or NULL
1089 * otherwise.
1091 * If the file is open for reading, some charset detection methods are
1092 * used. If any of them is successful, its name is stored in the
1093 * DETECTED_ENCODING element of the mpdm_root() hash. This value is
1094 * suitable to be copied over ENCODING or TEMP_ENCODING.
1096 * If the file is open for writing, the encoding to be used is read from
1097 * the ENCODING element of mpdm_root() and, if not set, from the
1098 * TEMP_ENCODING one. The latter will always be deleted afterwards.
1099 * [File Management]
1101 mpdm_t mpdm_open(const mpdm_t filename, const mpdm_t mode)
1103 FILE *f = NULL;
1104 mpdm_t fn;
1105 mpdm_t m;
1107 mpdm_ref(filename);
1108 mpdm_ref(mode);
1110 if (filename != NULL && mode != NULL) {
1112 /* convert to mbs,s */
1113 fn = mpdm_ref(MPDM_2MBS(filename->data));
1114 m = mpdm_ref(MPDM_2MBS(mode->data));
1116 if ((f = fopen((char *) fn->data, (char *) m->data)) == NULL)
1117 store_syserr();
1118 else {
1119 #if defined(CONFOPT_SYS_STAT_H) && defined(S_ISDIR) && defined(EISDIR)
1120 struct stat s;
1122 /* test if the open file is a directory */
1123 if (fstat(fileno(f), &s) != -1 && S_ISDIR(s.st_mode)) {
1124 /* it's a directory; fail */
1125 errno = EISDIR;
1126 store_syserr();
1127 fclose(f);
1128 f = NULL;
1130 #endif
1133 mpdm_unref(m);
1134 mpdm_unref(fn);
1137 mpdm_unref(mode);
1138 mpdm_unref(filename);
1140 return MPDM_F(f);
1145 * mpdm_close - Closes a file descriptor.
1146 * @fd: the value containing the file descriptor
1148 * Closes the file descriptor.
1149 * [File Management]
1151 mpdm_t mpdm_close(mpdm_t fd)
1153 struct mpdm_file *fs = (struct mpdm_file *) fd->data;
1155 mpdm_ref(fd);
1157 if ((fd->flags & MPDM_FILE) && fs != NULL) {
1158 if (fs->in != NULL)
1159 fclose(fs->in);
1161 if (fs->out != fs->in && fs->out != NULL)
1162 fclose(fs->out);
1164 destroy_mpdm_file(fd);
1167 fd = mpdm_unref(fd);
1169 return fd;
1174 * mpdm_read - Reads a line from a file descriptor.
1175 * @fd: the value containing the file descriptor
1177 * Reads a line from @fd. Returns the line, or NULL on EOF.
1178 * [File Management]
1179 * [Character Set Conversion]
1181 mpdm_t mpdm_read(const mpdm_t fd)
1183 mpdm_t v = NULL;
1184 wchar_t *ptr;
1185 int s;
1186 struct mpdm_file *fs = (struct mpdm_file *) fd->data;
1188 if (fs == NULL)
1189 return NULL;
1191 ptr = fs->f_read(fs, &s);
1193 if (ptr != NULL)
1194 v = MPDM_ENS(ptr, s);
1196 return v;
1200 mpdm_t mpdm_getchar(const mpdm_t fd)
1202 int c;
1203 wchar_t tmp[2];
1204 mpdm_t r = NULL;
1205 struct mpdm_file *fs = (struct mpdm_file *) fd->data;
1207 if (fs != NULL && (c = get_char(fs)) != EOF) {
1208 /* get the char as-is */
1209 tmp[0] = (wchar_t) c;
1210 tmp[1] = L'\0';
1212 r = MPDM_S(tmp);
1215 return r;
1219 int mpdm_putchar(const mpdm_t fd, const mpdm_t c)
1221 struct mpdm_file *fs = (struct mpdm_file *) fd->data;
1222 const wchar_t *ptr = mpdm_string(c);
1223 int r = 1;
1225 mpdm_ref(c);
1227 if (fs == NULL || put_char(*ptr, fs) == -1)
1228 r = 0;
1230 mpdm_unref(c);
1232 return r;
1237 * mpdm_write - Writes a value into a file.
1238 * @fd: the file descriptor.
1239 * @v: the value to be written.
1241 * Writes the @v string value into @fd, using the current encoding.
1242 * [File Management]
1243 * [Character Set Conversion]
1245 int mpdm_write(const mpdm_t fd, const mpdm_t v)
1247 struct mpdm_file *fs = (struct mpdm_file *) fd->data;
1248 int ret = -1;
1250 mpdm_ref(v);
1252 if (fs != NULL)
1253 ret = fs->f_write(fs, mpdm_string(v));
1255 mpdm_unref(v);
1257 return ret;
1261 int mpdm_fseek(const mpdm_t fd, long offset, int whence)
1263 struct mpdm_file *fs = (struct mpdm_file *) fd->data;
1265 return fseek(fs->in, offset, whence);
1269 long mpdm_ftell(const mpdm_t fd)
1271 struct mpdm_file *fs = (struct mpdm_file *) fd->data;
1273 return ftell(fs->in);
1277 FILE *mpdm_get_filehandle(const mpdm_t fd)
1279 FILE *f = NULL;
1281 if (fd->flags & MPDM_FILE && fd->data != NULL) {
1282 struct mpdm_file *fs = (struct mpdm_file *) fd->data;
1283 f = fs->in;
1286 return f;
1291 mpdm_t mpdm_bread(mpdm_t fd, int size)
1296 int mpdm_bwrite(mpdm_tfd, mpdm_t v, int size)
1302 static mpdm_t embedded_encodings(void)
1304 mpdm_t e;
1305 wchar_t *e2e[] = {
1306 L"utf-8", L"utf-8",
1307 L"utf8", NULL,
1308 L"iso8859-1", L"iso8859-1",
1309 L"iso-8859-1", NULL,
1310 L"8bit", NULL,
1311 L"latin1", NULL,
1312 L"latin-1", NULL,
1313 L"utf-16le", L"utf-16le",
1314 L"utf16le", NULL,
1315 L"ucs-2le", NULL,
1316 L"utf-16be", L"utf-16be",
1317 L"utf16be", NULL,
1318 L"ucs-2be", NULL,
1319 L"utf-16", L"utf-16",
1320 L"utf16", NULL,
1321 L"ucs-2", NULL,
1322 L"ucs2", NULL,
1323 L"utf-32le", L"utf-32le",
1324 L"utf32le", NULL,
1325 L"ucs-4le", NULL,
1326 L"utf-32be", L"utf-32be",
1327 L"utf32be", NULL,
1328 L"ucs-4be", NULL,
1329 L"utf-32", L"utf-32",
1330 L"utf32", NULL,
1331 L"ucs-4", NULL,
1332 L"ucs4", NULL,
1333 L"utf-8bom", L"utf-8bom",
1334 L"utf8bom", NULL,
1335 NULL, NULL
1338 if ((e = mpdm_hget_s(mpdm_root(), L"EMBEDDED_ENCODINGS")) == NULL) {
1339 int n;
1340 mpdm_t p = NULL;
1342 e = mpdm_ref(MPDM_H(0));
1344 for (n = 0; e2e[n] != NULL; n += 2) {
1345 mpdm_t v = MPDM_S(e2e[n]);
1347 if (e2e[n + 1] != NULL)
1348 p = MPDM_S(e2e[n + 1]);
1350 mpdm_hset(e, v, p);
1351 mpdm_hset(e, mpdm_ulc(v, 1), p);
1354 mpdm_hset_s(mpdm_root(), L"EMBEDDED_ENCODINGS", e);
1356 mpdm_unref(e);
1359 return e;
1364 * mpdm_encoding - Sets the current charset encoding for files.
1365 * @charset: the charset name.
1367 * Sets the current charset encoding for files. Future opened
1368 * files will be assumed to be encoded with @charset, which can
1369 * be any of the supported charset names (utf-8, iso-8859-1, etc.),
1370 * and converted on each read / write. If charset is NULL, it
1371 * is reverted to default charset conversion (i.e. the one defined
1372 * in the locale).
1374 * This function stores the @charset value into the ENCODING item
1375 * of the mpdm_root() hash.
1377 * Returns a negative number if @charset is unsupported, or zero
1378 * if no errors were found.
1379 * [File Management]
1380 * [Character Set Conversion]
1382 int mpdm_encoding(mpdm_t charset)
1384 int ret = -1;
1385 mpdm_t e = embedded_encodings();
1386 mpdm_t v = NULL;
1388 mpdm_ref(charset);
1390 /* NULL encoding? done */
1391 if (mpdm_size(charset) == 0) {
1392 mpdm_hset_s(mpdm_root(), L"ENCODING", NULL);
1393 ret = 0;
1396 #ifdef CONFOPT_ICONV
1397 else {
1398 iconv_t ic;
1399 mpdm_t cs = mpdm_ref(MPDM_2MBS(charset->data));
1401 /* tries to create an iconv encoder and decoder for this charset */
1403 if ((ic =
1404 iconv_open("WCHAR_T", (char *) cs->data)) == (iconv_t) - 1)
1405 ret = -1;
1406 else {
1407 iconv_close(ic);
1409 if ((ic =
1410 iconv_open((char *) cs->data,
1411 "WCHAR_T")) == (iconv_t) - 1)
1412 ret = -2;
1413 else {
1414 iconv_close(ic);
1416 /* got a valid encoding */
1417 v = charset;
1418 ret = 0;
1422 mpdm_unref(cs);
1424 #endif /* CONFOPT_ICONV */
1426 if (ret != 0 && (v = mpdm_hget(e, charset)) != NULL)
1427 ret = 0;
1429 if (ret == 0)
1430 mpdm_hset_s(mpdm_root(), L"ENCODING", v);
1432 mpdm_unref(charset);
1434 return ret;
1439 * mpdm_unlink - Deletes a file.
1440 * @filename: file name to be deleted
1442 * Deletes a file.
1443 * [File Management]
1445 int mpdm_unlink(const mpdm_t filename)
1447 int ret;
1448 mpdm_t fn;
1450 mpdm_ref(filename);
1452 /* convert to mbs */
1453 fn = mpdm_ref(MPDM_2MBS(filename->data));
1455 if ((ret = unlink((char *) fn->data)) == -1)
1456 store_syserr();
1458 mpdm_unref(fn);
1459 mpdm_unref(filename);
1461 return ret;
1466 * mpdm_stat - Gives status from a file.
1467 * @filename: file name to get the status from
1469 * Returns a 14 element array of the status (permissions, onwer, etc.)
1470 * from the desired @filename, or NULL if the file cannot be accessed.
1471 * (man 2 stat).
1473 * The values are: 0, device number of filesystem; 1, inode number;
1474 * 2, file mode; 3, number of hard links to the file; 4, uid; 5, gid;
1475 * 6, device identifier; 7, total size of file in bytes; 8, atime;
1476 * 9, mtime; 10, ctime; 11, preferred block size for system I/O;
1477 * 12, number of blocks allocated and 13, canonicalized file name.
1478 * Not all elements have necesarily meaningful values, as most are
1479 * system-dependent.
1480 * [File Management]
1482 mpdm_t mpdm_stat(const mpdm_t filename)
1484 mpdm_t r = NULL;
1486 mpdm_ref(filename);
1488 #ifdef CONFOPT_SYS_STAT_H
1489 struct stat s;
1490 mpdm_t fn;
1492 fn = mpdm_ref(MPDM_2MBS(filename->data));
1494 if (stat((char *) fn->data, &s) != -1) {
1495 r = MPDM_A(14);
1497 mpdm_ref(r);
1499 mpdm_aset(r, MPDM_I(s.st_dev), 0);
1500 mpdm_aset(r, MPDM_I(s.st_ino), 1);
1501 mpdm_aset(r, MPDM_I(s.st_mode), 2);
1502 mpdm_aset(r, MPDM_I(s.st_nlink), 3);
1503 mpdm_aset(r, MPDM_I(s.st_uid), 4);
1504 mpdm_aset(r, MPDM_I(s.st_gid), 5);
1505 mpdm_aset(r, MPDM_I(s.st_rdev), 6);
1506 mpdm_aset(r, MPDM_I(s.st_size), 7);
1507 mpdm_aset(r, MPDM_I(s.st_atime), 8);
1508 mpdm_aset(r, MPDM_I(s.st_mtime), 9);
1509 mpdm_aset(r, MPDM_I(s.st_ctime), 10);
1510 mpdm_aset(r, MPDM_I(0), 11); /* s.st_blksize */
1511 mpdm_aset(r, MPDM_I(0), 12); /* s.st_blocks */
1513 #ifdef CONFOPT_CANONICALIZE_FILE_NAME
1516 char *ptr;
1518 if ((ptr = canonicalize_file_name((char *) fn->data)) != NULL) {
1519 mpdm_aset(r, MPDM_MBS(ptr), 13);
1520 free(ptr);
1523 #endif
1525 #ifdef CONFOPT_REALPATH
1527 char tmp[2048];
1529 if (realpath((char *) fn->data, tmp) != NULL)
1530 mpdm_aset(r, MPDM_MBS(tmp), 13);
1532 #endif
1534 #ifdef CONFOPT_FULLPATH
1536 char tmp[_MAX_PATH + 1];
1538 if (_fullpath(tmp, (char *) fn->data, _MAX_PATH) != NULL)
1539 mpdm_aset(r, MPDM_MBS(tmp), 13);
1541 #endif
1543 mpdm_unrefnd(r);
1545 else
1546 store_syserr();
1548 mpdm_unref(fn);
1550 #endif /* CONFOPT_SYS_STAT_H */
1552 mpdm_unref(filename);
1554 return r;
1559 * mpdm_chmod - Changes a file's permissions.
1560 * @filename: the file name
1561 * @perms: permissions (element 2 from mpdm_stat())
1563 * Changes the permissions for a file.
1564 * [File Management]
1566 int mpdm_chmod(const mpdm_t filename, mpdm_t perms)
1568 int r = -1;
1570 mpdm_ref(filename);
1571 mpdm_ref(perms);
1573 mpdm_t fn = mpdm_ref(MPDM_2MBS(filename->data));
1575 if ((r = chmod((char *) fn->data, mpdm_ival(perms))) == -1)
1576 store_syserr();
1578 mpdm_unref(fn);
1579 mpdm_unref(perms);
1580 mpdm_unref(filename);
1582 return r;
1587 * mpdm_chdir - Changes the working directory
1588 * @dir: the new path
1590 * Changes the working directory
1591 * [File Management]
1593 int mpdm_chdir(const mpdm_t dir)
1595 int r = -1;
1597 mpdm_ref(dir);
1598 mpdm_t fn = mpdm_ref(MPDM_2MBS(dir->data));
1600 if ((r = chdir((char *) fn->data)) == -1)
1601 store_syserr();
1603 mpdm_unref(fn);
1604 mpdm_unref(dir);
1606 return r;
1611 * mpdm_chown - Changes a file's owner.
1612 * @filename: the file name
1613 * @uid: user id (element 4 from mpdm_stat())
1614 * @gid: group id (element 5 from mpdm_stat())
1616 * Changes the owner and group id's for a file.
1617 * [File Management]
1619 int mpdm_chown(const mpdm_t filename, mpdm_t uid, mpdm_t gid)
1621 int r = -1;
1623 mpdm_ref(filename);
1624 mpdm_ref(uid);
1625 mpdm_ref(gid);
1627 #ifdef CONFOPT_CHOWN
1629 mpdm_t fn = mpdm_ref(MPDM_2MBS(filename->data));
1631 if ((r =
1632 chown((char *) fn->data, mpdm_ival(uid), mpdm_ival(gid))) == -1)
1633 store_syserr();
1635 mpdm_unref(fn);
1637 #endif /* CONFOPT_CHOWN */
1639 mpdm_unref(gid);
1640 mpdm_unref(uid);
1641 mpdm_unref(filename);
1643 return r;
1648 * mpdm_glob - Executes a file globbing.
1649 * @spec: Globbing spec
1650 * @base: Optional base directory
1652 * Executes a file globbing. @spec is system-dependent, but usually
1653 * the * and ? metacharacters work everywhere. @base can contain a
1654 * directory; if that's the case, the output strings will include it.
1655 * In any case, each returned value will be suitable for a call to
1656 * mpdm_open().
1658 * Returns an array of files that match the globbing (can be an empty
1659 * array if no file matches), or NULL if globbing is unsupported.
1660 * [File Management]
1662 mpdm_t mpdm_glob(const mpdm_t spec, const mpdm_t base)
1664 mpdm_t d = NULL;
1665 mpdm_t f = NULL;
1666 mpdm_t v = NULL;
1668 mpdm_ref(spec);
1669 mpdm_ref(base);
1671 #ifdef CONFOPT_WIN32
1673 WIN32_FIND_DATA fd;
1674 HANDLE h;
1675 char *ptr;
1676 mpdm_t w;
1677 mpdm_t s = NULL;
1678 mpdm_t sp = NULL;
1680 /* add base */
1681 if (mpdm_size(base))
1682 sp = mpdm_strcat_s(base, L"/");
1684 /* add spec */
1685 w = mpdm_ref(sp);
1687 if (mpdm_size(spec) == 0)
1688 sp = mpdm_strcat_s(w, L"*.*");
1689 else
1690 sp = mpdm_strcat(w, spec);
1692 mpdm_unref(w);
1694 /* delete repeated directory delimiters */
1695 w = mpdm_ref(sp);
1696 sp = mpdm_sregex(w, MPDM_LS(L"@[\\/]+@g"), MPDM_LS(L"/"), 0);
1697 mpdm_unref(w);
1699 w = mpdm_ref(sp);
1700 sp = MPDM_2MBS(w->data);
1701 mpdm_unref(w);
1703 v = MPDM_A(0);
1704 d = mpdm_ref(MPDM_A(0));
1705 f = mpdm_ref(MPDM_A(0));
1706 mpdm_ref(sp);
1708 if ((h =
1709 FindFirstFile((char *) sp->data, &fd)) != INVALID_HANDLE_VALUE) {
1710 /* if spec includes a directory, store in s */
1711 if ((ptr = strrchr((char *) sp->data, '/')) != NULL) {
1712 *(ptr + 1) = '\0';
1713 s = MPDM_MBS(sp->data);
1716 do {
1717 /* ignore . and .. */
1718 if (strcmp(fd.cFileName, ".") == 0
1719 || strcmp(fd.cFileName, "..") == 0)
1720 continue;
1722 /* concat base directory and file names */
1723 w = mpdm_strcat(s, MPDM_MBS(fd.cFileName));
1725 /* if it's a directory, add a / */
1726 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1727 mpdm_t t = mpdm_ref(w);
1728 w = mpdm_strcat_s(t, L"/");
1729 mpdm_unref(t);
1731 mpdm_push(d, w);
1733 else
1734 mpdm_push(f, w);
1736 while (FindNextFile(h, &fd));
1738 FindClose(h);
1741 mpdm_unref(sp);
1743 #endif
1745 #if CONFOPT_GLOB_H
1747 /* glob.h support */
1748 glob_t globbuf;
1749 const char *ptr;
1750 mpdm_t w;
1752 /* build full path */
1753 if (mpdm_size(base))
1754 v = mpdm_strcat_s(base, L"/");
1756 w = mpdm_ref(v);
1758 if (mpdm_size(spec) == 0)
1759 v = mpdm_strcat_s(w, L"*");
1760 else
1761 v = mpdm_strcat(w, spec);
1763 mpdm_unref(w);
1765 /* delete repeated directory delimiters */
1766 w = mpdm_ref(v);
1767 v = mpdm_sregex(w, MPDM_LS(L"@/{2,}@g"), MPDM_LS(L"/"), 0);
1768 mpdm_unref(w);
1770 w = mpdm_ref(v);
1771 v = MPDM_2MBS(w->data);
1772 mpdm_unref(w);
1774 ptr = v->data;
1776 globbuf.gl_offs = 1;
1778 v = MPDM_A(0);
1779 d = mpdm_ref(MPDM_A(0));
1780 f = mpdm_ref(MPDM_A(0));
1782 if (glob(ptr, GLOB_MARK, NULL, &globbuf) == 0) {
1783 int n;
1785 for (n = 0; globbuf.gl_pathv[n] != NULL; n++) {
1786 char *ptr = globbuf.gl_pathv[n];
1787 mpdm_t t = MPDM_MBS(ptr);
1789 /* if last char is /, add to directories */
1790 if (ptr[strlen(ptr) - 1] == '/')
1791 mpdm_push(d, t);
1792 else
1793 mpdm_push(f, t);
1797 globfree(&globbuf);
1799 #else
1801 /* no win32 nor glob.h; try workaround */
1802 /* ... */
1804 #endif
1806 if (v != NULL) {
1807 int n;
1809 mpdm_sort(d, 1);
1810 mpdm_sort(f, 1);
1812 mpdm_ref(v);
1814 /* transfer all data in d and f */
1815 for (n = 0; n < mpdm_size(d); n++)
1816 mpdm_push(v, mpdm_aget(d, n));
1817 for (n = 0; n < mpdm_size(f); n++)
1818 mpdm_push(v, mpdm_aget(f, n));
1820 mpdm_unref(f);
1821 mpdm_unref(d);
1823 mpdm_unrefnd(v);
1826 mpdm_unref(base);
1827 mpdm_unref(spec);
1829 return v;
1833 #ifdef CONFOPT_WIN32
1835 static void win32_pipe(HANDLE * h, int n)
1837 SECURITY_ATTRIBUTES sa;
1838 HANDLE cp, t;
1840 memset(&sa, '\0', sizeof(sa));
1841 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
1842 sa.bInheritHandle = TRUE;
1843 sa.lpSecurityDescriptor = NULL;
1845 cp = GetCurrentProcess();
1847 CreatePipe(&h[0], &h[1], &sa, 0);
1848 DuplicateHandle(cp, h[n], cp, &t, 0, FALSE, DUPLICATE_SAME_ACCESS);
1849 CloseHandle(h[n]);
1850 h[n] = t;
1854 static int sysdep_popen(mpdm_t v, char *prg, int rw)
1855 /* win32-style pipe */
1857 HANDLE pr[2];
1858 HANDLE pw[2];
1859 PROCESS_INFORMATION pi;
1860 STARTUPINFO si;
1861 int ret;
1862 struct mpdm_file *fs = (struct mpdm_file *) v->data;
1864 /* init all */
1865 pr[0] = pr[1] = pw[0] = pw[1] = NULL;
1867 if (rw & 0x01)
1868 win32_pipe(pr, 0);
1869 if (rw & 0x02)
1870 win32_pipe(pw, 1);
1872 /* spawn new process */
1873 memset(&pi, '\0', sizeof(pi));
1874 memset(&si, '\0', sizeof(si));
1876 si.cb = sizeof(STARTUPINFO);
1877 si.hStdError = pr[1];
1878 si.hStdOutput = pr[1];
1879 si.hStdInput = pw[0];
1880 si.dwFlags |= STARTF_USESTDHANDLES;
1882 ret = CreateProcess(NULL, prg, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
1884 if (rw & 0x01)
1885 CloseHandle(pr[1]);
1886 if (rw & 0x02)
1887 CloseHandle(pw[0]);
1889 fs->hin = pr[0];
1890 fs->hout = pw[1];
1891 fs->process = pi.hProcess;
1893 return ret;
1897 static int sysdep_pclose(const mpdm_t v)
1899 struct mpdm_file *fs = (struct mpdm_file *) v->data;
1900 DWORD out = 0;
1902 if (fs->hin != NULL)
1903 CloseHandle(fs->hin);
1905 if (fs->hout != NULL)
1906 CloseHandle(fs->hout);
1908 /* waits until the process terminates */
1909 WaitForSingleObject(fs->process, 1000);
1910 GetExitCodeProcess(fs->process, &out);
1912 return (int) out;
1916 #else /* CONFOPT_WIN32 */
1918 static int sysdep_popen(mpdm_t v, char *prg, int rw)
1919 /* unix-style pipe open */
1921 int pr[2], pw[2];
1922 struct mpdm_file *fs = (struct mpdm_file *) v->data;
1924 /* init all */
1925 pr[0] = pr[1] = pw[0] = pw[1] = -1;
1927 if (rw & 0x01)
1928 pipe(pr);
1929 if (rw & 0x02)
1930 pipe(pw);
1932 if (fork() == 0) {
1933 /* child process */
1934 if (rw & 0x01) {
1935 close(1);
1936 dup(pr[1]);
1937 close(pr[0]);
1939 if (rw & 0x02) {
1940 close(0);
1941 dup(pw[0]);
1942 close(pw[1]);
1945 /* redirect stderr to stdout */
1946 close(2);
1947 dup(1);
1949 /* run the program */
1950 execlp("/bin/sh", "/bin/sh", "-c", prg, NULL);
1951 execlp(prg, prg, NULL);
1953 /* still here? exec failed; close pipes and exit */
1954 close(0);
1955 close(1);
1956 exit(0);
1959 /* create the pipes as non-buffered streams */
1960 if (rw & 0x01) {
1961 fs->in = fdopen(pr[0], "r");
1962 setvbuf(fs->in, NULL, _IONBF, 0);
1963 close(pr[1]);
1966 if (rw & 0x02) {
1967 fs->out = fdopen(pw[1], "w");
1968 setvbuf(fs->out, NULL, _IONBF, 0);
1969 close(pw[0]);
1972 return 1;
1976 static int sysdep_pclose(const mpdm_t v)
1977 /* unix-style pipe close */
1979 int s = 0;
1980 struct mpdm_file *fs = (struct mpdm_file *) v->data;
1982 if (fs->in != NULL)
1983 fclose(fs->in);
1985 if (fs->out != fs->in && fs->out != NULL)
1986 fclose(fs->out);
1988 wait(&s);
1990 return s;
1994 #endif /* CONFOPT_WIN32 */
1998 * mpdm_popen - Opens a pipe.
1999 * @prg: the program to pipe
2000 * @mode: an fopen-like mode string
2002 * Opens a pipe to a program. If @prg can be open in the specified @mode, an
2003 * mpdm_t value will be returned containing the file descriptor, or NULL
2004 * otherwise.
2005 * [File Management]
2007 mpdm_t mpdm_popen(const mpdm_t prg, const mpdm_t mode)
2009 mpdm_t v, pr, md;
2010 char *m;
2011 int rw = 0;
2013 mpdm_ref(prg);
2014 mpdm_ref(mode);
2016 if (prg != NULL && mode != NULL) {
2018 v = new_mpdm_file();
2020 /* convert to mbs,s */
2021 pr = mpdm_ref(MPDM_2MBS(prg->data));
2022 md = mpdm_ref(MPDM_2MBS(mode->data));
2024 /* get the mode */
2025 m = (char *) md->data;
2027 /* set the mode */
2028 if (m[0] == 'r')
2029 rw = 0x01;
2030 if (m[0] == 'w')
2031 rw = 0x02;
2032 if (m[1] == '+')
2033 rw = 0x03; /* r+ or w+ */
2035 if (!sysdep_popen(v, (char *) pr->data, rw)) {
2036 destroy_mpdm_file(v);
2037 mpdm_unref(mpdm_ref(v));
2038 v = NULL;
2041 mpdm_unref(md);
2042 mpdm_unref(pr);
2044 else
2045 v = NULL;
2047 mpdm_unref(mode);
2048 mpdm_unref(prg);
2050 return v;
2055 * mpdm_popen2 - Opens a pipe and returns 2 descriptors.
2056 * @prg: the program to pipe
2058 * Opens a read-write pipe and returns an array of two descriptors,
2059 * one for reading and one for writing. If @prg could not be piped to,
2060 * returns NULL.
2061 * [File Management]
2063 mpdm_t mpdm_popen2(const mpdm_t prg)
2065 mpdm_t i, o;
2066 mpdm_t p = NULL;
2068 if ((i = mpdm_popen(prg, MPDM_AS(L"r+"))) != NULL) {
2069 struct mpdm_file *ifs;
2070 struct mpdm_file *ofs;
2072 o = MPDM_C(i->flags, (void *)i->data, i->size);
2074 ifs = (struct mpdm_file *)i->data;
2075 ofs = (struct mpdm_file *)o->data;
2077 ofs->in = ifs->out;
2078 ifs->out = NULL;
2080 #ifdef CONFOPT_WIN32
2081 ofs->hin = ifs->hout;
2082 ifs->hout = NULL;
2083 #endif
2085 p = mpdm_ref(MPDM_A(2));
2086 mpdm_aset(p, i, 0);
2087 mpdm_aset(p, o, 1);
2088 mpdm_unrefnd(p);
2091 return p;
2096 * mpdm_pclose - Closes a pipe.
2097 * @fd: the value containing the file descriptor
2099 * Closes a pipe.
2100 * [File Management]
2102 mpdm_t mpdm_pclose(mpdm_t fd)
2104 mpdm_t r = NULL;
2106 mpdm_ref(fd);
2108 if ((fd->flags & MPDM_FILE) && fd->data != NULL) {
2109 r = MPDM_I(sysdep_pclose(fd));
2110 destroy_mpdm_file(fd);
2113 mpdm_unref(fd);
2115 return r;
2120 * mpdm_home_dir - Returns the home user directory.
2122 * Returns a system-dependent directory where the user can write
2123 * documents and create subdirectories.
2124 * [File Management]
2126 mpdm_t mpdm_home_dir(void)
2128 mpdm_t r = NULL;
2129 char *ptr;
2130 char tmp[512];
2132 tmp[0] = '\0';
2134 #ifdef CONFOPT_WIN32
2136 LPITEMIDLIST pidl;
2138 /* get the 'My Documents' folder */
2139 SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &pidl);
2140 SHGetPathFromIDList(pidl, tmp);
2141 strcat(tmp, "\\");
2143 #endif
2145 #ifdef CONFOPT_PWD_H
2147 struct passwd *p;
2149 /* get home dir from /etc/passwd entry */
2150 if (tmp[0] == '\0' && (p = getpwuid(getpid())) != NULL) {
2151 strcpy(tmp, p->pw_dir);
2152 strcat(tmp, "/");
2155 #endif
2157 /* still none? try the ENV variable $HOME */
2158 if (tmp[0] == '\0' && (ptr = getenv("HOME")) != NULL) {
2159 strcpy(tmp, ptr);
2160 strcat(tmp, "/");
2163 if (tmp[0] != '\0')
2164 r = MPDM_MBS(tmp);
2166 return r;
2171 * mpdm_app_dir - Returns the applications directory.
2173 * Returns a system-dependent directory where the applications store
2174 * their private data, as components or resources.
2175 * [File Management]
2177 mpdm_t mpdm_app_dir(void)
2179 mpdm_t r = NULL;
2181 #ifdef CONFOPT_WIN32
2183 HKEY hkey;
2184 char tmp[MAX_PATH];
2185 LPITEMIDLIST pidl;
2187 /* get the 'Program Files' folder (can fail) */
2188 tmp[0] = '\0';
2189 if (SHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidl) ==
2190 S_OK)
2191 SHGetPathFromIDList(pidl, tmp);
2193 /* if it's still empty, get from the registry */
2194 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
2195 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
2196 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS) {
2197 int n = sizeof(tmp);
2199 if (RegQueryValueEx(hkey, "ProgramFilesDir",
2200 NULL, NULL, tmp,
2201 (LPDWORD) & n) != ERROR_SUCCESS)
2202 tmp[0] = '\0';
2205 if (tmp[0] != '\0') {
2206 strcat(tmp, "\\");
2207 r = MPDM_MBS(tmp);
2209 #endif
2211 /* still none? get the configured directory */
2212 if (r == NULL)
2213 r = MPDM_MBS(CONFOPT_PREFIX "/share/");
2215 return r;