Protected mpdm.h from re-including.
[mpdm.git] / mpdm_f.c
blobf12bc6750c58e6b09b92b3e7240bdbba34d4456d
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 #endif /* CONFOPT_WIN32 */
94 #include <errno.h>
95 extern int errno;
98 /** code **/
101 static void store_syserr(void)
102 /* stores the system error inside the global ERRNO */
104 mpdm_hset_s(mpdm_root(), L"ERRNO", MPDM_MBS(strerror(errno)));
108 static int get_char(struct mpdm_file *f)
109 /* reads a character from a file structure */
111 int c = EOF;
113 #ifdef CONFOPT_WIN32
115 if (f->hin != NULL) {
116 char tmp;
117 DWORD n;
119 if (ReadFile(f->hin, &tmp, 1, &n, NULL) && n > 0)
120 c = (int) tmp;
123 #endif /* CONFOPT_WIN32 */
125 if (f->in != NULL) {
126 /* read (converting to positive if needed) */
127 if ((c = fgetc(f->in)) < 0 && !feof(f->in))
128 c += 256;
131 return c;
135 static int put_buf(const char *ptr, int s, struct mpdm_file *f)
136 /* writes s bytes in the buffer in ptr to f */
138 #ifdef CONFOPT_WIN32
140 if (f->hout != NULL) {
141 DWORD n;
143 if (WriteFile(f->hout, ptr, s, &n, NULL) && n > 0)
144 s = n;
146 else
147 #endif /* CONFOPT_WIN32 */
149 if (f->out != NULL)
150 s = fwrite(ptr, s, 1, f->out);
152 return s;
156 static int put_char(int c, struct mpdm_file *f)
157 /* writes a character in a file structure */
159 char tmp = c;
161 if (put_buf(&tmp, 1, f) != 1)
162 c = EOF;
164 return c;
168 static wchar_t *read_mbs(struct mpdm_file *f, int *s)
169 /* reads a multibyte string from a mpdm_file into a dynamic string */
171 wchar_t *ptr = NULL;
172 char *auxptr = NULL;
173 char tmp[100];
174 int c, i = 0, n = 0;
176 while ((c = get_char(f)) != EOF) {
177 tmp[i++] = c;
179 if (c == '\n')
180 break;
182 if (i == sizeof(tmp) - 1) {
183 /* out of space; start allocating */
184 if ((auxptr =
185 mpdm_poke(auxptr, &n, tmp, i, sizeof(char))) == NULL)
186 return NULL;
188 i = 0;
192 /* is there something to return? */
193 if (i || n) {
194 /* NULL-terminate */
195 tmp[i++] = '\0';
197 if (n) {
198 /* auxiliary space used; concat all */
199 if ((auxptr =
200 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(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(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(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(struct mpdm_file *f, int *s)
337 /* 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(struct mpdm_file *f, const wchar_t * str)
385 /* 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, SEEK_SET);
429 mpdm_hset_s(mpdm_root(), L"DETECTED_ENCODING", MPDM_LS(enc));
431 /* we're utf-8 from now on */
432 f->f_read = read_utf8;
434 return f->f_read(f, s);
438 static int write_utf8_bom(struct mpdm_file *f, const wchar_t * str)
439 /* utf-8 writer with BOM */
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(struct mpdm_file *f, int *s)
454 /* 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(struct mpdm_file *f, const wchar_t * str)
484 /* 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(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(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(struct mpdm_file *f, int *s)
563 return read_utf16ae(f, s, 1);
567 static int write_utf16le(struct mpdm_file *f, const wchar_t * str)
569 return write_utf16ae(f, str, 1);
573 static wchar_t *read_utf16be(struct mpdm_file *f, int *s)
575 return read_utf16ae(f, s, 0);
579 static int write_utf16be(struct mpdm_file *f, const wchar_t * str)
581 return write_utf16ae(f, str, 0);
585 static wchar_t *read_utf16(struct mpdm_file *f, int *s)
587 int c1, c2;
588 wchar_t *enc = L"utf-16le";
590 /* assume little-endian */
591 f->f_read = read_utf16le;
593 /* autodetection */
594 c1 = get_char(f);
595 c2 = get_char(f);
597 if (c1 == 0xfe && c2 == 0xff) {
598 enc = L"utf-16be";
599 f->f_read = read_utf16be;
601 else
602 if (c1 != 0xff || c2 != 0xfe) {
603 /* no BOM; rewind and hope */
604 fseek(f->in, 0, SEEK_SET);
607 mpdm_hset_s(mpdm_root(), L"DETECTED_ENCODING", MPDM_LS(enc));
609 return f->f_read(f, s);
613 static int write_utf16le_bom(struct mpdm_file *f, const wchar_t * str)
615 /* store the LE signature */
616 put_char(0xff, f);
617 put_char(0xfe, f);
619 /* we're 16le from now on */
620 f->f_write = write_utf16le;
622 return f->f_write(f, str);
626 static int write_utf16be_bom(struct mpdm_file *f, const wchar_t * str)
628 /* store the BE signature */
629 put_char(0xfe, f);
630 put_char(0xff, f);
632 /* we're 16be from now on */
633 f->f_write = write_utf16be;
635 return f->f_write(f, str);
639 static wchar_t *read_utf32ae(struct mpdm_file *f, int *s, int le)
640 /* utf32 reader, ANY ending */
642 wchar_t *ptr = NULL;
643 wchar_t wc;
644 int c1, c2, c3, c4;
646 *s = 0;
648 for (;;) {
649 wc = L'\0';
651 if ((c1 = get_char(f)) == EOF)
652 break;
654 if ((c2 = get_char(f)) == EOF)
655 break;
657 if ((c3 = get_char(f)) == EOF)
658 break;
660 if ((c4 = get_char(f)) == EOF)
661 break;
663 if (le)
664 wc = c1 | (c2 << 8) | (c3 << 16) | (c4 << 24);
665 else
666 wc = c4 | (c3 << 8) | (c2 << 16) | (c1 << 24);
668 /* store */
669 if ((ptr = mpdm_poke(ptr, s, &wc, 1, sizeof(wchar_t))) == NULL)
670 break;
672 /* if it's an end of line, finish */
673 if (wc == L'\n')
674 break;
677 if (ptr != NULL) {
678 ptr = mpdm_poke(ptr, s, L"", 1, sizeof(wchar_t));
679 (*s)--;
682 return ptr;
686 static int write_utf32ae(struct mpdm_file *f, const wchar_t * str, int le)
687 /* utf32 writer, ANY ending */
689 int cnt = 0;
690 wchar_t wc;
692 /* convert char by char */
693 for (; (wc = *str) != L'\0'; str++) {
695 if (le) {
696 put_char((wc & 0x000000ff), f);
697 put_char((wc & 0x0000ff00) >> 8, f);
698 put_char((wc & 0x00ff0000) >> 16, f);
699 put_char((wc & 0xff000000) >> 24, f);
701 else {
702 put_char((wc & 0xff000000) >> 24, f);
703 put_char((wc & 0x00ff0000) >> 16, f);
704 put_char((wc & 0x0000ff00) >> 8, f);
705 put_char((wc & 0x000000ff), f);
709 return cnt;
713 static wchar_t *read_utf32le(struct mpdm_file *f, int *s)
715 return read_utf32ae(f, s, 1);
719 static int write_utf32le(struct mpdm_file *f, const wchar_t * str)
721 return write_utf32ae(f, str, 1);
725 static wchar_t *read_utf32be(struct mpdm_file *f, int *s)
727 return read_utf32ae(f, s, 0);
731 static int write_utf32be(struct mpdm_file *f, const wchar_t * str)
733 return write_utf32ae(f, str, 0);
737 static wchar_t *read_utf32(struct mpdm_file *f, int *s)
739 int c1, c2, c3, c4;
740 wchar_t *enc = L"utf-32le";
742 f->f_read = read_utf32le;
744 /* autodetection */
745 c1 = get_char(f);
746 c2 = get_char(f);
747 c3 = get_char(f);
748 c4 = get_char(f);
750 if (c1 == 0 && c2 == 0 && c3 == 0xfe && c4 == 0xff) {
751 enc = L"utf-32be";
752 f->f_read = read_utf32be;
754 if (c1 != 0xff || c2 != 0xfe || c3 != 0 || c4 != 0) {
755 /* no BOM; assume le and hope */
756 fseek(f->in, 0, SEEK_SET);
759 mpdm_hset_s(mpdm_root(), L"DETECTED_ENCODING", MPDM_LS(enc));
761 return f->f_read(f, s);
765 static int write_utf32le_bom(struct mpdm_file *f, const wchar_t * str)
767 /* store the LE signature */
768 put_char(0xff, f);
769 put_char(0xfe, f);
770 put_char(0, f);
771 put_char(0, f);
773 /* we're 32le from now on */
774 f->f_write = write_utf32le;
776 return f->f_write(f, str);
780 static int write_utf32be_bom(struct mpdm_file *f, const wchar_t * str)
782 /* store the BE signature */
783 put_char(0, f);
784 put_char(0, f);
785 put_char(0xfe, f);
786 put_char(0xff, f);
788 /* we're 32be from now on */
789 f->f_write = write_utf32be;
791 return f->f_write(f, str);
795 static wchar_t *read_auto(struct mpdm_file *f, int *s)
796 /* autodetects different encodings based on the BOM */
798 wchar_t *enc = L"";
800 /* by default, multibyte reading */
801 f->f_read = read_mbs;
803 /* ensure seeking is possible */
804 if (f->in != NULL && fseek(f->in, 0, SEEK_CUR) != -1) {
805 int c;
807 c = get_char(f);
809 if (c == 0xff) {
810 /* can be utf32le or utf16le */
811 if (get_char(f) == 0xfe) {
812 /* if next 2 chars are 0x00, it's utf32; otherwise utf16 */
813 if (get_char(f) == 0x00 && get_char(f) == 0x00) {
814 enc = L"utf-32le";
815 f->f_read = read_utf32le;
816 goto got_encoding;
818 else {
819 /* rewind to 3rd character */
820 fseek(f->in, 2, SEEK_SET);
822 enc = L"utf-16le";
823 f->f_read = read_utf16le;
824 goto got_encoding;
828 else
829 if (c == 0x00) {
830 /* can be utf32be */
831 if (get_char(f) == 0x00 && get_char(f) == 0xfe
832 && get_char(f) == 0xff) {
833 enc = L"utf-32be";
834 f->f_read = read_utf32be;
835 goto got_encoding;
838 else
839 if (c == 0xfe) {
840 /* can be utf16be */
841 if (get_char(f) == 0xff) {
842 enc = L"utf-16be";
843 f->f_read = read_utf16be;
844 goto got_encoding;
847 else
848 if (c == 0xef) {
849 /* can be utf8 with BOM */
850 if (get_char(f) == 0xbb && get_char(f) == 0xbf) {
851 enc = L"utf-8bom";
852 f->f_read = read_utf8;
853 goto got_encoding;
856 else {
857 /* try if a first bunch of chars are valid UTF-8 */
858 int p = c;
859 int n = 10000;
860 int u = 0;
862 while (--n && (c = get_char(f)) != EOF) {
863 if ((c & 0xc0) == 0x80) {
864 if ((p & 0xc0) == 0xc0)
865 u++;
866 else
867 if ((p & 0x80) == 0x00) {
868 u = -1;
869 break;
872 else
873 if ((p & 0xc0) == 0xc0) {
874 u = -1;
875 break;
878 p = c;
881 if (u < 0) {
882 /* invalid utf-8; fall back to 8bit */
883 enc = L"8bit";
884 f->f_read = read_iso8859_1;
886 else
887 if (u > 0) {
888 /* utf-8 sequences found */
889 enc = L"utf-8";
890 f->f_read = read_utf8;
893 /* 7 bit ASCII: do nothing */
896 /* none of the above; restart */
897 fseek(f->in, 0, SEEK_SET);
900 got_encoding:
901 mpdm_hset_s(mpdm_root(), L"DETECTED_ENCODING", MPDM_LS(enc));
903 return f->f_read(f, s);
907 static mpdm_t new_mpdm_file(void)
908 /* creates a new file value */
910 mpdm_t v = NULL;
911 struct mpdm_file *fs;
912 mpdm_t e;
914 if ((fs = malloc(sizeof(struct mpdm_file))) == NULL)
915 return NULL;
917 memset(fs, '\0', sizeof(struct mpdm_file));
919 /* default I/O functions */
920 fs->f_read = read_auto;
921 fs->f_write = write_wcs;
923 #ifdef CONFOPT_ICONV
924 /* no iconv encodings by default */
925 fs->ic_enc = fs->ic_dec = (iconv_t) - 1;
926 #endif
928 if ((v =
929 mpdm_new(MPDM_FILE | MPDM_FREE, fs,
930 sizeof(struct mpdm_file))) == NULL) {
931 free(fs);
932 return NULL;
935 e = mpdm_hget_s(mpdm_root(), L"ENCODING");
937 if (mpdm_size(e) == 0)
938 e = mpdm_hget_s(mpdm_root(), L"TEMP_ENCODING");
940 if (mpdm_size(e)) {
942 wchar_t *enc = mpdm_string(e);
944 if (wcscmp(enc, L"utf-8") == 0) {
945 fs->f_read = read_utf8_bom;
946 fs->f_write = write_utf8;
948 else
949 if (wcscmp(enc, L"utf-8bom") == 0) {
950 fs->f_read = read_utf8_bom;
951 fs->f_write = write_utf8_bom;
953 else
954 if (wcscmp(enc, L"iso8859-1") == 0 ||
955 wcscmp(enc, L"8bit") == 0) {
956 fs->f_read = read_iso8859_1;
957 fs->f_write = write_iso8859_1;
959 else
960 if (wcscmp(enc, L"utf-16le") == 0) {
961 fs->f_read = read_utf16le;
962 fs->f_write = write_utf16le_bom;
964 else
965 if (wcscmp(enc, L"utf-16be") == 0) {
966 fs->f_read = read_utf16be;
967 fs->f_write = write_utf16be_bom;
969 else
970 if (wcscmp(enc, L"utf-16") == 0) {
971 fs->f_read = read_utf16;
972 fs->f_write = write_utf16le_bom;
974 else
975 if (wcscmp(enc, L"utf-32le") == 0) {
976 fs->f_read = read_utf32le;
977 fs->f_write = write_utf32le_bom;
979 else
980 if (wcscmp(enc, L"utf-32be") == 0) {
981 fs->f_read = read_utf32be;
982 fs->f_write = write_utf32be_bom;
984 else
985 if (wcscmp(enc, L"utf-32") == 0) {
986 fs->f_read = read_utf32;
987 fs->f_write = write_utf32le_bom;
989 else {
990 #ifdef CONFOPT_ICONV
991 mpdm_t cs = MPDM_2MBS(e->data);
993 if ((fs->ic_enc =
994 iconv_open((char *) cs->data, "WCHAR_T")) != (iconv_t) - 1
995 && (fs->ic_dec =
996 iconv_open("WCHAR_T",
997 (char *) cs->data)) != (iconv_t) - 1) {
999 fs->f_read = read_iconv;
1000 fs->f_write = write_iconv;
1002 #endif /* CONFOPT_ICONV */
1005 mpdm_hset_s(mpdm_root(), L"TEMP_ENCODING", NULL);
1008 return v;
1012 static void destroy_mpdm_file(mpdm_t v)
1013 /* destroys and file value */
1015 struct mpdm_file *fs = (struct mpdm_file *) v->data;
1017 if (fs != NULL) {
1018 #ifdef CONFOPT_ICONV
1019 if (fs->ic_enc != (iconv_t) - 1) {
1020 iconv_close(fs->ic_enc);
1021 fs->ic_enc = (iconv_t) - 1;
1024 if (fs->ic_dec != (iconv_t) - 1) {
1025 iconv_close(fs->ic_dec);
1026 fs->ic_dec = (iconv_t) - 1;
1028 #endif
1030 free(fs);
1031 v->data = NULL;
1036 /** interface **/
1038 wchar_t *mpdm_read_mbs(FILE * f, int *s)
1039 /* reads a multibyte string from a stream into a dynamic string */
1041 struct mpdm_file fs;
1043 /* reset the structure */
1044 memset(&fs, '\0', sizeof(fs));
1045 fs.in = f;
1047 return read_mbs(&fs, s);
1051 int mpdm_write_wcs(FILE * f, const wchar_t * str)
1052 /* writes a wide string to a stream */
1054 struct mpdm_file fs;
1056 /* reset the structure */
1057 memset(&fs, '\0', sizeof(fs));
1058 fs.out = f;
1060 return write_wcs(&fs, str);
1064 mpdm_t mpdm_new_f(FILE * f)
1065 /* creates a new file value from a FILE * */
1067 mpdm_t v = NULL;
1069 if (f == NULL)
1070 return NULL;
1072 if ((v = new_mpdm_file()) != NULL) {
1073 struct mpdm_file *fs = (struct mpdm_file *) v->data;
1074 fs->in = fs->out = f;
1077 return v;
1082 * mpdm_open - Opens a file.
1083 * @filename: the file name
1084 * @mode: an fopen-like mode string
1086 * Opens a file. If @filename can be open in the specified @mode, an
1087 * mpdm_t value will be returned containing the file descriptor, or NULL
1088 * otherwise.
1090 * If the file is open for reading, some charset detection methods are
1091 * used. If any of them is successful, its name is stored in the
1092 * DETECTED_ENCODING element of the mpdm_root() hash. This value is
1093 * suitable to be copied over ENCODING or TEMP_ENCODING.
1095 * If the file is open for writing, the encoding to be used is read from
1096 * the ENCODING element of mpdm_root() and, if not set, from the
1097 * TEMP_ENCODING one. The latter will always be deleted afterwards.
1098 * [File Management]
1100 mpdm_t mpdm_open(const mpdm_t filename, const mpdm_t mode)
1102 FILE *f = NULL;
1103 mpdm_t fn;
1104 mpdm_t m;
1106 mpdm_ref(filename);
1107 mpdm_ref(mode);
1109 if (filename != NULL && mode != NULL) {
1111 /* convert to mbs,s */
1112 fn = mpdm_ref(MPDM_2MBS(filename->data));
1113 m = mpdm_ref(MPDM_2MBS(mode->data));
1115 if ((f = fopen((char *) fn->data, (char *) m->data)) == NULL)
1116 store_syserr();
1117 else {
1118 #if defined(CONFOPT_SYS_STAT_H) && defined(S_ISDIR) && defined(EISDIR)
1119 struct stat s;
1121 /* test if the open file is a directory */
1122 if (fstat(fileno(f), &s) != -1 && S_ISDIR(s.st_mode)) {
1123 /* it's a directory; fail */
1124 errno = EISDIR;
1125 store_syserr();
1126 fclose(f);
1127 f = NULL;
1129 #endif
1132 mpdm_unref(m);
1133 mpdm_unref(fn);
1136 mpdm_unref(mode);
1137 mpdm_unref(filename);
1139 return MPDM_F(f);
1144 * mpdm_close - Closes a file descriptor.
1145 * @fd: the value containing the file descriptor
1147 * Closes the file descriptor.
1148 * [File Management]
1150 mpdm_t mpdm_close(mpdm_t fd)
1152 struct mpdm_file *fs = (struct mpdm_file *) fd->data;
1154 mpdm_ref(fd);
1156 if ((fd->flags & MPDM_FILE) && fs != NULL) {
1157 if (fs->in != NULL)
1158 fclose(fs->in);
1160 if (fs->out != fs->in && fs->out != NULL)
1161 fclose(fs->out);
1163 destroy_mpdm_file(fd);
1166 fd = mpdm_unref(fd);
1168 return fd;
1173 * mpdm_read - Reads a line from a file descriptor.
1174 * @fd: the value containing the file descriptor
1176 * Reads a line from @fd. Returns the line, or NULL on EOF.
1177 * [File Management]
1178 * [Character Set Conversion]
1180 mpdm_t mpdm_read(const mpdm_t fd)
1182 mpdm_t v = NULL;
1183 wchar_t *ptr;
1184 int s;
1185 struct mpdm_file *fs = (struct mpdm_file *) fd->data;
1187 if (fs == NULL)
1188 return NULL;
1190 ptr = fs->f_read(fs, &s);
1192 if (ptr != NULL)
1193 v = MPDM_ENS(ptr, s);
1195 return v;
1199 mpdm_t mpdm_getchar(const mpdm_t fd)
1201 int c;
1202 wchar_t tmp[2];
1203 mpdm_t r = NULL;
1204 struct mpdm_file *fs = (struct mpdm_file *) fd->data;
1206 if (fs != NULL && (c = get_char(fs)) != EOF) {
1207 /* get the char as-is */
1208 tmp[0] = (wchar_t) c;
1209 tmp[1] = L'\0';
1211 r = MPDM_S(tmp);
1214 return r;
1218 int mpdm_putchar(const mpdm_t fd, const mpdm_t c)
1220 struct mpdm_file *fs = (struct mpdm_file *) fd->data;
1221 const wchar_t *ptr = mpdm_string(c);
1222 int r = 1;
1224 mpdm_ref(c);
1226 if (fs == NULL || put_char(*ptr, fs) == -1)
1227 r = 0;
1229 mpdm_unref(c);
1231 return r;
1236 * mpdm_write - Writes a value into a file.
1237 * @fd: the file descriptor.
1238 * @v: the value to be written.
1240 * Writes the @v string value into @fd, using the current encoding.
1241 * [File Management]
1242 * [Character Set Conversion]
1244 int mpdm_write(const mpdm_t fd, const mpdm_t v)
1246 struct mpdm_file *fs = (struct mpdm_file *) fd->data;
1247 int ret = -1;
1249 mpdm_ref(v);
1251 if (fs != NULL)
1252 ret = fs->f_write(fs, mpdm_string(v));
1254 mpdm_unref(v);
1256 return ret;
1260 int mpdm_fseek(const mpdm_t fd, long offset, int whence)
1262 struct mpdm_file *fs = (struct mpdm_file *) fd->data;
1264 return fseek(fs->in, offset, whence);
1268 long mpdm_ftell(const mpdm_t fd)
1270 struct mpdm_file *fs = (struct mpdm_file *) fd->data;
1272 return ftell(fs->in);
1276 FILE *mpdm_get_filehandle(const mpdm_t fd)
1278 FILE *f = NULL;
1280 if (fd->flags & MPDM_FILE && fd->data != NULL) {
1281 struct mpdm_file *fs = (struct mpdm_file *) fd->data;
1282 f = fs->in;
1285 return f;
1290 mpdm_t mpdm_bread(mpdm_t fd, int size)
1295 int mpdm_bwrite(mpdm_tfd, mpdm_t v, int size)
1301 static mpdm_t embedded_encodings(void)
1303 mpdm_t e;
1304 wchar_t *e2e[] = {
1305 L"utf-8", L"utf-8",
1306 L"utf8", NULL,
1307 L"iso8859-1", L"iso8859-1",
1308 L"iso-8859-1", NULL,
1309 L"8bit", NULL,
1310 L"latin1", NULL,
1311 L"latin-1", NULL,
1312 L"utf-16le", L"utf-16le",
1313 L"utf16le", NULL,
1314 L"ucs-2le", NULL,
1315 L"utf-16be", L"utf-16be",
1316 L"utf16be", NULL,
1317 L"ucs-2be", NULL,
1318 L"utf-16", L"utf-16",
1319 L"utf16", NULL,
1320 L"ucs-2", NULL,
1321 L"ucs2", NULL,
1322 L"utf-32le", L"utf-32le",
1323 L"utf32le", NULL,
1324 L"ucs-4le", NULL,
1325 L"utf-32be", L"utf-32be",
1326 L"utf32be", NULL,
1327 L"ucs-4be", NULL,
1328 L"utf-32", L"utf-32",
1329 L"utf32", NULL,
1330 L"ucs-4", NULL,
1331 L"ucs4", NULL,
1332 L"utf-8bom", L"utf-8bom",
1333 L"utf8bom", NULL,
1334 NULL, NULL
1337 if ((e = mpdm_hget_s(mpdm_root(), L"EMBEDDED_ENCODINGS")) == NULL) {
1338 int n;
1339 mpdm_t p = NULL;
1341 e = mpdm_ref(MPDM_H(0));
1343 for (n = 0; e2e[n] != NULL; n += 2) {
1344 mpdm_t v = MPDM_S(e2e[n]);
1346 if (e2e[n + 1] != NULL)
1347 p = MPDM_S(e2e[n + 1]);
1349 mpdm_hset(e, v, p);
1350 mpdm_hset(e, mpdm_ulc(v, 1), p);
1353 mpdm_hset_s(mpdm_root(), L"EMBEDDED_ENCODINGS", e);
1355 mpdm_unref(e);
1358 return e;
1363 * mpdm_encoding - Sets the current charset encoding for files.
1364 * @charset: the charset name.
1366 * Sets the current charset encoding for files. Future opened
1367 * files will be assumed to be encoded with @charset, which can
1368 * be any of the supported charset names (utf-8, iso-8859-1, etc.),
1369 * and converted on each read / write. If charset is NULL, it
1370 * is reverted to default charset conversion (i.e. the one defined
1371 * in the locale).
1373 * This function stores the @charset value into the ENCODING item
1374 * of the mpdm_root() hash.
1376 * Returns a negative number if @charset is unsupported, or zero
1377 * if no errors were found.
1378 * [File Management]
1379 * [Character Set Conversion]
1381 int mpdm_encoding(mpdm_t charset)
1383 int ret = -1;
1384 mpdm_t e = embedded_encodings();
1385 mpdm_t v = NULL;
1387 mpdm_ref(charset);
1389 /* NULL encoding? done */
1390 if (mpdm_size(charset) == 0) {
1391 mpdm_hset_s(mpdm_root(), L"ENCODING", NULL);
1392 ret = 0;
1395 #ifdef CONFOPT_ICONV
1396 else {
1397 iconv_t ic;
1398 mpdm_t cs = mpdm_ref(MPDM_2MBS(charset->data));
1400 /* tries to create an iconv encoder and decoder for this charset */
1402 if ((ic =
1403 iconv_open("WCHAR_T", (char *) cs->data)) == (iconv_t) - 1)
1404 ret = -1;
1405 else {
1406 iconv_close(ic);
1408 if ((ic =
1409 iconv_open((char *) cs->data,
1410 "WCHAR_T")) == (iconv_t) - 1)
1411 ret = -2;
1412 else {
1413 iconv_close(ic);
1415 /* got a valid encoding */
1416 v = charset;
1417 ret = 0;
1421 mpdm_unref(cs);
1423 #endif /* CONFOPT_ICONV */
1425 if (ret != 0 && (v = mpdm_hget(e, charset)) != NULL)
1426 ret = 0;
1428 if (ret == 0)
1429 mpdm_hset_s(mpdm_root(), L"ENCODING", v);
1431 mpdm_unref(charset);
1433 return ret;
1438 * mpdm_unlink - Deletes a file.
1439 * @filename: file name to be deleted
1441 * Deletes a file.
1442 * [File Management]
1444 int mpdm_unlink(const mpdm_t filename)
1446 int ret;
1447 mpdm_t fn;
1449 mpdm_ref(filename);
1451 /* convert to mbs */
1452 fn = mpdm_ref(MPDM_2MBS(filename->data));
1454 if ((ret = unlink((char *) fn->data)) == -1)
1455 store_syserr();
1457 mpdm_unref(fn);
1458 mpdm_unref(filename);
1460 return ret;
1465 * mpdm_stat - Gives status from a file.
1466 * @filename: file name to get the status from
1468 * Returns a 14 element array of the status (permissions, onwer, etc.)
1469 * from the desired @filename, or NULL if the file cannot be accessed.
1470 * (man 2 stat).
1472 * The values are: 0, device number of filesystem; 1, inode number;
1473 * 2, file mode; 3, number of hard links to the file; 4, uid; 5, gid;
1474 * 6, device identifier; 7, total size of file in bytes; 8, atime;
1475 * 9, mtime; 10, ctime; 11, preferred block size for system I/O;
1476 * 12, number of blocks allocated and 13, canonicalized file name.
1477 * Not all elements have necesarily meaningful values, as most are
1478 * system-dependent.
1479 * [File Management]
1481 mpdm_t mpdm_stat(const mpdm_t filename)
1483 mpdm_t r = NULL;
1485 mpdm_ref(filename);
1487 #ifdef CONFOPT_SYS_STAT_H
1488 struct stat s;
1489 mpdm_t fn;
1491 fn = mpdm_ref(MPDM_2MBS(filename->data));
1493 if (stat((char *) fn->data, &s) != -1) {
1494 r = MPDM_A(14);
1496 mpdm_ref(r);
1498 mpdm_aset(r, MPDM_I(s.st_dev), 0);
1499 mpdm_aset(r, MPDM_I(s.st_ino), 1);
1500 mpdm_aset(r, MPDM_I(s.st_mode), 2);
1501 mpdm_aset(r, MPDM_I(s.st_nlink), 3);
1502 mpdm_aset(r, MPDM_I(s.st_uid), 4);
1503 mpdm_aset(r, MPDM_I(s.st_gid), 5);
1504 mpdm_aset(r, MPDM_I(s.st_rdev), 6);
1505 mpdm_aset(r, MPDM_I(s.st_size), 7);
1506 mpdm_aset(r, MPDM_I(s.st_atime), 8);
1507 mpdm_aset(r, MPDM_I(s.st_mtime), 9);
1508 mpdm_aset(r, MPDM_I(s.st_ctime), 10);
1509 mpdm_aset(r, MPDM_I(0), 11); /* s.st_blksize */
1510 mpdm_aset(r, MPDM_I(0), 12); /* s.st_blocks */
1512 #ifdef CONFOPT_CANONICALIZE_FILE_NAME
1515 char *ptr;
1517 if ((ptr = canonicalize_file_name((char *) fn->data)) != NULL) {
1518 mpdm_aset(r, MPDM_MBS(ptr), 13);
1519 free(ptr);
1522 #endif
1524 #ifdef CONFOPT_REALPATH
1526 char tmp[2048];
1528 if (realpath((char *) fn->data, tmp) != NULL)
1529 mpdm_aset(r, MPDM_MBS(tmp), 13);
1531 #endif
1533 #ifdef CONFOPT_FULLPATH
1535 char tmp[_MAX_PATH + 1];
1537 if (_fullpath(tmp, (char *) fn->data, _MAX_PATH) != NULL)
1538 mpdm_aset(r, MPDM_MBS(tmp), 13);
1540 #endif
1542 mpdm_unrefnd(r);
1544 else
1545 store_syserr();
1547 mpdm_unref(fn);
1549 #endif /* CONFOPT_SYS_STAT_H */
1551 mpdm_unref(filename);
1553 return r;
1558 * mpdm_chmod - Changes a file's permissions.
1559 * @filename: the file name
1560 * @perms: permissions (element 2 from mpdm_stat())
1562 * Changes the permissions for a file.
1563 * [File Management]
1565 int mpdm_chmod(const mpdm_t filename, mpdm_t perms)
1567 int r = -1;
1569 mpdm_ref(filename);
1570 mpdm_ref(perms);
1572 mpdm_t fn = mpdm_ref(MPDM_2MBS(filename->data));
1574 if ((r = chmod((char *) fn->data, mpdm_ival(perms))) == -1)
1575 store_syserr();
1577 mpdm_unref(fn);
1578 mpdm_unref(perms);
1579 mpdm_unref(filename);
1581 return r;
1586 * mpdm_chdir - Changes the working directory
1587 * @dir: the new path
1589 * Changes the working directory
1590 * [File Management]
1592 int mpdm_chdir(const mpdm_t dir)
1594 int r = -1;
1596 mpdm_ref(dir);
1597 mpdm_t fn = mpdm_ref(MPDM_2MBS(dir->data));
1599 if ((r = chdir((char *) fn->data)) == -1)
1600 store_syserr();
1602 mpdm_unref(fn);
1603 mpdm_unref(dir);
1605 return r;
1610 * mpdm_chown - Changes a file's owner.
1611 * @filename: the file name
1612 * @uid: user id (element 4 from mpdm_stat())
1613 * @gid: group id (element 5 from mpdm_stat())
1615 * Changes the owner and group id's for a file.
1616 * [File Management]
1618 int mpdm_chown(const mpdm_t filename, mpdm_t uid, mpdm_t gid)
1620 int r = -1;
1622 mpdm_ref(filename);
1623 mpdm_ref(uid);
1624 mpdm_ref(gid);
1626 #ifdef CONFOPT_CHOWN
1628 mpdm_t fn = mpdm_ref(MPDM_2MBS(filename->data));
1630 if ((r =
1631 chown((char *) fn->data, mpdm_ival(uid), mpdm_ival(gid))) == -1)
1632 store_syserr();
1634 mpdm_unref(fn);
1636 #endif /* CONFOPT_CHOWN */
1638 mpdm_unref(gid);
1639 mpdm_unref(uid);
1640 mpdm_unref(filename);
1642 return r;
1647 * mpdm_glob - Executes a file globbing.
1648 * @spec: Globbing spec
1649 * @base: Optional base directory
1651 * Executes a file globbing. @spec is system-dependent, but usually
1652 * the * and ? metacharacters work everywhere. @base can contain a
1653 * directory; if that's the case, the output strings will include it.
1654 * In any case, each returned value will be suitable for a call to
1655 * mpdm_open().
1657 * Returns an array of files that match the globbing (can be an empty
1658 * array if no file matches), or NULL if globbing is unsupported.
1659 * [File Management]
1661 mpdm_t mpdm_glob(const mpdm_t spec, const mpdm_t base)
1663 mpdm_t d = NULL;
1664 mpdm_t f = NULL;
1665 mpdm_t v = NULL;
1667 mpdm_ref(spec);
1668 mpdm_ref(base);
1670 #ifdef CONFOPT_WIN32
1672 WIN32_FIND_DATA fd;
1673 HANDLE h;
1674 char *ptr;
1675 mpdm_t w;
1676 mpdm_t s = NULL;
1677 mpdm_t sp = NULL;
1679 /* add base */
1680 if (mpdm_size(base))
1681 sp = mpdm_strcat_s(base, L"/");
1683 /* add spec */
1684 w = mpdm_ref(sp);
1686 if (mpdm_size(spec) == 0)
1687 sp = mpdm_strcat_s(w, L"*.*");
1688 else
1689 sp = mpdm_strcat(w, spec);
1691 mpdm_unref(w);
1693 /* delete repeated directory delimiters */
1694 w = mpdm_ref(sp);
1695 sp = mpdm_sregex(w, MPDM_LS(L"@[\\/]+@g"), MPDM_LS(L"/"), 0);
1696 mpdm_unref(w);
1698 w = mpdm_ref(sp);
1699 sp = MPDM_2MBS(w->data);
1700 mpdm_unref(w);
1702 v = MPDM_A(0);
1703 d = mpdm_ref(MPDM_A(0));
1704 f = mpdm_ref(MPDM_A(0));
1705 mpdm_ref(sp);
1707 if ((h =
1708 FindFirstFile((char *) sp->data, &fd)) != INVALID_HANDLE_VALUE) {
1709 /* if spec includes a directory, store in s */
1710 if ((ptr = strrchr((char *) sp->data, '/')) != NULL) {
1711 *(ptr + 1) = '\0';
1712 s = MPDM_MBS(sp->data);
1715 do {
1716 /* ignore . and .. */
1717 if (strcmp(fd.cFileName, ".") == 0
1718 || strcmp(fd.cFileName, "..") == 0)
1719 continue;
1721 /* concat base directory and file names */
1722 w = mpdm_strcat(s, MPDM_MBS(fd.cFileName));
1724 /* if it's a directory, add a / */
1725 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1726 mpdm_t t = mpdm_ref(w);
1727 w = mpdm_strcat_s(t, L"/");
1728 mpdm_unref(t);
1730 mpdm_push(d, w);
1732 else
1733 mpdm_push(f, w);
1735 while (FindNextFile(h, &fd));
1737 FindClose(h);
1740 mpdm_unref(sp);
1742 #endif
1744 #if CONFOPT_GLOB_H
1746 /* glob.h support */
1747 glob_t globbuf;
1748 const char *ptr;
1749 mpdm_t w;
1751 /* build full path */
1752 if (mpdm_size(base))
1753 v = mpdm_strcat_s(base, L"/");
1755 w = mpdm_ref(v);
1757 if (mpdm_size(spec) == 0)
1758 v = mpdm_strcat_s(w, L"*");
1759 else
1760 v = mpdm_strcat(w, spec);
1762 mpdm_unref(w);
1764 /* delete repeated directory delimiters */
1765 w = mpdm_ref(v);
1766 v = mpdm_sregex(w, MPDM_LS(L"@/{2,}@g"), MPDM_LS(L"/"), 0);
1767 mpdm_unref(w);
1769 w = mpdm_ref(v);
1770 v = MPDM_2MBS(w->data);
1771 mpdm_unref(w);
1773 ptr = v->data;
1775 globbuf.gl_offs = 1;
1777 v = MPDM_A(0);
1778 d = mpdm_ref(MPDM_A(0));
1779 f = mpdm_ref(MPDM_A(0));
1781 if (glob(ptr, GLOB_MARK, NULL, &globbuf) == 0) {
1782 int n;
1784 for (n = 0; globbuf.gl_pathv[n] != NULL; n++) {
1785 char *ptr = globbuf.gl_pathv[n];
1786 mpdm_t t = MPDM_MBS(ptr);
1788 /* if last char is /, add to directories */
1789 if (ptr[strlen(ptr) - 1] == '/')
1790 mpdm_push(d, t);
1791 else
1792 mpdm_push(f, t);
1796 globfree(&globbuf);
1798 #else
1800 /* no win32 nor glob.h; try workaround */
1801 /* ... */
1803 #endif
1805 if (v != NULL) {
1806 int n;
1808 mpdm_sort(d, 1);
1809 mpdm_sort(f, 1);
1811 mpdm_ref(v);
1813 /* transfer all data in d and f */
1814 for (n = 0; n < mpdm_size(d); n++)
1815 mpdm_push(v, mpdm_aget(d, n));
1816 for (n = 0; n < mpdm_size(f); n++)
1817 mpdm_push(v, mpdm_aget(f, n));
1819 mpdm_unref(f);
1820 mpdm_unref(d);
1822 mpdm_unrefnd(v);
1825 mpdm_unref(base);
1826 mpdm_unref(spec);
1828 return v;
1832 #ifdef CONFOPT_WIN32
1834 static void win32_pipe(HANDLE * h, int n)
1836 SECURITY_ATTRIBUTES sa;
1837 HANDLE cp, t;
1839 memset(&sa, '\0', sizeof(sa));
1840 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
1841 sa.bInheritHandle = TRUE;
1842 sa.lpSecurityDescriptor = NULL;
1844 cp = GetCurrentProcess();
1846 CreatePipe(&h[0], &h[1], &sa, 0);
1847 DuplicateHandle(cp, h[n], cp, &t, 0, FALSE, DUPLICATE_SAME_ACCESS);
1848 CloseHandle(h[n]);
1849 h[n] = t;
1853 static int sysdep_popen(mpdm_t v, char *prg, int rw)
1854 /* win32-style pipe */
1856 HANDLE pr[2];
1857 HANDLE pw[2];
1858 PROCESS_INFORMATION pi;
1859 STARTUPINFO si;
1860 int ret;
1861 struct mpdm_file *fs = (struct mpdm_file *) v->data;
1863 /* init all */
1864 pr[0] = pr[1] = pw[0] = pw[1] = NULL;
1866 if (rw & 0x01)
1867 win32_pipe(pr, 0);
1868 if (rw & 0x02)
1869 win32_pipe(pw, 1);
1871 /* spawn new process */
1872 memset(&pi, '\0', sizeof(pi));
1873 memset(&si, '\0', sizeof(si));
1875 si.cb = sizeof(STARTUPINFO);
1876 si.hStdError = pr[1];
1877 si.hStdOutput = pr[1];
1878 si.hStdInput = pw[0];
1879 si.dwFlags |= STARTF_USESTDHANDLES;
1881 ret =
1882 CreateProcess(NULL, prg, NULL, NULL, TRUE, 0, NULL, NULL, &si,
1883 &pi);
1885 if (rw & 0x01)
1886 CloseHandle(pr[1]);
1887 if (rw & 0x02)
1888 CloseHandle(pw[0]);
1890 fs->hin = pr[0];
1891 fs->hout = pw[1];
1893 return ret;
1897 static int sysdep_pclose(const mpdm_t v)
1899 struct mpdm_file *fs = (struct mpdm_file *) v->data;
1901 if (fs->hin != NULL)
1902 CloseHandle(fs->hin);
1904 if (fs->hout != NULL)
1905 CloseHandle(fs->hout);
1907 /* how to know process exit code? */
1908 return 0;
1912 #else /* CONFOPT_WIN32 */
1914 static int sysdep_popen(mpdm_t v, char *prg, int rw)
1915 /* unix-style pipe open */
1917 int pr[2], pw[2];
1918 struct mpdm_file *fs = (struct mpdm_file *) v->data;
1920 /* init all */
1921 pr[0] = pr[1] = pw[0] = pw[1] = -1;
1923 if (rw & 0x01)
1924 pipe(pr);
1925 if (rw & 0x02)
1926 pipe(pw);
1928 if (fork() == 0) {
1929 /* child process */
1930 if (rw & 0x01) {
1931 close(1);
1932 dup(pr[1]);
1933 close(pr[0]);
1935 if (rw & 0x02) {
1936 close(0);
1937 dup(pw[0]);
1938 close(pw[1]);
1941 /* redirect stderr to stdout */
1942 close(2);
1943 dup(1);
1945 /* run the program */
1946 execlp("/bin/sh", "/bin/sh", "-c", prg, NULL);
1947 execlp(prg, prg, NULL);
1949 /* still here? exec failed; close pipes and exit */
1950 close(0);
1951 close(1);
1952 exit(0);
1955 /* create the pipes as non-buffered streams */
1956 if (rw & 0x01) {
1957 fs->in = fdopen(pr[0], "r");
1958 setvbuf(fs->in, NULL, _IONBF, 0);
1959 close(pr[1]);
1962 if (rw & 0x02) {
1963 fs->out = fdopen(pw[1], "w");
1964 setvbuf(fs->out, NULL, _IONBF, 0);
1965 close(pw[0]);
1968 return 1;
1972 static int sysdep_pclose(const mpdm_t v)
1973 /* unix-style pipe close */
1975 int s;
1976 struct mpdm_file *fs = (struct mpdm_file *) v->data;
1978 if (fs->in != NULL)
1979 fclose(fs->in);
1981 if (fs->out != fs->in && fs->out != NULL)
1982 fclose(fs->out);
1984 wait(&s);
1986 return s;
1990 #endif /* CONFOPT_WIN32 */
1994 * mpdm_popen - Opens a pipe.
1995 * @prg: the program to pipe
1996 * @mode: an fopen-like mode string
1998 * Opens a pipe to a program. If @prg can be open in the specified @mode, an
1999 * mpdm_t value will be returned containing the file descriptor, or NULL
2000 * otherwise.
2001 * [File Management]
2003 mpdm_t mpdm_popen(const mpdm_t prg, const mpdm_t mode)
2005 mpdm_t v, pr, md;
2006 char *m;
2007 int rw = 0;
2009 mpdm_ref(prg);
2010 mpdm_ref(mode);
2012 if (prg != NULL && mode != NULL) {
2014 v = new_mpdm_file();
2016 /* convert to mbs,s */
2017 pr = mpdm_ref(MPDM_2MBS(prg->data));
2018 md = mpdm_ref(MPDM_2MBS(mode->data));
2020 /* get the mode */
2021 m = (char *) md->data;
2023 /* set the mode */
2024 if (m[0] == 'r')
2025 rw = 0x01;
2026 if (m[0] == 'w')
2027 rw = 0x02;
2028 if (m[1] == '+')
2029 rw = 0x03; /* r+ or w+ */
2031 if (!sysdep_popen(v, (char *) pr->data, rw)) {
2032 destroy_mpdm_file(v);
2033 mpdm_unref(mpdm_ref(v));
2034 v = NULL;
2037 mpdm_unref(md);
2038 mpdm_unref(pr);
2040 else
2041 v = NULL;
2043 mpdm_unref(mode);
2044 mpdm_unref(prg);
2046 return v;
2051 * mpdm_popen2 - Opens a pipe and returns 2 descriptors.
2052 * @prg: the program to pipe
2054 * Opens a read-write pipe and returns an array of two descriptors,
2055 * one for reading and one for writing. If @prg could not be piped to,
2056 * returns NULL.
2057 * [File Management]
2059 mpdm_t mpdm_popen2(const mpdm_t prg)
2061 mpdm_t i, o;
2062 mpdm_t p = NULL;
2064 if ((i = mpdm_popen(prg, MPDM_AS(L"r+"))) != NULL) {
2065 struct mpdm_file *ifs;
2066 struct mpdm_file *ofs;
2068 o = MPDM_C(i->flags, (void *)i->data, i->size);
2070 ifs = (struct mpdm_file *)i->data;
2071 ofs = (struct mpdm_file *)o->data;
2073 ofs->in = ifs->out;
2074 ifs->out = NULL;
2076 #ifdef CONFOPT_WIN32
2077 ofs->hin = ifs->hout;
2078 ifs->hout = NULL;
2079 #endif
2081 p = mpdm_ref(MPDM_A(2));
2082 mpdm_aset(p, i, 0);
2083 mpdm_aset(p, o, 1);
2084 mpdm_unrefnd(p);
2087 return p;
2092 * mpdm_pclose - Closes a pipe.
2093 * @fd: the value containing the file descriptor
2095 * Closes a pipe.
2096 * [File Management]
2098 mpdm_t mpdm_pclose(mpdm_t fd)
2100 mpdm_t r = NULL;
2102 mpdm_ref(fd);
2104 if ((fd->flags & MPDM_FILE) && fd->data != NULL) {
2105 r = MPDM_I(sysdep_pclose(fd));
2106 destroy_mpdm_file(fd);
2109 fd = mpdm_unref(fd);
2111 return r;
2116 * mpdm_home_dir - Returns the home user directory.
2118 * Returns a system-dependent directory where the user can write
2119 * documents and create subdirectories.
2120 * [File Management]
2122 mpdm_t mpdm_home_dir(void)
2124 mpdm_t r = NULL;
2125 char *ptr;
2126 char tmp[512] = "";
2128 #ifdef CONFOPT_WIN32
2130 LPITEMIDLIST pidl;
2132 /* get the 'My Documents' folder */
2133 SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &pidl);
2134 SHGetPathFromIDList(pidl, tmp);
2135 strcat(tmp, "\\");
2137 #endif
2139 #ifdef CONFOPT_PWD_H
2141 struct passwd *p;
2143 /* get home dir from /etc/passwd entry */
2144 if (tmp[0] == '\0' && (p = getpwuid(getpid())) != NULL) {
2145 strcpy(tmp, p->pw_dir);
2146 strcat(tmp, "/");
2149 #endif
2151 /* still none? try the ENV variable $HOME */
2152 if (tmp[0] == '\0' && (ptr = getenv("HOME")) != NULL) {
2153 strcpy(tmp, ptr);
2154 strcat(tmp, "/");
2157 if (tmp[0] != '\0')
2158 r = MPDM_MBS(tmp);
2160 return r;
2165 * mpdm_app_dir - Returns the applications directory.
2167 * Returns a system-dependent directory where the applications store
2168 * their private data, as components or resources.
2169 * [File Management]
2171 mpdm_t mpdm_app_dir(void)
2173 mpdm_t r = NULL;
2175 #ifdef CONFOPT_WIN32
2177 HKEY hkey;
2178 char tmp[MAX_PATH];
2179 LPITEMIDLIST pidl;
2181 /* get the 'Program Files' folder (can fail) */
2182 tmp[0] = '\0';
2183 if (SHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidl) ==
2184 S_OK)
2185 SHGetPathFromIDList(pidl, tmp);
2187 /* if it's still empty, get from the registry */
2188 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
2189 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
2190 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS) {
2191 int n = sizeof(tmp);
2193 if (RegQueryValueEx(hkey, "ProgramFilesDir",
2194 NULL, NULL, tmp,
2195 (LPDWORD) & n) != ERROR_SUCCESS)
2196 tmp[0] = '\0';
2199 if (tmp[0] != '\0') {
2200 strcat(tmp, "\\");
2201 r = MPDM_MBS(tmp);
2203 #endif
2205 /* still none? get the configured directory */
2206 if (r == NULL)
2207 r = MPDM_MBS(CONFOPT_PREFIX "/share/");
2209 return r;