Fixed mpdm_sregex().
[mpdm.git] / mpdm_f.c
blob5c62579aaf4506bc06f0b1fdbca0b9f39812d928
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 = mpdm_poke(auxptr, &n, tmp, i, sizeof(char))) == NULL)
185 return NULL;
187 i = 0;
191 /* is there something to return? */
192 if (i || n) {
193 /* NULL-terminate */
194 tmp[i++] = '\0';
196 if (n) {
197 /* auxiliary space used; concat all */
198 if ((auxptr = mpdm_poke(auxptr, &n, tmp, i, sizeof(char))) == NULL)
199 return NULL;
201 /* do the conversion */
202 ptr = mpdm_mbstowcs(auxptr, s, -1);
204 free(auxptr);
206 else
207 ptr = mpdm_mbstowcs(tmp, s, -1);
210 return ptr;
214 static int write_wcs(struct mpdm_file *f, const wchar_t * str)
215 /* writes a wide string to an struct mpdm_file */
217 int s;
218 char *ptr;
220 ptr = mpdm_wcstombs(str, &s);
221 s = put_buf(ptr, s, f);
222 free(ptr);
224 return s;
228 #ifdef CONFOPT_ICONV
230 static wchar_t *read_iconv(struct mpdm_file *f, int *s)
231 /* reads a multibyte string transforming with iconv */
233 char tmp[128];
234 wchar_t *ptr = NULL;
235 int c, i;
236 wchar_t wc;
238 *s = i = 0;
240 /* resets the decoder */
241 iconv(f->ic_dec, NULL, NULL, NULL, NULL);
243 while ((c = get_char(f)) != EOF) {
244 size_t il, ol;
245 char *iptr, *optr;
247 tmp[i++] = c;
249 /* too big? shouldn't happen */
250 if (i == sizeof(tmp))
251 break;
253 il = i;
254 iptr = tmp;
255 ol = sizeof(wchar_t);
256 optr = (char *) &wc;
258 /* write to file */
259 if (iconv(f->ic_dec, &iptr, &il, &optr, &ol) == (size_t) -1) {
260 /* found incomplete multibyte character */
261 if (errno == EINVAL)
262 continue;
264 /* otherwise, return '?' */
265 wc = L'?';
268 i = 0;
270 if ((ptr = mpdm_poke(ptr, s, &wc, 1, sizeof(wchar_t))) == NULL)
271 break;
273 /* if it's an end of line, finish */
274 if (wc == L'\n')
275 break;
278 if (ptr != NULL) {
279 ptr = mpdm_poke(ptr, s, L"", 1, sizeof(wchar_t));
280 (*s)--;
283 return ptr;
287 static int write_iconv(struct mpdm_file *f, const wchar_t * str)
288 /* writes a wide string to a stream using iconv */
290 char tmp[128];
291 int cnt = 0;
293 /* resets the encoder */
294 iconv(f->ic_enc, NULL, NULL, NULL, NULL);
296 /* convert char by char */
297 for (; *str != L'\0'; str++) {
298 size_t il, ol;
299 char *iptr, *optr;
300 int n;
302 il = sizeof(wchar_t);
303 iptr = (char *) str;
304 ol = sizeof(tmp);
305 optr = tmp;
307 /* write to file */
308 if (iconv(f->ic_enc, &iptr, &il, &optr, &ol) == (size_t) -1) {
309 /* error converting; convert a '?' instead */
310 wchar_t q = L'?';
312 il = sizeof(wchar_t);
313 iptr = (char *) &q;
314 ol = sizeof(tmp);
315 optr = tmp;
317 iconv(f->ic_enc, &iptr, &il, &optr, &ol);
320 for (n = 0; n < (int)(sizeof(tmp) - ol); n++, cnt++) {
321 if (put_char(tmp[n], f) == EOF)
322 return -1;
326 return cnt;
330 #endif /* CONFOPT_ICONV */
332 #define UTF8_BYTE() if((c = get_char(f)) == EOF) break
334 static wchar_t *read_utf8(struct mpdm_file *f, int *s)
335 /* utf8 reader */
337 wchar_t *ptr = NULL;
338 wchar_t wc;
339 int c;
341 *s = 0;
343 for (;;) {
344 wc = L'\0';
346 UTF8_BYTE();
348 if ((c & 0x80) == 0)
349 wc = c;
350 else
351 if ((c & 0xe0) == 0xe0) {
352 wc = (c & 0x1f) << 12;
353 UTF8_BYTE();
354 wc |= (c & 0x3f) << 6;
355 UTF8_BYTE();
356 wc |= (c & 0x3f);
358 else {
359 wc = (c & 0x3f) << 6;
360 UTF8_BYTE();
361 wc |= (c & 0x3f);
364 /* store */
365 if ((ptr = mpdm_poke(ptr, s, &wc, 1, sizeof(wchar_t))) == NULL)
366 break;
368 /* if it's an end of line, finish */
369 if (wc == L'\n')
370 break;
373 if (ptr != NULL) {
374 ptr = mpdm_poke(ptr, s, L"", 1, sizeof(wchar_t));
375 (*s)--;
378 return ptr;
382 static int write_utf8(struct mpdm_file *f, const wchar_t * str)
383 /* utf8 writer */
385 int cnt = 0;
386 wchar_t wc;
388 /* convert char by char */
389 for (; (wc = *str) != L'\0'; str++) {
390 if (wc < 0x80)
391 put_char((int) wc, f);
392 else
393 if (wc < 0x800) {
394 put_char((int) (0xc0 | (wc >> 6)), f);
395 put_char((int) (0x80 | (wc & 0x3f)), f);
396 cnt++;
398 else {
399 put_char((int) (0xe0 | (wc >> 12)), f);
400 put_char((int) (0x80 | ((wc >> 6) & 0x3f)), f);
401 put_char((int) (0x80 | (wc & 0x3f)), f);
402 cnt += 2;
405 cnt++;
408 return cnt;
412 static wchar_t *read_utf8_bom(struct mpdm_file *f, int *s)
413 /* utf-8 reader with BOM detection */
415 wchar_t *enc = L"";
417 f->f_read = NULL;
419 /* autodetection */
420 if (get_char(f) == 0xef && get_char(f) == 0xbb && get_char(f) == 0xbf)
421 enc = L"utf-8bom";
422 else {
423 enc = L"utf-8";
424 fseek(f->in, 0, SEEK_SET);
427 mpdm_hset_s(mpdm_root(), L"DETECTED_ENCODING", MPDM_LS(enc));
429 /* we're utf-8 from now on */
430 f->f_read = read_utf8;
432 return f->f_read(f, s);
436 static int write_utf8_bom(struct mpdm_file *f, const wchar_t * str)
437 /* utf-8 writer with BOM */
439 /* store the BOM */
440 put_char(0xef, f);
441 put_char(0xbb, f);
442 put_char(0xbf, f);
444 /* we're utf-8 from now on */
445 f->f_write = write_utf8;
447 return f->f_write(f, str);
451 static wchar_t *read_iso8859_1(struct mpdm_file *f, int *s)
452 /* iso8859-1 reader */
454 wchar_t *ptr = NULL;
455 wchar_t wc;
456 int c;
458 *s = 0;
460 while ((c = get_char(f)) != EOF) {
461 wc = c;
463 /* store */
464 if ((ptr = mpdm_poke(ptr, s, &wc, 1, sizeof(wchar_t))) == NULL)
465 break;
467 /* if it's an end of line, finish */
468 if (wc == L'\n')
469 break;
472 if (ptr != NULL) {
473 ptr = mpdm_poke(ptr, s, L"", 1, sizeof(wchar_t));
474 (*s)--;
477 return ptr;
481 static int write_iso8859_1(struct mpdm_file *f, const wchar_t * str)
482 /* iso8859-1 writer */
484 int cnt = 0;
485 wchar_t wc;
487 /* convert char by char */
488 for (; (wc = *str) != L'\0'; str++)
489 put_char(wc <= 0xff ? (int) wc : '?', f);
491 return cnt;
495 static wchar_t *read_utf16ae(struct mpdm_file *f, int *s, int le)
496 /* utf16 reader, ANY ending */
498 wchar_t *ptr = NULL;
499 wchar_t wc;
500 int c1, c2;
502 *s = 0;
504 for (;;) {
505 wc = L'\0';
507 if ((c1 = get_char(f)) == EOF)
508 break;
510 if ((c2 = get_char(f)) == EOF)
511 break;
513 if (le)
514 wc = c1 | (c2 << 8);
515 else
516 wc = c2 | (c1 << 8);
518 /* store */
519 if ((ptr = mpdm_poke(ptr, s, &wc, 1, sizeof(wchar_t))) == NULL)
520 break;
522 /* if it's an end of line, finish */
523 if (wc == L'\n')
524 break;
527 if (ptr != NULL) {
528 ptr = mpdm_poke(ptr, s, L"", 1, sizeof(wchar_t));
529 (*s)--;
532 return ptr;
536 static int write_utf16ae(struct mpdm_file *f, const wchar_t * str, int le)
537 /* utf16 writer, ANY ending */
539 int cnt = 0;
540 wchar_t wc;
542 /* convert char by char */
543 for (; (wc = *str) != L'\0'; str++) {
545 if (le) {
546 put_char(wc & 0xff, f);
547 put_char((wc & 0xff00) >> 8, f);
549 else {
550 put_char((wc & 0xff00) >> 8, f);
551 put_char(wc & 0xff, f);
555 return cnt;
559 static wchar_t *read_utf16le(struct mpdm_file *f, int *s)
561 return read_utf16ae(f, s, 1);
565 static int write_utf16le(struct mpdm_file *f, const wchar_t * str)
567 return write_utf16ae(f, str, 1);
571 static wchar_t *read_utf16be(struct mpdm_file *f, int *s)
573 return read_utf16ae(f, s, 0);
577 static int write_utf16be(struct mpdm_file *f, const wchar_t * str)
579 return write_utf16ae(f, str, 0);
583 static wchar_t *read_utf16(struct mpdm_file *f, int *s)
585 int c1, c2;
586 wchar_t *enc = L"utf-16le";
588 /* assume little-endian */
589 f->f_read = read_utf16le;
591 /* autodetection */
592 c1 = get_char(f);
593 c2 = get_char(f);
595 if (c1 == 0xfe && c2 == 0xff) {
596 enc = L"utf-16be";
597 f->f_read = read_utf16be;
599 else
600 if (c1 != 0xff || c2 != 0xfe) {
601 /* no BOM; rewind and hope */
602 fseek(f->in, 0, SEEK_SET);
605 mpdm_hset_s(mpdm_root(), L"DETECTED_ENCODING", MPDM_LS(enc));
607 return f->f_read(f, s);
611 static int write_utf16le_bom(struct mpdm_file *f, const wchar_t * str)
613 /* store the LE signature */
614 put_char(0xff, f);
615 put_char(0xfe, f);
617 /* we're 16le from now on */
618 f->f_write = write_utf16le;
620 return f->f_write(f, str);
624 static int write_utf16be_bom(struct mpdm_file *f, const wchar_t * str)
626 /* store the BE signature */
627 put_char(0xfe, f);
628 put_char(0xff, f);
630 /* we're 16be from now on */
631 f->f_write = write_utf16be;
633 return f->f_write(f, str);
637 static wchar_t *read_utf32ae(struct mpdm_file *f, int *s, int le)
638 /* utf32 reader, ANY ending */
640 wchar_t *ptr = NULL;
641 wchar_t wc;
642 int c1, c2, c3, c4;
644 *s = 0;
646 for (;;) {
647 wc = L'\0';
649 if ((c1 = get_char(f)) == EOF)
650 break;
652 if ((c2 = get_char(f)) == EOF)
653 break;
655 if ((c3 = get_char(f)) == EOF)
656 break;
658 if ((c4 = get_char(f)) == EOF)
659 break;
661 if (le)
662 wc = c1 | (c2 << 8) | (c3 << 16) | (c4 << 24);
663 else
664 wc = c4 | (c3 << 8) | (c2 << 16) | (c1 << 24);
666 /* store */
667 if ((ptr = mpdm_poke(ptr, s, &wc, 1, sizeof(wchar_t))) == NULL)
668 break;
670 /* if it's an end of line, finish */
671 if (wc == L'\n')
672 break;
675 if (ptr != NULL) {
676 ptr = mpdm_poke(ptr, s, L"", 1, sizeof(wchar_t));
677 (*s)--;
680 return ptr;
684 static int write_utf32ae(struct mpdm_file *f, const wchar_t * str, int le)
685 /* utf32 writer, ANY ending */
687 int cnt = 0;
688 wchar_t wc;
690 /* convert char by char */
691 for (; (wc = *str) != L'\0'; str++) {
693 if (le) {
694 put_char((wc & 0x000000ff), f);
695 put_char((wc & 0x0000ff00) >> 8, f);
696 put_char((wc & 0x00ff0000) >> 16, f);
697 put_char((wc & 0xff000000) >> 24, f);
699 else {
700 put_char((wc & 0xff000000) >> 24, f);
701 put_char((wc & 0x00ff0000) >> 16, f);
702 put_char((wc & 0x0000ff00) >> 8, f);
703 put_char((wc & 0x000000ff), f);
707 return cnt;
711 static wchar_t *read_utf32le(struct mpdm_file *f, int *s)
713 return read_utf32ae(f, s, 1);
717 static int write_utf32le(struct mpdm_file *f, const wchar_t * str)
719 return write_utf32ae(f, str, 1);
723 static wchar_t *read_utf32be(struct mpdm_file *f, int *s)
725 return read_utf32ae(f, s, 0);
729 static int write_utf32be(struct mpdm_file *f, const wchar_t * str)
731 return write_utf32ae(f, str, 0);
735 static wchar_t *read_utf32(struct mpdm_file *f, int *s)
737 int c1, c2, c3, c4;
738 wchar_t *enc = L"utf-32le";
740 f->f_read = read_utf32le;
742 /* autodetection */
743 c1 = get_char(f);
744 c2 = get_char(f);
745 c3 = get_char(f);
746 c4 = get_char(f);
748 if (c1 == 0 && c2 == 0 && c3 == 0xfe && c4 == 0xff) {
749 enc = L"utf-32be";
750 f->f_read = read_utf32be;
752 if (c1 != 0xff || c2 != 0xfe || c3 != 0 || c4 != 0) {
753 /* no BOM; assume le and hope */
754 fseek(f->in, 0, SEEK_SET);
757 mpdm_hset_s(mpdm_root(), L"DETECTED_ENCODING", MPDM_LS(enc));
759 return f->f_read(f, s);
763 static int write_utf32le_bom(struct mpdm_file *f, const wchar_t * str)
765 /* store the LE signature */
766 put_char(0xff, f);
767 put_char(0xfe, f);
768 put_char(0, f);
769 put_char(0, f);
771 /* we're 32le from now on */
772 f->f_write = write_utf32le;
774 return f->f_write(f, str);
778 static int write_utf32be_bom(struct mpdm_file *f, const wchar_t * str)
780 /* store the BE signature */
781 put_char(0, f);
782 put_char(0, f);
783 put_char(0xfe, f);
784 put_char(0xff, f);
786 /* we're 32be from now on */
787 f->f_write = write_utf32be;
789 return f->f_write(f, str);
793 static wchar_t *read_auto(struct mpdm_file *f, int *s)
794 /* autodetects different encodings based on the BOM */
796 wchar_t *enc = L"";
798 /* by default, multibyte reading */
799 f->f_read = read_mbs;
801 /* ensure seeking is possible */
802 if (f->in != NULL && fseek(f->in, 0, SEEK_CUR) != -1) {
803 int c;
805 c = get_char(f);
807 if (c == 0xff) {
808 /* can be utf32le or utf16le */
809 if (get_char(f) == 0xfe) {
810 /* if next 2 chars are 0x00, it's utf32; otherwise utf16 */
811 if (get_char(f) == 0x00 && get_char(f) == 0x00) {
812 enc = L"utf-32le";
813 f->f_read = read_utf32le;
814 goto got_encoding;
816 else {
817 /* rewind to 3rd character */
818 fseek(f->in, 2, SEEK_SET);
820 enc = L"utf-16le";
821 f->f_read = read_utf16le;
822 goto got_encoding;
826 else
827 if (c == 0x00) {
828 /* can be utf32be */
829 if (get_char(f) == 0x00 && get_char(f) == 0xfe && get_char(f) == 0xff) {
830 enc = L"utf-32be";
831 f->f_read = read_utf32be;
832 goto got_encoding;
835 else
836 if (c == 0xfe) {
837 /* can be utf16be */
838 if (get_char(f) == 0xff) {
839 enc = L"utf-16be";
840 f->f_read = read_utf16be;
841 goto got_encoding;
844 else
845 if (c == 0xef) {
846 /* can be utf8 with BOM */
847 if (get_char(f) == 0xbb && get_char(f) == 0xbf) {
848 enc = L"utf-8bom";
849 f->f_read = read_utf8;
850 goto got_encoding;
853 else {
854 /* try if a first bunch of chars are valid UTF-8 */
855 int p = c;
856 int n = 10000;
857 int u = 0;
859 while (--n && (c = get_char(f)) != EOF) {
860 if ((c & 0xc0) == 0x80) {
861 if ((p & 0xc0) == 0xc0)
862 u++;
863 else
864 if ((p & 0x80) == 0x00) {
865 u = -1;
866 break;
869 else
870 if ((p & 0xc0) == 0xc0) {
871 u = -1;
872 break;
875 p = c;
878 if (u < 0) {
879 /* invalid utf-8; fall back to 8bit */
880 enc = L"8bit";
881 f->f_read = read_iso8859_1;
883 else
884 if (u > 0) {
885 /* utf-8 sequences found */
886 enc = L"utf-8";
887 f->f_read = read_utf8;
890 /* 7 bit ASCII: do nothing */
893 /* none of the above; restart */
894 fseek(f->in, 0, SEEK_SET);
897 got_encoding:
898 mpdm_hset_s(mpdm_root(), L"DETECTED_ENCODING", MPDM_LS(enc));
900 return f->f_read(f, s);
904 static mpdm_t new_mpdm_file(void)
905 /* creates a new file value */
907 mpdm_t v = NULL;
908 struct mpdm_file *fs;
909 mpdm_t e;
911 if ((fs = malloc(sizeof(struct mpdm_file))) == NULL)
912 return NULL;
914 memset(fs, '\0', sizeof(struct mpdm_file));
916 /* default I/O functions */
917 fs->f_read = read_auto;
918 fs->f_write = write_wcs;
920 #ifdef CONFOPT_ICONV
921 /* no iconv encodings by default */
922 fs->ic_enc = fs->ic_dec = (iconv_t) -1;
923 #endif
925 if ((v = mpdm_new(MPDM_FILE | MPDM_FREE, fs, sizeof(struct mpdm_file))) == NULL) {
926 free(fs);
927 return NULL;
930 e = mpdm_hget_s(mpdm_root(), L"ENCODING");
932 if (mpdm_size(e) == 0)
933 e = mpdm_hget_s(mpdm_root(), L"TEMP_ENCODING");
935 if (mpdm_size(e)) {
937 wchar_t *enc = mpdm_string(e);
939 if (wcscmp(enc, L"utf-8") == 0) {
940 fs->f_read = read_utf8_bom;
941 fs->f_write = write_utf8;
943 else
944 if (wcscmp(enc, L"utf-8bom") == 0) {
945 fs->f_read = read_utf8_bom;
946 fs->f_write = write_utf8_bom;
948 else
949 if (wcscmp(enc, L"iso8859-1") == 0 ||
950 wcscmp(enc, L"8bit") == 0) {
951 fs->f_read = read_iso8859_1;
952 fs->f_write = write_iso8859_1;
954 else
955 if (wcscmp(enc, L"utf-16le") == 0) {
956 fs->f_read = read_utf16le;
957 fs->f_write = write_utf16le_bom;
959 else
960 if (wcscmp(enc, L"utf-16be") == 0) {
961 fs->f_read = read_utf16be;
962 fs->f_write = write_utf16be_bom;
964 else
965 if (wcscmp(enc, L"utf-16") == 0) {
966 fs->f_read = read_utf16;
967 fs->f_write = write_utf16le_bom;
969 else
970 if (wcscmp(enc, L"utf-32le") == 0) {
971 fs->f_read = read_utf32le;
972 fs->f_write = write_utf32le_bom;
974 else
975 if (wcscmp(enc, L"utf-32be") == 0) {
976 fs->f_read = read_utf32be;
977 fs->f_write = write_utf32be_bom;
979 else
980 if (wcscmp(enc, L"utf-32") == 0) {
981 fs->f_read = read_utf32;
982 fs->f_write = write_utf32le_bom;
984 else {
985 #ifdef CONFOPT_ICONV
986 mpdm_t cs = MPDM_2MBS(e->data);
988 if ((fs->ic_enc = iconv_open((char *) cs->data, "WCHAR_T")) != (iconv_t) -1 &&
989 (fs->ic_dec = iconv_open("WCHAR_T", (char *) cs->data)) != (iconv_t) -1) {
991 fs->f_read = read_iconv;
992 fs->f_write = write_iconv;
994 #endif /* CONFOPT_ICONV */
997 mpdm_hset_s(mpdm_root(), L"TEMP_ENCODING", NULL);
1000 return v;
1004 static void destroy_mpdm_file(mpdm_t v)
1005 /* destroys and file value */
1007 struct mpdm_file *fs = (struct mpdm_file *)v->data;
1009 if (fs != NULL) {
1010 #ifdef CONFOPT_ICONV
1011 if (fs->ic_enc != (iconv_t) - 1) {
1012 iconv_close(fs->ic_enc);
1013 fs->ic_enc = (iconv_t) - 1;
1016 if (fs->ic_dec != (iconv_t) - 1) {
1017 iconv_close(fs->ic_dec);
1018 fs->ic_dec = (iconv_t) - 1;
1020 #endif
1022 free(fs);
1023 v->data = NULL;
1028 /** interface **/
1030 wchar_t *mpdm_read_mbs(FILE * f, int *s)
1031 /* reads a multibyte string from a stream into a dynamic string */
1033 struct mpdm_file fs;
1035 /* reset the structure */
1036 memset(&fs, '\0', sizeof(fs));
1037 fs.in = f;
1039 return read_mbs(&fs, s);
1043 int mpdm_write_wcs(FILE * f, const wchar_t * str)
1044 /* writes a wide string to a stream */
1046 struct mpdm_file fs;
1048 /* reset the structure */
1049 memset(&fs, '\0', sizeof(fs));
1050 fs.out = f;
1052 return write_wcs(&fs, str);
1056 mpdm_t mpdm_new_f(FILE * f)
1057 /* creates a new file value from a FILE * */
1059 mpdm_t v = NULL;
1061 if (f == NULL)
1062 return NULL;
1064 if ((v = new_mpdm_file()) != NULL) {
1065 struct mpdm_file *fs = (struct mpdm_file *)v->data;
1066 fs->in = fs->out = f;
1069 return v;
1074 * mpdm_open - Opens a file.
1075 * @filename: the file name
1076 * @mode: an fopen-like mode string
1078 * Opens a file. If @filename can be open in the specified @mode, an
1079 * mpdm_t value will be returned containing the file descriptor, or NULL
1080 * otherwise.
1082 * If the file is open for reading, some charset detection methods are
1083 * used. If any of them is successful, its name is stored in the
1084 * DETECTED_ENCODING element of the mpdm_root() hash. This value is
1085 * suitable to be copied over ENCODING or TEMP_ENCODING.
1087 * If the file is open for writing, the encoding to be used is read from
1088 * the ENCODING element of mpdm_root() and, if not set, from the
1089 * TEMP_ENCODING one. The latter will always be deleted afterwards.
1090 * [File Management]
1092 mpdm_t mpdm_open(const mpdm_t filename, const mpdm_t mode)
1094 FILE *f = NULL;
1095 mpdm_t fn;
1096 mpdm_t m;
1098 mpdm_ref(filename);
1099 mpdm_ref(mode);
1101 if (filename != NULL && mode != NULL) {
1103 /* convert to mbs,s */
1104 fn = mpdm_ref(MPDM_2MBS(filename->data));
1105 m = mpdm_ref(MPDM_2MBS(mode->data));
1107 if ((f = fopen((char *) fn->data, (char *) m->data)) == NULL)
1108 store_syserr();
1109 else {
1110 #if defined(CONFOPT_SYS_STAT_H) && defined(S_ISDIR) && defined(EISDIR)
1111 struct stat s;
1113 /* test if the open file is a directory */
1114 if (fstat(fileno(f), &s) != -1 && S_ISDIR(s.st_mode)) {
1115 /* it's a directory; fail */
1116 errno = EISDIR;
1117 store_syserr();
1118 fclose(f);
1119 f = NULL;
1121 #endif
1124 mpdm_unref(m);
1125 mpdm_unref(fn);
1128 mpdm_unref(mode);
1129 mpdm_unref(filename);
1131 return MPDM_F(f);
1136 * mpdm_close - Closes a file descriptor.
1137 * @fd: the value containing the file descriptor
1139 * Closes the file descriptor.
1140 * [File Management]
1142 mpdm_t mpdm_close(mpdm_t fd)
1144 struct mpdm_file *fs = (struct mpdm_file *)fd->data;
1146 mpdm_ref(fd);
1148 if ((fd->flags & MPDM_FILE) && fs != NULL) {
1149 if (fs->in != NULL)
1150 fclose(fs->in);
1152 if (fs->out != fs->in && fs->out != NULL)
1153 fclose(fs->out);
1155 destroy_mpdm_file(fd);
1158 fd = mpdm_unref(fd);
1160 return fd;
1165 * mpdm_read - Reads a line from a file descriptor.
1166 * @fd: the value containing the file descriptor
1168 * Reads a line from @fd. Returns the line, or NULL on EOF.
1169 * [File Management]
1170 * [Character Set Conversion]
1172 mpdm_t mpdm_read(const mpdm_t fd)
1174 mpdm_t v = NULL;
1175 wchar_t *ptr;
1176 int s;
1177 struct mpdm_file *fs = (struct mpdm_file *)fd->data;
1179 if (fs == NULL)
1180 return NULL;
1182 ptr = fs->f_read(fs, &s);
1184 if (ptr != NULL)
1185 v = MPDM_ENS(ptr, s);
1187 return v;
1191 mpdm_t mpdm_getchar(const mpdm_t fd)
1193 int c;
1194 wchar_t tmp[2];
1195 mpdm_t r = NULL;
1196 struct mpdm_file *fs = (struct mpdm_file *)fd->data;
1198 if (fs != NULL && (c = get_char(fs)) != EOF) {
1199 /* get the char as-is */
1200 tmp[0] = (wchar_t) c;
1201 tmp[1] = L'\0';
1203 r = MPDM_S(tmp);
1206 return r;
1210 int mpdm_putchar(const mpdm_t fd, const mpdm_t c)
1212 struct mpdm_file *fs = (struct mpdm_file *)fd->data;
1213 const wchar_t *ptr = mpdm_string(c);
1214 int r = 1;
1216 mpdm_ref(c);
1218 if (fs == NULL || put_char(*ptr, fs) == -1)
1219 r = 0;
1221 mpdm_unref(c);
1223 return r;
1228 * mpdm_write - Writes a value into a file.
1229 * @fd: the file descriptor.
1230 * @v: the value to be written.
1232 * Writes the @v string value into @fd, using the current encoding.
1233 * [File Management]
1234 * [Character Set Conversion]
1236 int mpdm_write(const mpdm_t fd, const mpdm_t v)
1238 struct mpdm_file *fs = (struct mpdm_file *)fd->data;
1239 int ret = -1;
1241 mpdm_ref(v);
1243 if (fs != NULL)
1244 ret = fs->f_write(fs, mpdm_string(v));
1246 mpdm_unref(v);
1248 return ret;
1252 int mpdm_fseek(const mpdm_t fd, long offset, int whence)
1254 struct mpdm_file *fs = (struct mpdm_file *)fd->data;
1256 return fseek(fs->in, offset, whence);
1260 long mpdm_ftell(const mpdm_t fd)
1262 struct mpdm_file *fs = (struct mpdm_file *)fd->data;
1264 return ftell(fs->in);
1268 FILE * mpdm_get_filehandle(const mpdm_t fd)
1270 FILE * f = NULL;
1272 if (fd->flags & MPDM_FILE && fd->data != NULL) {
1273 struct mpdm_file *fs = (struct mpdm_file *)fd->data;
1274 f = fs->in;
1277 return f;
1282 mpdm_t mpdm_bread(mpdm_t fd, int size)
1287 int mpdm_bwrite(mpdm_tfd, mpdm_t v, int size)
1293 static mpdm_t embedded_encodings(void)
1295 mpdm_t e;
1296 wchar_t *e2e[] = {
1297 L"utf-8", L"utf-8",
1298 L"utf8", NULL,
1299 L"iso8859-1", L"iso8859-1",
1300 L"iso-8859-1", NULL,
1301 L"8bit", NULL,
1302 L"latin1", NULL,
1303 L"latin-1", NULL,
1304 L"utf-16le", L"utf-16le",
1305 L"utf16le", NULL,
1306 L"ucs-2le", NULL,
1307 L"utf-16be", L"utf-16be",
1308 L"utf16be", NULL,
1309 L"ucs-2be", NULL,
1310 L"utf-16", L"utf-16",
1311 L"utf16", NULL,
1312 L"ucs-2", NULL,
1313 L"ucs2", NULL,
1314 L"utf-32le", L"utf-32le",
1315 L"utf32le", NULL,
1316 L"ucs-4le", NULL,
1317 L"utf-32be", L"utf-32be",
1318 L"utf32be", NULL,
1319 L"ucs-4be", NULL,
1320 L"utf-32", L"utf-32",
1321 L"utf32", NULL,
1322 L"ucs-4", NULL,
1323 L"ucs4", NULL,
1324 L"utf-8bom", L"utf-8bom",
1325 L"utf8bom", NULL,
1326 NULL, NULL
1329 if ((e = mpdm_hget_s(mpdm_root(), L"EMBEDDED_ENCODINGS")) == NULL) {
1330 int n;
1331 mpdm_t p = NULL;
1333 e = mpdm_ref(MPDM_H(0));
1335 for (n = 0; e2e[n] != NULL; n += 2) {
1336 mpdm_t v = MPDM_S(e2e[n]);
1338 if (e2e[n + 1] != NULL)
1339 p = MPDM_S(e2e[n + 1]);
1341 mpdm_hset(e, v, p);
1342 mpdm_hset(e, mpdm_ulc(v, 1), p);
1345 mpdm_hset_s(mpdm_root(), L"EMBEDDED_ENCODINGS", e);
1347 mpdm_unref(e);
1350 return e;
1355 * mpdm_encoding - Sets the current charset encoding for files.
1356 * @charset: the charset name.
1358 * Sets the current charset encoding for files. Future opened
1359 * files will be assumed to be encoded with @charset, which can
1360 * be any of the supported charset names (utf-8, iso-8859-1, etc.),
1361 * and converted on each read / write. If charset is NULL, it
1362 * is reverted to default charset conversion (i.e. the one defined
1363 * in the locale).
1365 * This function stores the @charset value into the ENCODING item
1366 * of the mpdm_root() hash.
1368 * Returns a negative number if @charset is unsupported, or zero
1369 * if no errors were found.
1370 * [File Management]
1371 * [Character Set Conversion]
1373 int mpdm_encoding(mpdm_t charset)
1375 int ret = -1;
1376 mpdm_t e = embedded_encodings();
1377 mpdm_t v = NULL;
1379 mpdm_ref(charset);
1381 /* NULL encoding? done */
1382 if (mpdm_size(charset) == 0) {
1383 mpdm_hset_s(mpdm_root(), L"ENCODING", NULL);
1384 ret = 0;
1387 #ifdef CONFOPT_ICONV
1388 else {
1389 iconv_t ic;
1390 mpdm_t cs = mpdm_ref(MPDM_2MBS(charset->data));
1392 /* tries to create an iconv encoder and decoder for this charset */
1394 if ((ic = iconv_open("WCHAR_T", (char *) cs->data)) == (iconv_t) - 1)
1395 ret = -1;
1396 else {
1397 iconv_close(ic);
1399 if ((ic = iconv_open((char *) cs->data, "WCHAR_T")) == (iconv_t) - 1)
1400 ret = -2;
1401 else {
1402 iconv_close(ic);
1404 /* got a valid encoding */
1405 v = charset;
1406 ret = 0;
1410 mpdm_unref(cs);
1412 #endif /* CONFOPT_ICONV */
1414 if (ret != 0 && (v = mpdm_hget(e, charset)) != NULL)
1415 ret = 0;
1417 if (ret == 0)
1418 mpdm_hset_s(mpdm_root(), L"ENCODING", v);
1420 mpdm_unref(charset);
1422 return ret;
1427 * mpdm_unlink - Deletes a file.
1428 * @filename: file name to be deleted
1430 * Deletes a file.
1431 * [File Management]
1433 int mpdm_unlink(const mpdm_t filename)
1435 int ret;
1436 mpdm_t fn;
1438 mpdm_ref(filename);
1440 /* convert to mbs */
1441 fn = mpdm_ref(MPDM_2MBS(filename->data));
1443 if ((ret = unlink((char *) fn->data)) == -1)
1444 store_syserr();
1446 mpdm_unref(fn);
1447 mpdm_unref(filename);
1449 return ret;
1454 * mpdm_stat - Gives status from a file.
1455 * @filename: file name to get the status from
1457 * Returns a 14 element array of the status (permissions, onwer, etc.)
1458 * from the desired @filename, or NULL if the file cannot be accessed.
1459 * (man 2 stat).
1461 * The values are: 0, device number of filesystem; 1, inode number;
1462 * 2, file mode; 3, number of hard links to the file; 4, uid; 5, gid;
1463 * 6, device identifier; 7, total size of file in bytes; 8, atime;
1464 * 9, mtime; 10, ctime; 11, preferred block size for system I/O;
1465 * 12, number of blocks allocated and 13, canonicalized file name.
1466 * Not all elements have necesarily meaningful values, as most are
1467 * system-dependent.
1468 * [File Management]
1470 mpdm_t mpdm_stat(const mpdm_t filename)
1472 mpdm_t r = NULL;
1474 mpdm_ref(filename);
1476 #ifdef CONFOPT_SYS_STAT_H
1477 struct stat s;
1478 mpdm_t fn;
1480 fn = mpdm_ref(MPDM_2MBS(filename->data));
1482 if (stat((char *) fn->data, &s) != -1) {
1483 r = MPDM_A(14);
1485 mpdm_ref(r);
1487 mpdm_aset(r, MPDM_I(s.st_dev), 0);
1488 mpdm_aset(r, MPDM_I(s.st_ino), 1);
1489 mpdm_aset(r, MPDM_I(s.st_mode), 2);
1490 mpdm_aset(r, MPDM_I(s.st_nlink), 3);
1491 mpdm_aset(r, MPDM_I(s.st_uid), 4);
1492 mpdm_aset(r, MPDM_I(s.st_gid), 5);
1493 mpdm_aset(r, MPDM_I(s.st_rdev), 6);
1494 mpdm_aset(r, MPDM_I(s.st_size), 7);
1495 mpdm_aset(r, MPDM_I(s.st_atime), 8);
1496 mpdm_aset(r, MPDM_I(s.st_mtime), 9);
1497 mpdm_aset(r, MPDM_I(s.st_ctime), 10);
1498 mpdm_aset(r, MPDM_I(0), 11); /* s.st_blksize */
1499 mpdm_aset(r, MPDM_I(0), 12); /* s.st_blocks */
1501 #ifdef CONFOPT_CANONICALIZE_FILE_NAME
1504 char * ptr;
1506 if ((ptr = canonicalize_file_name(
1507 (char *)fn->data)) != NULL) {
1508 mpdm_aset(r, MPDM_MBS(ptr), 13);
1509 free(ptr);
1512 #endif
1514 #ifdef CONFOPT_REALPATH
1516 char tmp[2048];
1518 if (realpath((char *)fn->data, tmp) != NULL)
1519 mpdm_aset(r, MPDM_MBS(tmp), 13);
1521 #endif
1523 #ifdef CONFOPT_FULLPATH
1525 char tmp[_MAX_PATH + 1];
1527 if (_fullpath(tmp, (char *)fn->data, _MAX_PATH) != NULL)
1528 mpdm_aset(r, MPDM_MBS(tmp), 13);
1530 #endif
1532 mpdm_unrefnd(r);
1534 else
1535 store_syserr();
1537 mpdm_unref(fn);
1539 #endif /* CONFOPT_SYS_STAT_H */
1541 mpdm_unref(filename);
1543 return r;
1548 * mpdm_chmod - Changes a file's permissions.
1549 * @filename: the file name
1550 * @perms: permissions (element 2 from mpdm_stat())
1552 * Changes the permissions for a file.
1553 * [File Management]
1555 int mpdm_chmod(const mpdm_t filename, mpdm_t perms)
1557 int r = -1;
1559 mpdm_ref(filename);
1560 mpdm_ref(perms);
1562 mpdm_t fn = mpdm_ref(MPDM_2MBS(filename->data));
1564 if ((r = chmod((char *) fn->data, mpdm_ival(perms))) == -1)
1565 store_syserr();
1567 mpdm_unref(fn);
1568 mpdm_unref(perms);
1569 mpdm_unref(filename);
1571 return r;
1576 * mpdm_chdir - Changes the working directory
1577 * @dir: the new path
1579 * Changes the working directory
1580 * [File Management]
1582 int mpdm_chdir(const mpdm_t dir)
1584 int r = -1;
1586 mpdm_ref(dir);
1587 mpdm_t fn = mpdm_ref(MPDM_2MBS(dir->data));
1589 if ((r = chdir((char *) fn->data)) == -1)
1590 store_syserr();
1592 mpdm_unref(fn);
1593 mpdm_unref(dir);
1595 return r;
1600 * mpdm_chown - Changes a file's owner.
1601 * @filename: the file name
1602 * @uid: user id (element 4 from mpdm_stat())
1603 * @gid: group id (element 5 from mpdm_stat())
1605 * Changes the owner and group id's for a file.
1606 * [File Management]
1608 int mpdm_chown(const mpdm_t filename, mpdm_t uid, mpdm_t gid)
1610 int r = -1;
1612 mpdm_ref(filename);
1613 mpdm_ref(uid);
1614 mpdm_ref(gid);
1616 #ifdef CONFOPT_CHOWN
1618 mpdm_t fn = mpdm_ref(MPDM_2MBS(filename->data));
1620 if ((r = chown((char *) fn->data, mpdm_ival(uid), mpdm_ival(gid))) == -1)
1621 store_syserr();
1623 mpdm_unref(fn);
1625 #endif /* CONFOPT_CHOWN */
1627 mpdm_unref(gid);
1628 mpdm_unref(uid);
1629 mpdm_unref(filename);
1631 return r;
1636 * mpdm_glob - Executes a file globbing.
1637 * @spec: Globbing spec
1638 * @base: Optional base directory
1640 * Executes a file globbing. @spec is system-dependent, but usually
1641 * the * and ? metacharacters work everywhere. @base can contain a
1642 * directory; if that's the case, the output strings will include it.
1643 * In any case, each returned value will be suitable for a call to
1644 * mpdm_open().
1646 * Returns an array of files that match the globbing (can be an empty
1647 * array if no file matches), or NULL if globbing is unsupported.
1648 * [File Management]
1650 mpdm_t mpdm_glob(const mpdm_t spec, const mpdm_t base)
1652 mpdm_t d = NULL;
1653 mpdm_t f = NULL;
1654 mpdm_t v = NULL;
1656 mpdm_ref(spec);
1657 mpdm_ref(base);
1659 #ifdef CONFOPT_WIN32
1661 WIN32_FIND_DATA fd;
1662 HANDLE h;
1663 char *ptr;
1664 mpdm_t w;
1665 mpdm_t s = NULL;
1666 mpdm_t sp = NULL;
1668 /* add base */
1669 if (mpdm_size(base))
1670 sp = mpdm_strcat_s(base, L"/");
1672 /* add spec */
1673 w = mpdm_ref(sp);
1675 if (mpdm_size(spec) == 0)
1676 sp = mpdm_strcat_s(w, L"*.*");
1677 else
1678 sp = mpdm_strcat(w, spec);
1680 mpdm_unref(w);
1682 /* delete repeated directory delimiters */
1683 w = mpdm_ref(sp);
1684 sp = mpdm_sregex(MPDM_LS(L"@[\\/]+@g"), w, MPDM_LS(L"/"), 0);
1685 mpdm_unref(w);
1687 w = mpdm_ref(sp);
1688 sp = MPDM_2MBS(w->data);
1689 mpdm_unref(w);
1691 v = MPDM_A(0);
1692 d = mpdm_ref(MPDM_A(0));
1693 f = mpdm_ref(MPDM_A(0));
1694 mpdm_ref(sp);
1696 if ((h = FindFirstFile((char *) sp->data, &fd)) != INVALID_HANDLE_VALUE) {
1697 /* if spec includes a directory, store in s */
1698 if ((ptr = strrchr((char *) sp->data, '/')) != NULL) {
1699 *(ptr + 1) = '\0';
1700 s = MPDM_MBS(sp->data);
1703 do {
1704 /* ignore . and .. */
1705 if (strcmp(fd.cFileName, ".") == 0 || strcmp(fd.cFileName, "..") == 0)
1706 continue;
1708 /* concat base directory and file names */
1709 w = mpdm_strcat(s, MPDM_MBS(fd.cFileName));
1711 /* if it's a directory, add a / */
1712 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1713 mpdm_t t = mpdm_ref(w);
1714 w = mpdm_strcat_s(t, L"/");
1715 mpdm_unref(t);
1717 mpdm_push(d, w);
1719 else
1720 mpdm_push(f, w);
1722 while (FindNextFile(h, &fd));
1724 FindClose(h);
1727 mpdm_unref(sp);
1729 #endif
1731 #if CONFOPT_GLOB_H
1733 /* glob.h support */
1734 glob_t globbuf;
1735 const char *ptr;
1736 mpdm_t w;
1738 /* build full path */
1739 if (mpdm_size(base))
1740 v = mpdm_strcat_s(base, L"/");
1742 w = mpdm_ref(v);
1744 if (mpdm_size(spec) == 0)
1745 v = mpdm_strcat_s(w, L"*");
1746 else
1747 v = mpdm_strcat(w, spec);
1749 mpdm_unref(w);
1751 /* delete repeated directory delimiters */
1752 w = mpdm_ref(v);
1753 v = mpdm_sregex(MPDM_LS(L"@/{2,}@g"), w, MPDM_LS(L"/"), 0);
1754 mpdm_unref(w);
1756 w = mpdm_ref(v);
1757 v = MPDM_2MBS(w->data);
1758 mpdm_unref(w);
1760 ptr = v->data;
1762 globbuf.gl_offs = 1;
1764 v = MPDM_A(0);
1765 d = mpdm_ref(MPDM_A(0));
1766 f = mpdm_ref(MPDM_A(0));
1768 if (glob(ptr, GLOB_MARK, NULL, &globbuf) == 0) {
1769 int n;
1771 for (n = 0; globbuf.gl_pathv[n] != NULL; n++) {
1772 char *ptr = globbuf.gl_pathv[n];
1773 mpdm_t t = MPDM_MBS(ptr);
1775 /* if last char is /, add to directories */
1776 if (ptr[strlen(ptr) - 1] == '/')
1777 mpdm_push(d, t);
1778 else
1779 mpdm_push(f, t);
1783 globfree(&globbuf);
1785 #else
1787 /* no win32 nor glob.h; try workaround */
1788 /* ... */
1790 #endif
1792 if (v != NULL) {
1793 int n;
1795 mpdm_sort(d, 1);
1796 mpdm_sort(f, 1);
1798 mpdm_ref(v);
1800 /* transfer all data in d and f */
1801 for (n = 0; n < mpdm_size(d); n++)
1802 mpdm_push(v, mpdm_aget(d, n));
1803 for (n = 0; n < mpdm_size(f); n++)
1804 mpdm_push(v, mpdm_aget(f, n));
1806 mpdm_unref(f);
1807 mpdm_unref(d);
1809 mpdm_unrefnd(v);
1812 mpdm_unref(base);
1813 mpdm_unref(spec);
1815 return v;
1819 #ifdef CONFOPT_WIN32
1821 static void win32_pipe(HANDLE * h, int n)
1823 SECURITY_ATTRIBUTES sa;
1824 HANDLE cp, t;
1826 memset(&sa, '\0', sizeof(sa));
1827 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
1828 sa.bInheritHandle = TRUE;
1829 sa.lpSecurityDescriptor = NULL;
1831 cp = GetCurrentProcess();
1833 CreatePipe(&h[0], &h[1], &sa, 0);
1834 DuplicateHandle(cp, h[n], cp, &t, 0, FALSE, DUPLICATE_SAME_ACCESS);
1835 CloseHandle(h[n]);
1836 h[n] = t;
1840 static int sysdep_popen(mpdm_t v, char *prg, int rw)
1841 /* win32-style pipe */
1843 HANDLE pr[2];
1844 HANDLE pw[2];
1845 PROCESS_INFORMATION pi;
1846 STARTUPINFO si;
1847 int ret;
1848 struct mpdm_file *fs = (struct mpdm_file *) v->data;
1850 /* init all */
1851 pr[0] = pr[1] = pw[0] = pw[1] = NULL;
1853 if (rw & 0x01)
1854 win32_pipe(pr, 0);
1855 if (rw & 0x02)
1856 win32_pipe(pw, 1);
1858 /* spawn new process */
1859 memset(&pi, '\0', sizeof(pi));
1860 memset(&si, '\0', sizeof(si));
1862 si.cb = sizeof(STARTUPINFO);
1863 si.hStdError = pr[1];
1864 si.hStdOutput = pr[1];
1865 si.hStdInput = pw[0];
1866 si.dwFlags |= STARTF_USESTDHANDLES;
1868 ret = CreateProcess(NULL, prg, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
1870 if (rw & 0x01)
1871 CloseHandle(pr[1]);
1872 if (rw & 0x02)
1873 CloseHandle(pw[0]);
1875 fs->hin = pr[0];
1876 fs->hout = pw[1];
1878 return ret;
1882 static int sysdep_pclose(const mpdm_t v)
1884 struct mpdm_file *fs = (struct mpdm_file *)v->data;
1886 if (fs->hin != NULL)
1887 CloseHandle(fs->hin);
1889 if (fs->hout != NULL)
1890 CloseHandle(fs->hout);
1892 /* how to know process exit code? */
1893 return 0;
1897 #else /* CONFOPT_WIN32 */
1899 static int sysdep_popen(mpdm_t v, char *prg, int rw)
1900 /* unix-style pipe open */
1902 int pr[2], pw[2];
1903 struct mpdm_file *fs = (struct mpdm_file *)v->data;
1905 /* init all */
1906 pr[0] = pr[1] = pw[0] = pw[1] = -1;
1908 if (rw & 0x01)
1909 pipe(pr);
1910 if (rw & 0x02)
1911 pipe(pw);
1913 if (fork() == 0) {
1914 /* child process */
1915 if (rw & 0x01) {
1916 close(1);
1917 dup(pr[1]);
1918 close(pr[0]);
1920 if (rw & 0x02) {
1921 close(0);
1922 dup(pw[0]);
1923 close(pw[1]);
1926 /* redirect stderr to stdout */
1927 close(2);
1928 dup(1);
1930 /* run the program */
1931 execlp("/bin/sh", "/bin/sh", "-c", prg, NULL);
1932 execlp(prg, prg, NULL);
1934 /* still here? exec failed; close pipes and exit */
1935 close(0);
1936 close(1);
1937 exit(0);
1940 /* create the pipes as non-buffered streams */
1941 if (rw & 0x01) {
1942 fs->in = fdopen(pr[0], "r");
1943 setvbuf(fs->in, NULL, _IONBF, 0);
1944 close(pr[1]);
1947 if (rw & 0x02) {
1948 fs->out = fdopen(pw[1], "w");
1949 setvbuf(fs->out, NULL, _IONBF, 0);
1950 close(pw[0]);
1953 return 1;
1957 static int sysdep_pclose(const mpdm_t v)
1958 /* unix-style pipe close */
1960 int s;
1961 struct mpdm_file *fs = (struct mpdm_file *)v->data;
1963 if (fs->in != NULL)
1964 fclose(fs->in);
1966 if (fs->out != fs->in && fs->out != NULL)
1967 fclose(fs->out);
1969 wait(&s);
1971 return s;
1975 #endif /* CONFOPT_WIN32 */
1979 * mpdm_popen - Opens a pipe.
1980 * @prg: the program to pipe
1981 * @mode: an fopen-like mode string
1983 * Opens a pipe to a program. If @prg can be open in the specified @mode, an
1984 * mpdm_t value will be returned containing the file descriptor, or NULL
1985 * otherwise.
1986 * [File Management]
1988 mpdm_t mpdm_popen(const mpdm_t prg, const mpdm_t mode)
1990 mpdm_t v, pr, md;
1991 char *m;
1992 int rw = 0;
1994 mpdm_ref(prg);
1995 mpdm_ref(mode);
1997 if (prg != NULL && mode != NULL) {
1999 v = new_mpdm_file();
2001 /* convert to mbs,s */
2002 pr = mpdm_ref(MPDM_2MBS(prg->data));
2003 md = mpdm_ref(MPDM_2MBS(mode->data));
2005 /* get the mode */
2006 m = (char *) md->data;
2008 /* set the mode */
2009 if (m[0] == 'r')
2010 rw = 0x01;
2011 if (m[0] == 'w')
2012 rw = 0x02;
2013 if (m[1] == '+')
2014 rw = 0x03; /* r+ or w+ */
2016 if (!sysdep_popen(v, (char *) pr->data, rw)) {
2017 destroy_mpdm_file(v);
2018 mpdm_unref(mpdm_ref(v));
2019 v = NULL;
2022 mpdm_unref(md);
2023 mpdm_unref(pr);
2025 else
2026 v = NULL;
2028 mpdm_unref(mode);
2029 mpdm_unref(prg);
2031 return v;
2036 * mpdm_pclose - Closes a pipe.
2037 * @fd: the value containing the file descriptor
2039 * Closes a pipe.
2040 * [File Management]
2042 mpdm_t mpdm_pclose(mpdm_t fd)
2044 mpdm_t r = NULL;
2046 mpdm_ref(fd);
2048 if ((fd->flags & MPDM_FILE) && fd->data != NULL) {
2049 r = MPDM_I(sysdep_pclose(fd));
2050 destroy_mpdm_file(fd);
2053 fd = mpdm_unref(fd);
2055 return r;
2060 * mpdm_home_dir - Returns the home user directory.
2062 * Returns a system-dependent directory where the user can write
2063 * documents and create subdirectories.
2064 * [File Management]
2066 mpdm_t mpdm_home_dir(void)
2068 mpdm_t r = NULL;
2069 char *ptr;
2070 char tmp[512] = "";
2072 #ifdef CONFOPT_WIN32
2074 LPITEMIDLIST pidl;
2076 /* get the 'My Documents' folder */
2077 SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &pidl);
2078 SHGetPathFromIDList(pidl, tmp);
2079 strcat(tmp, "\\");
2081 #endif
2083 #ifdef CONFOPT_PWD_H
2085 struct passwd *p;
2087 /* get home dir from /etc/passwd entry */
2088 if (tmp[0] == '\0' && (p = getpwuid(getpid())) != NULL) {
2089 strcpy(tmp, p->pw_dir);
2090 strcat(tmp, "/");
2093 #endif
2095 /* still none? try the ENV variable $HOME */
2096 if (tmp[0] == '\0' && (ptr = getenv("HOME")) != NULL) {
2097 strcpy(tmp, ptr);
2098 strcat(tmp, "/");
2101 if (tmp[0] != '\0')
2102 r = MPDM_MBS(tmp);
2104 return r;
2109 * mpdm_app_dir - Returns the applications directory.
2111 * Returns a system-dependent directory where the applications store
2112 * their private data, as components or resources.
2113 * [File Management]
2115 mpdm_t mpdm_app_dir(void)
2117 mpdm_t r = NULL;
2119 #ifdef CONFOPT_WIN32
2121 HKEY hkey;
2122 char tmp[MAX_PATH];
2123 LPITEMIDLIST pidl;
2125 /* get the 'Program Files' folder (can fail) */
2126 tmp[0] = '\0';
2127 if (SHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidl) == S_OK)
2128 SHGetPathFromIDList(pidl, tmp);
2130 /* if it's still empty, get from the registry */
2131 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
2132 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
2133 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS) {
2134 int n = sizeof(tmp);
2136 if (RegQueryValueEx(hkey, "ProgramFilesDir",
2137 NULL, NULL, tmp, (LPDWORD) & n) != ERROR_SUCCESS)
2138 tmp[0] = '\0';
2141 if (tmp[0] != '\0') {
2142 strcat(tmp, "\\");
2143 r = MPDM_MBS(tmp);
2145 #endif
2147 /* still none? get the configured directory */
2148 if (r == NULL)
2149 r = MPDM_MBS(CONFOPT_PREFIX "/share/");
2151 return r;