Changed the order in mpdm_cmp() arguments inside mpdm_bseek().
[mpdm.git] / mpdm_f.c
blob6ef38518c46577d0bc983c552656d1b8b96c0d42
1 /*
3 MPDM - Minimum Profit Data Manager
4 Copyright (C) 2003/2009 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 /*******************
99 Code
100 ********************/
103 static void store_syserr(void)
104 /* stores the system error inside the global ERRNO */
106 mpdm_hset_s(mpdm_root(), L"ERRNO", MPDM_MBS(strerror(errno)));
110 static int get_char(struct mpdm_file *f)
111 /* reads a character from a file structure */
113 int c = EOF;
115 #ifdef CONFOPT_WIN32
117 if (f->hin != NULL) {
118 char tmp;
119 DWORD n;
121 if (ReadFile(f->hin, &tmp, 1, &n, NULL) && n > 0)
122 c = (int) tmp;
125 #endif /* CONFOPT_WIN32 */
127 if (f->in != NULL) {
128 /* read (converting to positive if needed) */
129 if ((c = fgetc(f->in)) < 0 && !feof(f->in))
130 c += 256;
133 return c;
137 static int put_buf(const char *ptr, int s, struct mpdm_file *f)
138 /* writes s bytes in the buffer in ptr to f */
140 #ifdef CONFOPT_WIN32
142 if (f->hout != NULL) {
143 DWORD n;
145 if (WriteFile(f->hout, ptr, s, &n, NULL) && n > 0)
146 s = n;
148 else
149 #endif /* CONFOPT_WIN32 */
151 if (f->out != NULL)
152 s = fwrite(ptr, s, 1, f->out);
154 return s;
158 static int put_char(int c, struct mpdm_file *f)
159 /* writes a character in a file structure */
161 char tmp = c;
163 if (put_buf(&tmp, 1, f) != 1)
164 c = EOF;
166 return c;
170 static wchar_t *read_mbs(struct mpdm_file *f, int *s)
171 /* reads a multibyte string from a mpdm_file into a dynamic string */
173 wchar_t *ptr = NULL;
174 char *auxptr = NULL;
175 char tmp[100];
176 int c, i = 0, n = 0;
178 while ((c = get_char(f)) != EOF) {
179 tmp[i++] = c;
181 if (c == '\n')
182 break;
184 if (i == sizeof(tmp) - 1) {
185 /* out of space; start allocating */
186 if ((auxptr = mpdm_poke(auxptr, &n, tmp, i, sizeof(char))) == NULL)
187 return NULL;
189 i = 0;
193 /* is there something to return? */
194 if (i || n) {
195 /* NULL-terminate */
196 tmp[i++] = '\0';
198 if (n) {
199 /* auxiliary space used; concat all */
200 if ((auxptr = mpdm_poke(auxptr, &n, tmp, i, sizeof(char))) == NULL)
201 return NULL;
203 /* do the conversion */
204 ptr = mpdm_mbstowcs(auxptr, s, -1);
206 free(auxptr);
208 else
209 ptr = mpdm_mbstowcs(tmp, s, -1);
212 return ptr;
216 static int write_wcs(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 && get_char(f) == 0xff) {
832 enc = L"utf-32be";
833 f->f_read = read_utf32be;
834 goto got_encoding;
837 else
838 if (c == 0xfe) {
839 /* can be utf16be */
840 if (get_char(f) == 0xff) {
841 enc = L"utf-16be";
842 f->f_read = read_utf16be;
843 goto got_encoding;
846 else
847 if (c == 0xef) {
848 /* can be utf8 with BOM */
849 if (get_char(f) == 0xbb && get_char(f) == 0xbf) {
850 enc = L"utf-8bom";
851 f->f_read = read_utf8;
852 goto got_encoding;
855 else {
856 /* try if a first bunch of chars are valid UTF-8 */
857 int p = c;
858 int n = 10000;
859 int u = 0;
861 while (--n && (c = get_char(f)) != EOF) {
862 if ((c & 0xc0) == 0x80) {
863 if ((p & 0xc0) == 0xc0)
864 u++;
865 else
866 if ((p & 0x80) == 0x00) {
867 u = -1;
868 break;
871 else
872 if ((p & 0xc0) == 0xc0) {
873 u = -1;
874 break;
877 p = c;
880 if (u < 0) {
881 /* invalid utf-8; fall back to 8bit */
882 enc = L"8bit";
883 f->f_read = read_iso8859_1;
885 else
886 if (u > 0) {
887 /* utf-8 sequences found */
888 enc = L"utf-8";
889 f->f_read = read_utf8;
892 /* 7 bit ASCII: do nothing */
895 /* none of the above; restart */
896 fseek(f->in, 0, SEEK_SET);
899 got_encoding:
900 mpdm_hset_s(mpdm_root(), L"DETECTED_ENCODING", MPDM_LS(enc));
902 return f->f_read(f, s);
906 static mpdm_t new_mpdm_file(void)
907 /* creates a new file value */
909 mpdm_t v = NULL;
910 struct mpdm_file *fs;
911 mpdm_t e;
913 if ((fs = malloc(sizeof(struct mpdm_file))) == NULL)
914 return NULL;
916 memset(fs, '\0', sizeof(struct mpdm_file));
918 /* default I/O functions */
919 fs->f_read = read_auto;
920 fs->f_write = write_wcs;
922 #ifdef CONFOPT_ICONV
923 /* no iconv encodings by default */
924 fs->ic_enc = fs->ic_dec = (iconv_t) -1;
925 #endif
927 if ((v = mpdm_new(MPDM_FILE | MPDM_FREE, fs, sizeof(struct mpdm_file))) == NULL) {
928 free(fs);
929 return NULL;
932 e = mpdm_hget_s(mpdm_root(), L"ENCODING");
934 if (mpdm_size(e) == 0)
935 e = mpdm_hget_s(mpdm_root(), L"TEMP_ENCODING");
937 if (mpdm_size(e)) {
939 wchar_t *enc = mpdm_string(e);
941 if (wcscmp(enc, L"utf-8") == 0) {
942 fs->f_read = read_utf8_bom;
943 fs->f_write = write_utf8;
945 else
946 if (wcscmp(enc, L"utf-8bom") == 0) {
947 fs->f_read = read_utf8_bom;
948 fs->f_write = write_utf8_bom;
950 else
951 if (wcscmp(enc, L"iso8859-1") == 0 ||
952 wcscmp(enc, L"8bit") == 0) {
953 fs->f_read = read_iso8859_1;
954 fs->f_write = write_iso8859_1;
956 else
957 if (wcscmp(enc, L"utf-16le") == 0) {
958 fs->f_read = read_utf16le;
959 fs->f_write = write_utf16le_bom;
961 else
962 if (wcscmp(enc, L"utf-16be") == 0) {
963 fs->f_read = read_utf16be;
964 fs->f_write = write_utf16be_bom;
966 else
967 if (wcscmp(enc, L"utf-16") == 0) {
968 fs->f_read = read_utf16;
969 fs->f_write = write_utf16le_bom;
971 else
972 if (wcscmp(enc, L"utf-32le") == 0) {
973 fs->f_read = read_utf32le;
974 fs->f_write = write_utf32le_bom;
976 else
977 if (wcscmp(enc, L"utf-32be") == 0) {
978 fs->f_read = read_utf32be;
979 fs->f_write = write_utf32be_bom;
981 else
982 if (wcscmp(enc, L"utf-32") == 0) {
983 fs->f_read = read_utf32;
984 fs->f_write = write_utf32le_bom;
986 else {
987 #ifdef CONFOPT_ICONV
988 mpdm_t cs = MPDM_2MBS(e->data);
990 if ((fs->ic_enc = iconv_open((char *) cs->data, "WCHAR_T")) != (iconv_t) -1 &&
991 (fs->ic_dec = iconv_open("WCHAR_T", (char *) cs->data)) != (iconv_t) -1) {
993 fs->f_read = read_iconv;
994 fs->f_write = write_iconv;
996 #endif /* CONFOPT_ICONV */
999 mpdm_hset_s(mpdm_root(), L"TEMP_ENCODING", NULL);
1002 return v;
1006 static void destroy_mpdm_file(mpdm_t v)
1007 /* destroys and file value */
1009 struct mpdm_file *fs = (struct mpdm_file *)v->data;
1011 if (fs != NULL) {
1012 #ifdef CONFOPT_ICONV
1013 if (fs->ic_enc != (iconv_t) - 1) {
1014 iconv_close(fs->ic_enc);
1015 fs->ic_enc = (iconv_t) - 1;
1018 if (fs->ic_dec != (iconv_t) - 1) {
1019 iconv_close(fs->ic_dec);
1020 fs->ic_dec = (iconv_t) - 1;
1022 #endif
1024 free(fs);
1025 v->data = NULL;
1030 /** interface **/
1032 wchar_t *mpdm_read_mbs(FILE * f, int *s)
1033 /* reads a multibyte string from a stream into a dynamic string */
1035 struct mpdm_file fs;
1037 /* reset the structure */
1038 memset(&fs, '\0', sizeof(fs));
1039 fs.in = f;
1041 return read_mbs(&fs, s);
1045 int mpdm_write_wcs(FILE * f, const wchar_t * str)
1046 /* writes a wide string to a stream */
1048 struct mpdm_file fs;
1050 /* reset the structure */
1051 memset(&fs, '\0', sizeof(fs));
1052 fs.out = f;
1054 return write_wcs(&fs, str);
1058 mpdm_t mpdm_new_f(FILE * f)
1059 /* creates a new file value from a FILE * */
1061 mpdm_t v = NULL;
1063 if (f == NULL)
1064 return NULL;
1066 if ((v = new_mpdm_file()) != NULL) {
1067 struct mpdm_file *fs = (struct mpdm_file *)v->data;
1068 fs->in = fs->out = f;
1071 return v;
1076 * mpdm_open - Opens a file.
1077 * @filename: the file name
1078 * @mode: an fopen-like mode string
1080 * Opens a file. If @filename can be open in the specified @mode, an
1081 * mpdm_t value will be returned containing the file descriptor, or NULL
1082 * otherwise.
1084 * If the file is open for reading, some charset detection methods are
1085 * used. If any of them is successful, its name is stored in the
1086 * DETECTED_ENCODING element of the mpdm_root() hash. This value is
1087 * suitable to be copied over ENCODING or TEMP_ENCODING.
1089 * If the file is open for writing, the encoding to be used is read from
1090 * the ENCODING element of mpdm_root() and, if not set, from the
1091 * TEMP_ENCODING one. The latter will always be deleted afterwards.
1092 * [File Management]
1094 mpdm_t mpdm_open(const mpdm_t filename, const mpdm_t mode)
1096 FILE *f;
1097 mpdm_t fn;
1098 mpdm_t m;
1100 if (filename == NULL || mode == NULL)
1101 return NULL;
1103 /* convert to mbs,s */
1104 fn = MPDM_2MBS(filename->data);
1105 m = 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 return MPDM_F(f);
1129 * mpdm_close - Closes a file descriptor.
1130 * @fd: the value containing the file descriptor
1132 * Closes the file descriptor.
1133 * [File Management]
1135 mpdm_t mpdm_close(mpdm_t fd)
1137 struct mpdm_file *fs = (struct mpdm_file *)fd->data;
1139 if ((fd->flags & MPDM_FILE) && fs != NULL) {
1140 if (fs->in != NULL)
1141 fclose(fs->in);
1143 if (fs->out != fs->in && fs->out != NULL)
1144 fclose(fs->out);
1146 destroy_mpdm_file(fd);
1149 return NULL;
1154 * mpdm_read - Reads a line from a file descriptor.
1155 * @fd: the value containing the file descriptor
1157 * Reads a line from @fd. Returns the line, or NULL on EOF.
1158 * [File Management]
1159 * [Character Set Conversion]
1161 mpdm_t mpdm_read(const mpdm_t fd)
1163 mpdm_t v = NULL;
1164 wchar_t *ptr;
1165 int s;
1166 struct mpdm_file *fs = (struct mpdm_file *)fd->data;
1168 if (fs == NULL)
1169 return NULL;
1171 ptr = fs->f_read(fs, &s);
1173 if (ptr != NULL)
1174 v = MPDM_ENS(ptr, s);
1176 return v;
1180 mpdm_t mpdm_getchar(const mpdm_t fd)
1182 int c;
1183 wchar_t tmp[2];
1184 struct mpdm_file *fs = (struct mpdm_file *)fd->data;
1186 if (fs == NULL || (c = get_char(fs)) == EOF)
1187 return NULL;
1189 /* get the char as-is */
1190 tmp[0] = (wchar_t) c;
1191 tmp[1] = L'\0';
1193 return MPDM_S(tmp);
1197 mpdm_t mpdm_putchar(const mpdm_t fd, const mpdm_t c)
1199 struct mpdm_file *fs = (struct mpdm_file *)fd->data;
1200 const wchar_t *ptr = mpdm_string(c);
1202 if (fs == NULL || put_char(*ptr, fs) == -1)
1203 return NULL;
1205 return c;
1210 * mpdm_write - Writes a value into a file.
1211 * @fd: the file descriptor.
1212 * @v: the value to be written.
1214 * Writes the @v string value into @fd, using the current encoding.
1215 * [File Management]
1216 * [Character Set Conversion]
1218 int mpdm_write(const mpdm_t fd, const mpdm_t v)
1220 struct mpdm_file *fs = (struct mpdm_file *)fd->data;
1221 int ret = -1;
1223 if (fs == NULL)
1224 return -1;
1226 ret = fs->f_write(fs, mpdm_string(v));
1228 return ret;
1232 int mpdm_fseek(const mpdm_t fd, long offset, int whence)
1234 struct mpdm_file *fs = (struct mpdm_file *)fd->data;
1236 return fseek(fs->in, offset, whence);
1240 long mpdm_ftell(const mpdm_t fd)
1242 struct mpdm_file *fs = (struct mpdm_file *)fd->data;
1244 return ftell(fs->in);
1248 FILE * mpdm_get_filehandle(const mpdm_t fd)
1250 FILE * f = NULL;
1252 if (fd->flags & MPDM_FILE) {
1253 struct mpdm_file *fs = (struct mpdm_file *)fd->data;
1254 f = fs->in;
1257 return f;
1262 mpdm_t mpdm_bread(mpdm_t fd, int size)
1267 int mpdm_bwrite(mpdm_tfd, mpdm_t v, int size)
1273 static mpdm_t embedded_encodings(void)
1275 mpdm_t e;
1276 wchar_t *e2e[] = {
1277 L"utf-8", L"utf-8",
1278 L"utf8", NULL,
1279 L"iso8859-1", L"iso8859-1",
1280 L"iso-8859-1", NULL,
1281 L"8bit", NULL,
1282 L"latin1", NULL,
1283 L"latin-1", NULL,
1284 L"utf-16le", L"utf-16le",
1285 L"utf16le", NULL,
1286 L"ucs-2le", NULL,
1287 L"utf-16be", L"utf-16be",
1288 L"utf16be", NULL,
1289 L"ucs-2be", NULL,
1290 L"utf-16", L"utf-16",
1291 L"utf16", NULL,
1292 L"ucs-2", NULL,
1293 L"ucs2", NULL,
1294 L"utf-32le", L"utf-32le",
1295 L"utf32le", NULL,
1296 L"ucs-4le", NULL,
1297 L"utf-32be", L"utf-32be",
1298 L"utf32be", NULL,
1299 L"ucs-4be", NULL,
1300 L"utf-32", L"utf-32",
1301 L"utf32", NULL,
1302 L"ucs-4", NULL,
1303 L"ucs4", NULL,
1304 L"utf-8bom", L"utf-8bom",
1305 L"utf8bom", NULL,
1306 NULL, NULL
1309 if ((e = mpdm_hget_s(mpdm_root(), L"EMBEDDED_ENCODINGS")) == NULL) {
1310 int n;
1311 wchar_t *p = NULL;
1313 e = MPDM_H(0);
1315 for (n = 0; e2e[n] != NULL; n += 2) {
1316 mpdm_t v = MPDM_S(e2e[n]);
1318 if (e2e[n + 1] != NULL)
1319 p = e2e[n + 1];
1321 mpdm_hset(e, v, MPDM_S(p));
1322 mpdm_hset(e, mpdm_ulc(v, 1), MPDM_S(p));
1325 mpdm_hset_s(mpdm_root(), L"EMBEDDED_ENCODINGS", e);
1328 return e;
1333 * mpdm_encoding - Sets the current charset encoding for files.
1334 * @charset: the charset name.
1336 * Sets the current charset encoding for files. Future opened
1337 * files will be assumed to be encoded with @charset, which can
1338 * be any of the supported charset names (utf-8, iso-8859-1, etc.),
1339 * and converted on each read / write. If charset is NULL, it
1340 * is reverted to default charset conversion (i.e. the one defined
1341 * in the locale).
1343 * This function stores the @charset value into the ENCODING item
1344 * of the mpdm_root() hash.
1346 * Returns a negative number if @charset is unsupported, or zero
1347 * if no errors were found.
1348 * [File Management]
1349 * [Character Set Conversion]
1351 int mpdm_encoding(mpdm_t charset)
1353 int ret = -1;
1354 mpdm_t e = embedded_encodings();
1355 mpdm_t v = NULL;
1357 /* NULL encoding? done */
1358 if (mpdm_size(charset) == 0) {
1359 mpdm_hset_s(mpdm_root(), L"ENCODING", NULL);
1360 return 0;
1363 #ifdef CONFOPT_ICONV
1365 iconv_t ic;
1366 mpdm_t cs = MPDM_2MBS(charset->data);
1368 /* tries to create an iconv encoder and decoder for this charset */
1370 if ((ic = iconv_open("WCHAR_T", (char *) cs->data)) == (iconv_t) - 1)
1371 ret = -1;
1372 else {
1373 iconv_close(ic);
1375 if ((ic = iconv_open((char *) cs->data, "WCHAR_T")) == (iconv_t) - 1)
1376 ret = -2;
1377 else {
1378 iconv_close(ic);
1380 /* got a valid encoding */
1381 v = charset;
1382 ret = 0;
1386 #endif /* CONFOPT_ICONV */
1388 if (ret != 0 && (v = mpdm_hget(e, charset)) != NULL)
1389 ret = 0;
1391 if (ret == 0)
1392 mpdm_hset_s(mpdm_root(), L"ENCODING", v);
1394 return ret;
1399 * mpdm_unlink - Deletes a file.
1400 * @filename: file name to be deleted
1402 * Deletes a file.
1403 * [File Management]
1405 int mpdm_unlink(const mpdm_t filename)
1407 int ret;
1408 mpdm_t fn;
1410 /* convert to mbs */
1411 fn = MPDM_2MBS(filename->data);
1413 if ((ret = unlink((char *) fn->data)) == -1)
1414 store_syserr();
1416 return ret;
1421 * mpdm_stat - Gives status from a file.
1422 * @filename: file name to get the status from
1424 * Returns a 14 element array of the status (permissions, onwer, etc.)
1425 * from the desired @filename, or NULL if the file cannot be accessed.
1426 * (man 2 stat).
1428 * The values are: 0, device number of filesystem; 1, inode number;
1429 * 2, file mode; 3, number of hard links to the file; 4, uid; 5, gid;
1430 * 6, device identifier; 7, total size of file in bytes; 8, atime;
1431 * 9, mtime; 10, ctime; 11, preferred block size for system I/O;
1432 * 12, number of blocks allocated and 13, canonicalized file name.
1433 * Not all elements have necesarily meaningful values, as most are
1434 * system-dependent.
1435 * [File Management]
1437 mpdm_t mpdm_stat(const mpdm_t filename)
1439 mpdm_t r = NULL;
1441 #ifdef CONFOPT_SYS_STAT_H
1442 struct stat s;
1443 mpdm_t fn;
1445 fn = MPDM_2MBS(filename->data);
1447 if (stat((char *) fn->data, &s) != -1) {
1448 r = MPDM_A(14);
1450 mpdm_aset(r, MPDM_I(s.st_dev), 0);
1451 mpdm_aset(r, MPDM_I(s.st_ino), 1);
1452 mpdm_aset(r, MPDM_I(s.st_mode), 2);
1453 mpdm_aset(r, MPDM_I(s.st_nlink), 3);
1454 mpdm_aset(r, MPDM_I(s.st_uid), 4);
1455 mpdm_aset(r, MPDM_I(s.st_gid), 5);
1456 mpdm_aset(r, MPDM_I(s.st_rdev), 6);
1457 mpdm_aset(r, MPDM_I(s.st_size), 7);
1458 mpdm_aset(r, MPDM_I(s.st_atime), 8);
1459 mpdm_aset(r, MPDM_I(s.st_mtime), 9);
1460 mpdm_aset(r, MPDM_I(s.st_ctime), 10);
1461 mpdm_aset(r, MPDM_I(0), 11); /* s.st_blksize */
1462 mpdm_aset(r, MPDM_I(0), 12); /* s.st_blocks */
1464 #ifdef CONFOPT_CANONICALIZE_FILE_NAME
1467 char * ptr;
1469 if ((ptr = canonicalize_file_name(
1470 (char *)fn->data)) != NULL) {
1471 mpdm_aset(r, MPDM_MBS(ptr), 13);
1472 free(ptr);
1475 #endif
1477 #ifdef CONFOPT_REALPATH
1479 char tmp[2048];
1481 if (realpath((char *)fn->data, tmp) != NULL)
1482 mpdm_aset(r, MPDM_MBS(tmp), 13);
1484 #endif
1486 #ifdef CONFOPT_FULLPATH
1488 char tmp[_MAX_PATH + 1];
1490 if (_fullpath(tmp, (char *)fn->data, _MAX_PATH) != NULL)
1491 mpdm_aset(r, MPDM_MBS(tmp), 13);
1493 #endif
1496 else
1497 store_syserr();
1499 #endif /* CONFOPT_SYS_STAT_H */
1501 return r;
1506 * mpdm_chmod - Changes a file's permissions.
1507 * @filename: the file name
1508 * @perms: permissions (element 2 from mpdm_stat())
1510 * Changes the permissions for a file.
1511 * [File Management]
1513 int mpdm_chmod(const mpdm_t filename, mpdm_t perms)
1515 int r = -1;
1517 mpdm_t fn = MPDM_2MBS(filename->data);
1519 if ((r = chmod((char *) fn->data, mpdm_ival(perms))) == -1)
1520 store_syserr();
1522 return r;
1527 * mpdm_chdir - Changes the working directory
1528 * @dir: the new path
1530 * Changes the working directory
1531 * [File Management]
1533 int mpdm_chdir(const mpdm_t dir)
1535 int r = -1;
1537 mpdm_t fn = MPDM_2MBS(dir->data);
1539 if ((r = chdir((char *) fn->data)) == -1)
1540 store_syserr();
1542 return r;
1547 * mpdm_chown - Changes a file's owner.
1548 * @filename: the file name
1549 * @uid: user id (element 4 from mpdm_stat())
1550 * @gid: group id (element 5 from mpdm_stat())
1552 * Changes the owner and group id's for a file.
1553 * [File Management]
1555 int mpdm_chown(const mpdm_t filename, mpdm_t uid, mpdm_t gid)
1557 int r = -1;
1559 #ifdef CONFOPT_CHOWN
1561 mpdm_t fn = MPDM_2MBS(filename->data);
1563 if ((r = chown((char *) fn->data, mpdm_ival(uid), mpdm_ival(gid))) == -1)
1564 store_syserr();
1566 #endif /* CONFOPT_CHOWN */
1568 return r;
1573 * mpdm_glob - Executes a file globbing.
1574 * @spec: Globbing spec
1575 * @base: Optional base directory
1577 * Executes a file globbing. @spec is system-dependent, but usually
1578 * the * and ? metacharacters work everywhere. @base can contain a
1579 * directory; if that's the case, the output strings will include it.
1580 * In any case, each returned value will be suitable for a call to
1581 * mpdm_open().
1583 * Returns an array of files that match the globbing (can be an empty
1584 * array if no file matches), or NULL if globbing is unsupported.
1585 * [File Management]
1587 mpdm_t mpdm_glob(const mpdm_t spec, const mpdm_t base)
1589 mpdm_t d = NULL;
1590 mpdm_t f = NULL;
1591 mpdm_t v = NULL;
1593 #ifdef CONFOPT_WIN32
1595 WIN32_FIND_DATA fd;
1596 HANDLE h;
1597 char *ptr;
1598 mpdm_t w;
1599 mpdm_t s = NULL;
1600 mpdm_t sp = NULL;
1602 if (mpdm_size(base))
1603 sp = mpdm_strcat_s(base, L"/");
1605 if (mpdm_size(spec) == 0)
1606 sp = mpdm_strcat_s(sp, L"*.*");
1607 else
1608 sp = mpdm_strcat(sp, spec);
1610 /* delete repeated directory delimiters */
1611 sp = mpdm_sregex(MPDM_LS(L"@[\\/]+@g"), sp, MPDM_LS(L"/"), 0);
1613 sp = MPDM_2MBS(sp->data);
1615 v = MPDM_A(0);
1616 d = MPDM_A(0);
1617 f = MPDM_A(0);
1619 if ((h = FindFirstFile((char *) sp->data, &fd)) != INVALID_HANDLE_VALUE) {
1620 /* if spec includes a directory, store in s */
1621 if ((ptr = strrchr((char *) sp->data, '/')) != NULL) {
1622 *(ptr + 1) = '\0';
1623 s = MPDM_MBS(sp->data);
1626 do {
1627 /* ignore . and .. */
1628 if (strcmp(fd.cFileName, ".") == 0 || strcmp(fd.cFileName, "..") == 0)
1629 continue;
1631 /* concat base directory and file names */
1632 w = mpdm_strcat(s, MPDM_MBS(fd.cFileName));
1634 /* if it's a directory, add a / */
1635 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1636 w = mpdm_strcat_s(w, L"/");
1637 mpdm_push(d, w);
1639 else
1640 mpdm_push(f, w);
1642 while (FindNextFile(h, &fd));
1644 FindClose(h);
1647 #endif
1649 #if CONFOPT_GLOB_H
1651 /* glob.h support */
1652 glob_t globbuf;
1653 const char *ptr;
1655 /* build full path */
1656 if (mpdm_size(base))
1657 v = mpdm_strcat_s(base, L"/");
1659 if (mpdm_size(spec) == 0)
1660 v = mpdm_strcat_s(v, L"*");
1661 else
1662 v = mpdm_strcat(v, spec);
1664 /* delete repeated directory delimiters */
1665 v = mpdm_sregex(MPDM_LS(L"@/{2,}@g"), v, MPDM_LS(L"/"), 0);
1667 v = MPDM_2MBS(v->data);
1669 ptr = v->data;
1671 globbuf.gl_offs = 1;
1673 v = MPDM_A(0);
1674 d = MPDM_A(0);
1675 f = MPDM_A(0);
1677 if (glob(ptr, GLOB_MARK, NULL, &globbuf) == 0) {
1678 int n;
1680 for (n = 0; globbuf.gl_pathv[n] != NULL; n++) {
1681 char *ptr = globbuf.gl_pathv[n];
1682 mpdm_t t = MPDM_MBS(ptr);
1684 /* if last char is /, add to directories */
1685 if (ptr[strlen(ptr) - 1] == '/')
1686 mpdm_push(d, t);
1687 else
1688 mpdm_push(f, t);
1692 globfree(&globbuf);
1694 #else
1696 /* no win32 nor glob.h; try workaround */
1697 /* ... */
1699 #endif
1701 if (v != NULL) {
1702 int n;
1704 d = mpdm_sort(d, 1);
1705 f = mpdm_sort(f, 1);
1707 /* transfer all data in d and f */
1708 for (n = 0; n < mpdm_size(d); n++)
1709 mpdm_push(v, mpdm_aget(d, n));
1710 for (n = 0; n < mpdm_size(f); n++)
1711 mpdm_push(v, mpdm_aget(f, n));
1714 return v;
1718 #ifdef CONFOPT_WIN32
1720 static void win32_pipe(HANDLE * h, int n)
1722 SECURITY_ATTRIBUTES sa;
1723 HANDLE cp, t;
1725 memset(&sa, '\0', sizeof(sa));
1726 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
1727 sa.bInheritHandle = TRUE;
1728 sa.lpSecurityDescriptor = NULL;
1730 cp = GetCurrentProcess();
1732 CreatePipe(&h[0], &h[1], &sa, 0);
1733 DuplicateHandle(cp, h[n], cp, &t, 0, FALSE, DUPLICATE_SAME_ACCESS);
1734 CloseHandle(h[n]);
1735 h[n] = t;
1739 static int sysdep_popen(mpdm_t v, char *prg, int rw)
1740 /* win32-style pipe */
1742 HANDLE pr[2];
1743 HANDLE pw[2];
1744 PROCESS_INFORMATION pi;
1745 STARTUPINFO si;
1746 int ret;
1747 struct mpdm_file *fs = v->data;
1749 /* init all */
1750 pr[0] = pr[1] = pw[0] = pw[1] = NULL;
1752 if (rw & 0x01)
1753 win32_pipe(pr, 0);
1754 if (rw & 0x02)
1755 win32_pipe(pw, 1);
1757 /* spawn new process */
1758 memset(&pi, '\0', sizeof(pi));
1759 memset(&si, '\0', sizeof(si));
1761 si.cb = sizeof(STARTUPINFO);
1762 si.hStdError = pr[1];
1763 si.hStdOutput = pr[1];
1764 si.hStdInput = pw[0];
1765 si.dwFlags |= STARTF_USESTDHANDLES;
1767 ret = CreateProcess(NULL, prg, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
1769 if (rw & 0x01)
1770 CloseHandle(pr[1]);
1771 if (rw & 0x02)
1772 CloseHandle(pw[0]);
1774 fs->hin = pr[0];
1775 fs->hout = pw[1];
1777 return ret;
1781 static int sysdep_pclose(const mpdm_t v)
1783 struct mpdm_file *fs = v->data;
1785 if (fs->hin != NULL)
1786 CloseHandle(fs->hin);
1788 if (fs->hout != NULL)
1789 CloseHandle(fs->hout);
1791 /* how to know process exit code? */
1792 return 0;
1796 #else /* CONFOPT_WIN32 */
1798 static int sysdep_popen(mpdm_t v, char *prg, int rw)
1799 /* unix-style pipe open */
1801 int pr[2], pw[2];
1802 struct mpdm_file *fs = (struct mpdm_file *)v->data;
1804 /* init all */
1805 pr[0] = pr[1] = pw[0] = pw[1] = -1;
1807 if (rw & 0x01)
1808 pipe(pr);
1809 if (rw & 0x02)
1810 pipe(pw);
1812 if (fork() == 0) {
1813 /* child process */
1814 if (rw & 0x01) {
1815 close(1);
1816 dup(pr[1]);
1817 close(pr[0]);
1819 if (rw & 0x02) {
1820 close(0);
1821 dup(pw[0]);
1822 close(pw[1]);
1825 /* redirect stderr to stdout */
1826 close(2);
1827 dup(1);
1829 /* run the program */
1830 execlp("/bin/sh", "/bin/sh", "-c", prg, NULL);
1831 execlp(prg, prg, NULL);
1833 /* still here? exec failed; close pipes and exit */
1834 close(0);
1835 close(1);
1836 exit(0);
1839 /* create the pipes as non-buffered streams */
1840 if (rw & 0x01) {
1841 fs->in = fdopen(pr[0], "r");
1842 setvbuf(fs->in, NULL, _IONBF, 0);
1843 close(pr[1]);
1846 if (rw & 0x02) {
1847 fs->out = fdopen(pw[1], "w");
1848 setvbuf(fs->out, NULL, _IONBF, 0);
1849 close(pw[0]);
1852 return 1;
1856 static int sysdep_pclose(const mpdm_t v)
1857 /* unix-style pipe close */
1859 int s;
1860 struct mpdm_file *fs = (struct mpdm_file *)v->data;
1862 if (fs->in != NULL)
1863 fclose(fs->in);
1865 if (fs->out != fs->in && fs->out != NULL)
1866 fclose(fs->out);
1868 wait(&s);
1870 return s;
1874 #endif /* CONFOPT_WIN32 */
1878 * mpdm_popen - Opens a pipe.
1879 * @prg: the program to pipe
1880 * @mode: an fopen-like mode string
1882 * Opens a pipe to a program. If @prg can be open in the specified @mode, an
1883 * mpdm_t value will be returned containing the file descriptor, or NULL
1884 * otherwise.
1885 * [File Management]
1887 mpdm_t mpdm_popen(const mpdm_t prg, const mpdm_t mode)
1889 mpdm_t v, pr, md;
1890 char *m;
1891 int rw = 0;
1893 if (prg == NULL || mode == NULL)
1894 return NULL;
1896 if ((v = new_mpdm_file()) == NULL)
1897 return NULL;
1899 /* convert to mbs,s */
1900 pr = MPDM_2MBS(prg->data);
1901 md = MPDM_2MBS(mode->data);
1903 /* get the mode */
1904 m = (char *) md->data;
1906 /* set the mode */
1907 if (m[0] == 'r')
1908 rw = 0x01;
1909 if (m[0] == 'w')
1910 rw = 0x02;
1911 if (m[1] == '+')
1912 rw = 0x03; /* r+ or w+ */
1914 if (!sysdep_popen(v, (char *) pr->data, rw)) {
1915 destroy_mpdm_file(v);
1916 v = NULL;
1919 return v;
1924 * mpdm_pclose - Closes a pipe.
1925 * @fd: the value containing the file descriptor
1927 * Closes a pipe.
1928 * [File Management]
1930 mpdm_t mpdm_pclose(mpdm_t fd)
1932 mpdm_t r = NULL;
1934 if ((fd->flags & MPDM_FILE) && fd->data != NULL) {
1935 r = MPDM_I(sysdep_pclose(fd));
1936 destroy_mpdm_file(fd);
1939 return r;
1944 * mpdm_home_dir - Returns the home user directory.
1946 * Returns a system-dependent directory where the user can write
1947 * documents and create subdirectories.
1948 * [File Management]
1950 mpdm_t mpdm_home_dir(void)
1952 mpdm_t r = NULL;
1953 char *ptr;
1954 char tmp[512] = "";
1956 #ifdef CONFOPT_WIN32
1958 LPITEMIDLIST pidl;
1960 /* get the 'My Documents' folder */
1961 SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &pidl);
1962 SHGetPathFromIDList(pidl, tmp);
1963 strcat(tmp, "\\");
1965 #endif
1967 #ifdef CONFOPT_PWD_H
1969 struct passwd *p;
1971 /* get home dir from /etc/passwd entry */
1972 if (tmp[0] == '\0' && (p = getpwuid(getpid())) != NULL) {
1973 strcpy(tmp, p->pw_dir);
1974 strcat(tmp, "/");
1977 #endif
1979 /* still none? try the ENV variable $HOME */
1980 if (tmp[0] == '\0' && (ptr = getenv("HOME")) != NULL) {
1981 strcpy(tmp, ptr);
1982 strcat(tmp, "/");
1985 if (tmp[0] != '\0')
1986 r = MPDM_MBS(tmp);
1988 return r;
1993 * mpdm_app_dir - Returns the applications directory.
1995 * Returns a system-dependent directory where the applications store
1996 * their private data, as components or resources.
1997 * [File Management]
1999 mpdm_t mpdm_app_dir(void)
2001 mpdm_t r = NULL;
2003 #ifdef CONFOPT_WIN32
2005 HKEY hkey;
2006 char tmp[MAX_PATH];
2007 LPITEMIDLIST pidl;
2009 /* get the 'Program Files' folder (can fail) */
2010 tmp[0] = '\0';
2011 if (SHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidl) == S_OK)
2012 SHGetPathFromIDList(pidl, tmp);
2014 /* if it's still empty, get from the registry */
2015 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
2016 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
2017 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS) {
2018 int n = sizeof(tmp);
2020 if (RegQueryValueEx(hkey, "ProgramFilesDir",
2021 NULL, NULL, tmp, (LPDWORD) & n) != ERROR_SUCCESS)
2022 tmp[0] = '\0';
2025 if (tmp[0] != '\0') {
2026 strcat(tmp, "\\");
2027 r = MPDM_MBS(tmp);
2029 #endif
2031 /* still none? get the configured directory */
2032 if (r == NULL)
2033 r = MPDM_MBS(CONFOPT_PREFIX "/share/");
2035 return r;