New Makefile target realdistclean.
[mpdm.git] / mpdm_f.c
blob143d2a95f7e77e7ae82755cf658178f7b6a16429
1 /*
3 MPDM - Minimum Profit Data Manager
4 Copyright (C) 2003/2007 Angel Ortega <angel@triptico.com>
6 mpdm_f.c - File management
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 http://www.triptico.com
26 #include "config.h"
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <wchar.h>
33 #ifdef CONFOPT_UNISTD_H
34 #include <unistd.h>
35 #endif
37 #ifdef CONFOPT_GLOB_H
38 #include <glob.h>
39 #endif
41 #ifdef CONFOPT_WIN32
43 #include <windows.h>
44 #include <commctrl.h>
45 #include <shlobj.h>
47 #endif
49 #ifdef CONFOPT_SYS_TYPES_H
50 #include <sys/types.h>
51 #endif
53 #ifdef CONFOPT_SYS_WAIT_H
54 #include <sys/wait.h>
55 #endif
57 #ifdef CONFOPT_SYS_STAT_H
58 #include <sys/stat.h>
59 #endif
61 #ifdef CONFOPT_PWD_H
62 #include <pwd.h>
63 #endif
65 #include "mpdm.h"
67 #ifdef CONFOPT_ICONV
69 #include <iconv.h>
71 #endif
73 /* file structure */
74 struct mpdm_file {
75 FILE *in;
76 FILE *out;
78 #ifdef CONFOPT_ICONV
80 iconv_t ic_enc;
81 iconv_t ic_dec;
83 #else /* CONFOPT_ICONV */
85 int utf8;
87 #endif /* CONFOPT_ICONV */
89 #ifdef CONFOPT_WIN32
91 HANDLE hin;
92 HANDLE hout;
94 #endif /* CONFOPT_WIN32 */
97 #include <errno.h>
98 extern int errno;
101 /*******************
102 Code
103 ********************/
106 static void store_syserr(void)
107 /* stores the system error inside the global ERRNO */
109 mpdm_hset_s(mpdm_root(), L"ERRNO", MPDM_MBS(strerror(errno)));
113 static int get_char(struct mpdm_file *f)
114 /* reads a character from a file structure */
116 int c = EOF;
118 #ifdef CONFOPT_WIN32
120 if (f->hin != NULL) {
121 char tmp;
122 DWORD n;
124 if (ReadFile(f->hin, &tmp, 1, &n, NULL) && n > 0)
125 c = (int) tmp;
128 #endif /* CONFOPT_WIN32 */
130 if (f->in != NULL) {
131 /* read (converting to positive if needed) */
132 if ((c = fgetc(f->in)) < 0 && !feof(f->in))
133 c += 256;
136 return c;
140 static int put_buf(char *ptr, int s, struct mpdm_file *f)
141 /* writes s bytes in the buffer in ptr to f */
143 #ifdef CONFOPT_WIN32
145 if (f->hout != NULL) {
146 DWORD n;
148 if (WriteFile(f->hout, ptr, s, &n, NULL) && n > 0)
149 s = n;
151 else
152 #endif /* CONFOPT_WIN32 */
154 if (f->out != NULL)
155 s = fwrite(ptr, s, 1, f->out);
157 return s;
161 static int put_char(int c, struct mpdm_file *f)
162 /* writes a character in a file structure */
164 char tmp = c;
166 if (put_buf(&tmp, 1, f) != 1)
167 c = EOF;
169 return c;
173 static wchar_t *read_mbs(struct mpdm_file *f, int *s)
174 /* reads a multibyte string from a mpdm_file into a dynamic string */
176 wchar_t *ptr = NULL;
177 char *auxptr = NULL;
178 char tmp[100];
179 int c, i = 0, n = 0;
181 while ((c = get_char(f)) != EOF) {
182 tmp[i++] = c;
184 if (c == '\n')
185 break;
187 if (i == sizeof(tmp) - 1) {
188 /* out of space; start allocating */
189 if ((auxptr = mpdm_poke(auxptr, &n, tmp, i, sizeof(char))) == NULL)
190 return NULL;
192 i = 0;
196 /* is there something to return? */
197 if (i || n) {
198 /* NULL-terminate */
199 tmp[i++] = '\0';
201 if (n) {
202 /* auxiliary space used; concat all */
203 if ((auxptr = mpdm_poke(auxptr, &n, tmp, i, sizeof(char))) == NULL)
204 return NULL;
206 /* do the conversion */
207 ptr = mpdm_mbstowcs(auxptr, s, -1);
209 free(auxptr);
211 else
212 ptr = mpdm_mbstowcs(tmp, s, -1);
215 return ptr;
219 static int write_wcs(struct mpdm_file *f, wchar_t * str)
220 /* writes a wide string to an struct mpdm_file */
222 int s;
223 char *ptr;
225 ptr = mpdm_wcstombs(str, &s);
226 s = put_buf(ptr, s, f);
227 free(ptr);
229 return s;
233 #ifdef CONFOPT_ICONV
235 static wchar_t *read_iconv(struct mpdm_file *f, int *s)
236 /* reads a multibyte string transforming with iconv */
238 char tmp[128];
239 wchar_t *ptr = NULL;
240 int c, i;
241 wchar_t wc;
243 *s = i = 0;
245 /* resets the decoder */
246 iconv(f->ic_dec, NULL, NULL, NULL, NULL);
248 while ((c = get_char(f)) != EOF) {
249 size_t il, ol;
250 char *iptr, *optr;
252 tmp[i++] = c;
254 /* too big? shouldn't happen */
255 if (i == sizeof(tmp))
256 break;
258 il = i;
259 iptr = tmp;
260 ol = sizeof(wchar_t);
261 optr = (char *) &wc;
263 /* write to file */
264 if (iconv(f->ic_dec, &iptr, &il, &optr, &ol) == -1) {
265 /* found incomplete multibyte character */
266 if (errno == EINVAL)
267 continue;
269 /* otherwise, return '?' */
270 wc = L'?';
273 i = 0;
275 if ((ptr = mpdm_poke(ptr, s, &wc, 1, sizeof(wchar_t))) == NULL)
276 break;
278 /* if it's an end of line, finish */
279 if (wc == L'\n')
280 break;
283 if (ptr != NULL) {
284 ptr = mpdm_poke(ptr, s, L"", 1, sizeof(wchar_t));
285 (*s)--;
288 return ptr;
292 static int write_iconv(struct mpdm_file *f, wchar_t * str)
293 /* writes a wide string to a stream using iconv */
295 char tmp[128];
296 int cnt = 0;
298 /* resets the encoder */
299 iconv(f->ic_enc, NULL, NULL, NULL, NULL);
301 /* convert char by char */
302 for (; *str != L'\0'; str++) {
303 size_t il, ol;
304 char *iptr, *optr;
305 int n;
307 il = sizeof(wchar_t);
308 iptr = (char *) str;
309 ol = sizeof(tmp);
310 optr = tmp;
312 /* write to file */
313 if (iconv(f->ic_enc, &iptr, &il, &optr, &ol) == -1) {
314 /* error converting; convert a '?' instead */
315 wchar_t q = L'?';
317 il = sizeof(wchar_t);
318 iptr = (char *) &q;
319 ol = sizeof(tmp);
320 optr = tmp;
322 iconv(f->ic_enc, &iptr, &il, &optr, &ol);
325 for (n = 0; n < sizeof(tmp) - ol; n++, cnt++) {
326 if (put_char(tmp[n], f) == EOF)
327 return -1;
331 return cnt;
335 #else /* CONFOPT_ICONV */
337 #define UTF8_BYTE() if((c = get_char(f)) == EOF) break
339 static wchar_t *read_utf8(struct mpdm_file *f, int *s)
340 /* crappy, ad-hoc utf8 reader */
342 wchar_t *ptr = NULL;
343 wchar_t wc;
344 int c;
346 *s = 0;
348 for (;;) {
349 wc = L'\0';
351 UTF8_BYTE();
353 if ((c & 0x80) == 0)
354 wc = c;
355 else
356 if ((c & 0xe0) == 0xe0) {
357 wc = (c & 0x1f) << 12;
358 UTF8_BYTE();
359 wc |= (c & 0x3f) << 6;
360 UTF8_BYTE();
361 wc |= (c & 0x3f);
363 else {
364 wc = (c & 0x3f) << 6;
365 UTF8_BYTE();
366 wc |= (c & 0x3f);
369 /* store */
370 if ((ptr = mpdm_poke(ptr, s, &wc, 1, sizeof(wchar_t))) == NULL)
371 break;
373 /* if it's an end of line, finish */
374 if (wc == L'\n')
375 break;
378 if (ptr != NULL) {
379 ptr = mpdm_poke(ptr, s, L"", 1, sizeof(wchar_t));
380 (*s)--;
383 return ptr;
387 static int write_utf8(struct mpdm_file *f, wchar_t * str)
388 /* crappy, ad-hoc utf8 writer */
390 int cnt = 0;
391 wchar_t wc;
393 /* convert char by char */
394 for (; (wc = *str) != L'\0'; str++) {
395 if (wc < 0x80)
396 put_char((int) wc, f);
397 else
398 if (wc < 0x800) {
399 put_char((int) (0xc0 | (wc >> 6)), f);
400 put_char((int) (0x80 | (wc & 0x3f)), f);
401 cnt++;
403 else {
404 put_char((int) (0xe0 | (wc >> 12)), f);
405 put_char((int) (0x80 | ((wc >> 6) & 0x3f)), f);
406 put_char((int) (0x80 | (wc & 0x3f)), f);
407 cnt += 2;
410 cnt++;
413 return cnt;
417 #endif /* CONFOPT_ICONV */
420 static mpdm_t new_mpdm_file(void)
421 /* creates a new file value */
423 mpdm_t v = NULL;
424 struct mpdm_file *fs;
426 if ((fs = malloc(sizeof(struct mpdm_file))) == NULL)
427 return NULL;
429 memset(fs, '\0', sizeof(struct mpdm_file));
431 #ifdef CONFOPT_ICONV
433 if ((v = mpdm_hget_s(mpdm_root(), L"ENCODING")) != NULL) {
434 mpdm_t cs = MPDM_2MBS(v->data);
436 fs->ic_enc = iconv_open((char *) cs->data, "WCHAR_T");
437 fs->ic_dec = iconv_open("WCHAR_T", (char *) cs->data);
439 else
440 fs->ic_enc = fs->ic_dec = (iconv_t) - 1;
442 #else /* CONFOPT_ICONV */
444 /* if the encoding is utf8, set the flag */
445 if ((v = mpdm_hget_s(mpdm_root(), L"ENCODING")) != NULL) {
446 wchar_t *enc = mpdm_string(v);
448 /* if it's utf-8, set the flag */
449 if (wcscmp(enc, L"utf-8") == 0 ||
450 wcscmp(enc, L"UTF-8") == 0 ||
451 wcscmp(enc, L"utf8") == 0 || wcscmp(enc, L"UTF8") == 0)
452 fs->utf8 = 1;
455 #endif /* CONFOPT_ICONV */
457 if ((v = mpdm_new(MPDM_FILE | MPDM_FREE, fs, sizeof(struct mpdm_file))) == NULL)
458 free(fs);
460 return v;
464 static void destroy_mpdm_file(mpdm_t v)
465 /* destroys and file value */
467 struct mpdm_file *fs = v->data;
469 if (fs != NULL) {
470 #ifdef CONFOPT_ICONV
472 if (fs->ic_enc != (iconv_t) - 1) {
473 iconv_close(fs->ic_enc);
474 fs->ic_enc = (iconv_t) - 1;
477 if (fs->ic_dec != (iconv_t) - 1) {
478 iconv_close(fs->ic_dec);
479 fs->ic_dec = (iconv_t) - 1;
481 #endif
483 free(fs);
484 v->data = NULL;
489 /** interface **/
491 wchar_t *mpdm_read_mbs(FILE * f, int *s)
492 /* reads a multibyte string from a stream into a dynamic string */
494 struct mpdm_file fs;
496 /* reset the structure */
497 memset(&fs, '\0', sizeof(fs));
498 fs.in = f;
500 return read_mbs(&fs, s);
504 int mpdm_write_wcs(FILE * f, wchar_t * str)
505 /* writes a wide string to a stream */
507 struct mpdm_file fs;
509 /* reset the structure */
510 memset(&fs, '\0', sizeof(fs));
511 fs.out = f;
513 return write_wcs(&fs, str);
517 mpdm_t mpdm_new_f(FILE * f)
518 /* creates a new file value from a FILE * */
520 mpdm_t v = NULL;
522 if (f == NULL)
523 return NULL;
525 if ((v = new_mpdm_file()) != NULL) {
526 struct mpdm_file *fs = v->data;
527 fs->in = fs->out = f;
530 return v;
535 * mpdm_open - Opens a file.
536 * @filename: the file name
537 * @mode: an fopen-like mode string
539 * Opens a file. If @filename can be open in the specified @mode, an
540 * mpdm_t value will be returned containing the file descriptor, or NULL
541 * otherwise.
542 * [File Management]
544 mpdm_t mpdm_open(mpdm_t filename, mpdm_t mode)
546 FILE *f;
548 if (filename == NULL || mode == NULL)
549 return NULL;
551 /* convert to mbs,s */
552 filename = MPDM_2MBS(filename->data);
553 mode = MPDM_2MBS(mode->data);
555 if ((f = fopen((char *) filename->data, (char *) mode->data)) == NULL)
556 store_syserr();
557 else {
558 #if defined(CONFOPT_SYS_STAT_H) && defined(S_ISDIR) && defined(EISDIR)
559 struct stat s;
561 /* test if the open file is a directory */
562 if (fstat(fileno(f), &s) != -1 && S_ISDIR(s.st_mode)) {
563 /* it's a directory; fail */
564 errno = EISDIR;
565 store_syserr();
566 fclose(f);
567 f = NULL;
569 #endif
572 return MPDM_F(f);
577 * mpdm_close - Closes a file descriptor.
578 * @fd: the value containing the file descriptor
580 * Closes the file descriptor.
581 * [File Management]
583 mpdm_t mpdm_close(mpdm_t fd)
585 struct mpdm_file *fs = fd->data;
587 if ((fd->flags & MPDM_FILE) && fs != NULL) {
588 if (fs->in != NULL)
589 fclose(fs->in);
591 if (fs->out != fs->in && fs->out != NULL)
592 fclose(fs->out);
594 destroy_mpdm_file(fd);
597 return NULL;
602 * mpdm_read - Reads a line from a file descriptor.
603 * @fd: the value containing the file descriptor
605 * Reads a line from @fd. Returns the line, or NULL on EOF.
606 * [File Management]
607 * [Character Set Conversion]
609 mpdm_t mpdm_read(mpdm_t fd)
611 mpdm_t v = NULL;
612 wchar_t *ptr;
613 int s;
614 struct mpdm_file *fs = fd->data;
616 if (fs == NULL)
617 return NULL;
619 #ifdef CONFOPT_ICONV
621 if (fs->ic_dec != (iconv_t) - 1)
622 ptr = read_iconv(fs, &s);
623 else
624 #else /* CONFOPT_ICONV */
626 if (fs->utf8)
627 ptr = read_utf8(fs, &s);
628 else
629 #endif /* CONFOPT_ICONV */
631 ptr = read_mbs(fs, &s);
633 if (ptr != NULL)
634 v = MPDM_ENS(ptr, s);
636 return v;
640 mpdm_t mpdm_getchar(mpdm_t fd)
642 int c;
643 wchar_t tmp[2];
644 struct mpdm_file *fs = fd->data;
646 if (fs == NULL || (c = get_char(fs)) == EOF)
647 return NULL;
649 /* get the char as-is */
650 tmp[0] = (wchar_t) c;
651 tmp[1] = L'\0';
653 return MPDM_S(tmp);
657 mpdm_t mpdm_putchar(mpdm_t fd, mpdm_t c)
659 struct mpdm_file *fs = fd->data;
660 wchar_t *ptr = mpdm_string(c);
662 if (fs == NULL || put_char(*ptr, fs) == -1)
663 return NULL;
665 return c;
670 * mpdm_write - Writes a value into a file.
671 * @fd: the file descriptor.
672 * @v: the value to be written.
674 * Writes the @v string value into @fd, using the current encoding.
675 * [File Management]
676 * [Character Set Conversion]
678 int mpdm_write(mpdm_t fd, mpdm_t v)
680 struct mpdm_file *fs = fd->data;
681 int ret = -1;
683 if (fs == NULL)
684 return -1;
686 #ifdef CONFOPT_ICONV
688 if (fs->ic_enc != (iconv_t) - 1)
689 ret = write_iconv(fs, mpdm_string(v));
690 else
691 #else /* CONFOPT_ICONV */
693 if (fs->utf8)
694 ret = write_utf8(fs, mpdm_string(v));
695 else
696 #endif /* CONFOPT_ICONV */
698 ret = write_wcs(fs, mpdm_string(v));
700 return ret;
704 int mpdm_fseek(mpdm_t fd, long offset, int whence)
706 struct mpdm_file *fs = fd->data;
708 return fseek(fs->in, offset, whence);
712 long mpdm_ftell(mpdm_t fd)
714 struct mpdm_file *fs = fd->data;
716 return ftell(fs->in);
720 FILE * mpdm_get_filehandle(mpdm_t fd)
722 FILE * f = NULL;
724 if (fd->flags & MPDM_FILE) {
725 struct mpdm_file *fs = fd->data;
726 f = fs->in;
729 return f;
734 mpdm_t mpdm_bread(mpdm_t fd, int size)
739 int mpdm_bwrite(mpdm_tfd, mpdm_t v, int size)
746 * mpdm_encoding - Sets the current charset encoding for files.
747 * @charset: the charset name.
749 * Sets the current charset encoding for files. Future opened
750 * files will be assumed to be encoded with @charset, which can
751 * be any of the supported charset names (utf-8, iso-8859-1, etc.),
752 * and converted on each read / write. If charset is NULL, it
753 * is reverted to default charset conversion (i.e. the one defined
754 * in the locale).
755 * Returns a negative number if @charset is unsupported, or zero
756 * if no errors were found.
757 * [File Management]
758 * [Character Set Conversion]
760 int mpdm_encoding(mpdm_t charset)
762 int ret = -1;
764 #ifdef CONFOPT_ICONV
766 if (charset != NULL) {
767 iconv_t ic;
768 mpdm_t cs = MPDM_2MBS(charset->data);
770 /* tries to create an encoder and a decoder for this charset */
772 if ((ic = iconv_open("WCHAR_T", (char *) cs->data)) == (iconv_t) - 1)
773 return -1;
775 iconv_close(ic);
777 if ((ic = iconv_open((char *) cs->data, "WCHAR_T")) == (iconv_t) - 1)
778 return -2;
780 iconv_close(ic);
783 /* can create; store and exit */
785 mpdm_hset_s(mpdm_root(), L"ENCODING", charset);
787 ret = 0;
789 #else /* CONFOPT_ICONV */
791 wchar_t *enc = mpdm_string(charset);
793 /* if it's NULL or utf-8, store */
794 if (charset == NULL ||
795 wcscmp(enc, L"utf-8") == 0 ||
796 wcscmp(enc, L"UTF-8") == 0 ||
797 wcscmp(enc, L"utf8") == 0 || wcscmp(enc, L"UTF8") == 0) {
798 mpdm_hset_s(mpdm_root(), L"ENCODING", charset);
799 ret = 0;
802 #endif /* CONFOPT_ICONV */
804 return ret;
809 * mpdm_unlink - Deletes a file.
810 * @filename: file name to be deleted
812 * Deletes a file.
813 * [File Management]
815 int mpdm_unlink(mpdm_t filename)
817 int ret;
819 /* convert to mbs */
820 filename = MPDM_2MBS(filename->data);
822 if ((ret = unlink((char *) filename->data)) == -1)
823 store_syserr();
825 return ret;
830 * mpdm_stat - Gives status from a file.
831 * @filename: file name to get the status from
833 * Returns a 13 element array of the status (permissions, onwer, etc.)
834 * from the desired @filename, or NULL if the file cannot be accessed.
835 * (man 2 stat).
836 * [File Management]
838 mpdm_t mpdm_stat(mpdm_t filename)
840 mpdm_t r = NULL;
842 #ifdef CONFOPT_SYS_STAT_H
843 struct stat s;
845 filename = MPDM_2MBS(filename->data);
847 if (stat((char *) filename->data, &s) != -1) {
848 r = MPDM_A(13);
850 mpdm_aset(r, MPDM_I(s.st_dev), 0);
851 mpdm_aset(r, MPDM_I(s.st_ino), 1);
852 mpdm_aset(r, MPDM_I(s.st_mode), 2);
853 mpdm_aset(r, MPDM_I(s.st_nlink), 3);
854 mpdm_aset(r, MPDM_I(s.st_uid), 4);
855 mpdm_aset(r, MPDM_I(s.st_gid), 5);
856 mpdm_aset(r, MPDM_I(s.st_rdev), 6);
857 mpdm_aset(r, MPDM_I(s.st_size), 7);
858 mpdm_aset(r, MPDM_I(s.st_atime), 8);
859 mpdm_aset(r, MPDM_I(s.st_mtime), 9);
860 mpdm_aset(r, MPDM_I(s.st_ctime), 10);
861 mpdm_aset(r, MPDM_I(0), 11); /* s.st_blksize */
862 mpdm_aset(r, MPDM_I(0), 12); /* s.st_blocks */
864 else
865 store_syserr();
867 #endif /* CONFOPT_SYS_STAT_H */
869 return r;
874 * mpdm_chmod - Changes a file's permissions.
875 * @filename: the file name
876 * @perms: permissions (element 2 from mpdm_stat())
878 * Changes the permissions for a file.
879 * [File Management]
881 int mpdm_chmod(mpdm_t filename, mpdm_t perms)
883 int r = -1;
885 filename = MPDM_2MBS(filename->data);
886 if ((r = chmod((char *) filename->data, mpdm_ival(perms))) == -1)
887 store_syserr();
889 return r;
894 * mpdm_chown - Changes a file's owner.
895 * @filename: the file name
896 * @uid: user id (element 4 from mpdm_stat())
897 * @gid: group id (element 5 from mpdm_stat())
899 * Changes the owner and group id's for a file.
900 * [File Management]
902 int mpdm_chown(mpdm_t filename, mpdm_t uid, mpdm_t gid)
904 int r = -1;
906 #ifdef CONFOPT_CHOWN
908 filename = MPDM_2MBS(filename->data);
909 if ((r = chown((char *) filename->data, mpdm_ival(uid), mpdm_ival(gid))) == -1)
910 store_syserr();
912 #endif /* CONFOPT_CHOWN */
914 return r;
919 * mpdm_glob - Executes a file globbing.
920 * @spec: Globbing spec
922 * Executes a file globbing. @spec is system-dependent, but usually
923 * the * and ? metacharacters work everywhere. @spec can contain a
924 * directory; if that's the case, the output strings will include it.
925 * In any case, each returned value will be suitable for a call to
926 * mpdm_open().
928 * Returns an array of files that match the globbing (can be an empty
929 * array if no file matches), or NULL if globbing is unsupported.
930 * [File Management]
932 mpdm_t mpdm_glob(mpdm_t spec)
934 mpdm_t d = NULL;
935 mpdm_t f = NULL;
936 mpdm_t v = NULL;
938 #ifdef CONFOPT_WIN32
940 WIN32_FIND_DATA fd;
941 HANDLE h;
942 char *ptr;
943 mpdm_t w;
944 mpdm_t s = NULL;
946 /* convert to mbs */
947 if (spec != NULL)
948 spec = MPDM_2MBS(spec->data);
949 else
950 spec = MPDM_2MBS(L"*.*");
952 ptr = (char *) spec->data;
954 /* convert MSDOS dir separators into Unix ones */
955 for (; *ptr != '\0'; ptr++) {
956 if (*ptr == '\\')
957 *ptr = '/';
960 v = MPDM_A(0);
961 d = MPDM_A(0);
962 f = MPDM_A(0);
964 if ((h = FindFirstFile((char *) spec->data, &fd)) != INVALID_HANDLE_VALUE) {
965 /* if spec includes a directory, store in s */
966 if ((ptr = strrchr((char *) spec->data, '/')) != NULL) {
967 *(ptr + 1) = '\0';
968 s = MPDM_S(spec->data);
971 do {
972 /* ignore . and .. */
973 if (strcmp(fd.cFileName, ".") == 0 || strcmp(fd.cFileName, "..") == 0)
974 continue;
976 /* concat base directory and file names */
977 w = mpdm_strcat(s, MPDM_MBS(fd.cFileName));
979 /* if it's a directory, add a / */
980 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
981 w = mpdm_strcat(w, MPDM_LS(L"/"));
982 mpdm_push(d, w);
984 else
985 mpdm_push(f, w);
987 while (FindNextFile(h, &fd));
989 FindClose(h);
992 #endif
994 #if CONFOPT_GLOB_H
996 /* glob.h support */
997 glob_t globbuf;
998 char *ptr;
1000 /* convert to mbs */
1001 if (spec != NULL) {
1002 spec = MPDM_2MBS(spec->data);
1004 ptr = spec->data;
1005 if (ptr == NULL || *ptr == '\0')
1006 ptr = "*";
1008 else
1009 ptr = "*";
1011 globbuf.gl_offs = 1;
1013 v = MPDM_A(0);
1014 d = MPDM_A(0);
1015 f = MPDM_A(0);
1017 if (glob(ptr, GLOB_MARK, NULL, &globbuf) == 0) {
1018 int n;
1020 for (n = 0; globbuf.gl_pathv[n] != NULL; n++) {
1021 char *ptr = globbuf.gl_pathv[n];
1022 mpdm_t t = MPDM_MBS(ptr);
1024 /* if last char is /, add to directories */
1025 if (ptr[strlen(ptr) - 1] == '/')
1026 mpdm_push(d, t);
1027 else
1028 mpdm_push(f, t);
1032 globfree(&globbuf);
1034 #else
1036 /* no win32 nor glob.h; try workaround */
1037 /* ... */
1039 #endif
1041 if (v != NULL) {
1042 int n;
1044 d = mpdm_sort(d, 1);
1045 f = mpdm_sort(f, 1);
1047 /* transfer all data in d and f */
1048 for (n = 0; n < mpdm_size(d); n++)
1049 mpdm_push(v, mpdm_aget(d, n));
1050 for (n = 0; n < mpdm_size(f); n++)
1051 mpdm_push(v, mpdm_aget(f, n));
1054 return v;
1058 #ifdef CONFOPT_WIN32
1060 static void win32_pipe(HANDLE * h, int n)
1062 SECURITY_ATTRIBUTES sa;
1063 HANDLE cp, t;
1065 memset(&sa, '\0', sizeof(sa));
1066 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
1067 sa.bInheritHandle = TRUE;
1068 sa.lpSecurityDescriptor = NULL;
1070 cp = GetCurrentProcess();
1072 CreatePipe(&h[0], &h[1], &sa, 0);
1073 DuplicateHandle(cp, h[n], cp, &t, 0, FALSE, DUPLICATE_SAME_ACCESS);
1074 CloseHandle(h[n]);
1075 h[n] = t;
1079 static int sysdep_popen(mpdm_t v, char *prg, int rw)
1080 /* win32-style pipe */
1082 HANDLE pr[2];
1083 HANDLE pw[2];
1084 PROCESS_INFORMATION pi;
1085 STARTUPINFO si;
1086 int ret;
1087 struct mpdm_file *fs = v->data;
1089 /* init all */
1090 pr[0] = pr[1] = pw[0] = pw[1] = NULL;
1092 if (rw & 0x01)
1093 win32_pipe(pr, 0);
1094 if (rw & 0x02)
1095 win32_pipe(pw, 1);
1097 /* spawn new process */
1098 memset(&pi, '\0', sizeof(pi));
1099 memset(&si, '\0', sizeof(si));
1101 si.cb = sizeof(STARTUPINFO);
1102 si.hStdError = pr[1];
1103 si.hStdOutput = pr[1];
1104 si.hStdInput = pw[0];
1105 si.dwFlags |= STARTF_USESTDHANDLES;
1107 ret = CreateProcess(NULL, prg, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
1109 if (rw & 0x01)
1110 CloseHandle(pr[1]);
1111 if (rw & 0x02)
1112 CloseHandle(pw[0]);
1114 fs->hin = pr[0];
1115 fs->hout = pw[1];
1117 return ret;
1121 static int sysdep_pclose(mpdm_t v)
1123 struct mpdm_file *fs = v->data;
1125 if (fs->hin != NULL)
1126 CloseHandle(fs->hin);
1128 if (fs->hout != NULL)
1129 CloseHandle(fs->hout);
1131 /* how to know process exit code? */
1132 return 0;
1136 #else /* CONFOPT_WIN32 */
1138 static int sysdep_popen(mpdm_t v, char *prg, int rw)
1139 /* unix-style pipe open */
1141 int pr[2], pw[2];
1142 struct mpdm_file *fs = v->data;
1144 /* init all */
1145 pr[0] = pr[1] = pw[0] = pw[1] = -1;
1147 if (rw & 0x01)
1148 pipe(pr);
1149 if (rw & 0x02)
1150 pipe(pw);
1152 if (fork() == 0) {
1153 /* child process */
1154 if (rw & 0x01) {
1155 close(1);
1156 dup(pr[1]);
1157 close(pr[0]);
1159 if (rw & 0x02) {
1160 close(0);
1161 dup(pw[0]);
1162 close(pw[1]);
1165 /* redirect stderr to stdout */
1166 close(2);
1167 dup(1);
1169 /* run the program */
1170 execlp("/bin/sh", "/bin/sh", "-c", prg, NULL);
1171 execlp(prg, prg, NULL);
1173 /* still here? exec failed; close pipes and exit */
1174 close(0);
1175 close(1);
1176 exit(0);
1179 /* create the pipes as non-buffered streams */
1180 if (rw & 0x01) {
1181 fs->in = fdopen(pr[0], "r");
1182 setvbuf(fs->in, NULL, _IONBF, 0);
1183 close(pr[1]);
1186 if (rw & 0x02) {
1187 fs->out = fdopen(pw[1], "w");
1188 setvbuf(fs->out, NULL, _IONBF, 0);
1189 close(pw[0]);
1192 return 1;
1196 static int sysdep_pclose(mpdm_t v)
1197 /* unix-style pipe close */
1199 int s;
1200 struct mpdm_file *fs = v->data;
1202 if (fs->in != NULL)
1203 fclose(fs->in);
1205 if (fs->out != fs->in && fs->out != NULL)
1206 fclose(fs->out);
1208 wait(&s);
1210 return s;
1214 #endif /* CONFOPT_WIN32 */
1218 * mpdm_popen - Opens a pipe.
1219 * @prg: the program to pipe
1220 * @mode: an fopen-like mode string
1222 * Opens a pipe to a program. If @prg can be open in the specified @mode, an
1223 * mpdm_t value will be returned containing the file descriptor, or NULL
1224 * otherwise.
1225 * [File Management]
1227 mpdm_t mpdm_popen(mpdm_t prg, mpdm_t mode)
1229 mpdm_t v;
1230 char *m;
1231 int rw = 0;
1233 if (prg == NULL || mode == NULL)
1234 return NULL;
1236 if ((v = new_mpdm_file()) == NULL)
1237 return NULL;
1239 /* convert to mbs,s */
1240 prg = MPDM_2MBS(prg->data);
1241 mode = MPDM_2MBS(mode->data);
1243 /* get the mode */
1244 m = (char *) mode->data;
1246 /* set the mode */
1247 if (m[0] == 'r')
1248 rw = 0x01;
1249 if (m[0] == 'w')
1250 rw = 0x02;
1251 if (m[1] == '+')
1252 rw = 0x03; /* r+ or w+ */
1254 if (!sysdep_popen(v, (char *) prg->data, rw)) {
1255 destroy_mpdm_file(v);
1256 v = NULL;
1259 return v;
1264 * mpdm_pclose - Closes a pipe.
1265 * @fd: the value containing the file descriptor
1267 * Closes a pipe.
1268 * [File Management]
1270 mpdm_t mpdm_pclose(mpdm_t fd)
1272 mpdm_t r = NULL;
1274 if ((fd->flags & MPDM_FILE) && fd->data != NULL) {
1275 r = MPDM_I(sysdep_pclose(fd));
1276 destroy_mpdm_file(fd);
1279 return r;
1284 * mpdm_home_dir - Returns the home user directory.
1286 * Returns a system-dependent directory where the user can write
1287 * documents and create subdirectories.
1288 * [File Management]
1290 mpdm_t mpdm_home_dir(void)
1292 mpdm_t r = NULL;
1293 char *ptr;
1294 char tmp[512] = "";
1296 #ifdef CONFOPT_WIN32
1298 LPITEMIDLIST pidl;
1300 /* get the 'My Documents' folder */
1301 SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &pidl);
1302 SHGetPathFromIDList(pidl, tmp);
1303 strcat(tmp, "\\");
1305 #endif
1307 #ifdef CONFOPT_PWD_H
1309 struct passwd *p;
1311 /* get home dir from /etc/passwd entry */
1312 if (tmp[0] == '\0' && (p = getpwuid(getpid())) != NULL) {
1313 strcpy(tmp, p->pw_dir);
1314 strcat(tmp, "/");
1317 #endif
1319 /* still none? try the ENV variable $HOME */
1320 if (tmp[0] == '\0' && (ptr = getenv("HOME")) != NULL) {
1321 strcpy(tmp, ptr);
1322 strcat(tmp, "/");
1325 if (tmp[0] != '\0')
1326 r = MPDM_MBS(tmp);
1328 return r;
1333 * mpdm_app_dir - Returns the applications directory.
1335 * Returns a system-dependent directory where the applications store
1336 * their private data, as components or resources.
1337 * [File Management]
1339 mpdm_t mpdm_app_dir(void)
1341 mpdm_t r = NULL;
1343 #ifdef CONFOPT_WIN32
1345 HKEY hkey;
1346 char tmp[MAX_PATH];
1347 LPITEMIDLIST pidl;
1349 /* get the 'Program Files' folder (can fail) */
1350 tmp[0] = '\0';
1351 if (SHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidl) == S_OK)
1352 SHGetPathFromIDList(pidl, tmp);
1354 /* if it's still empty, get from the registry */
1355 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
1356 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
1357 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS) {
1358 int n = sizeof(tmp);
1360 if (RegQueryValueEx(hkey, "ProgramFilesDir",
1361 NULL, NULL, tmp, (LPDWORD) & n) != ERROR_SUCCESS)
1362 tmp[0] = '\0';
1365 if (tmp[0] != '\0') {
1366 strcat(tmp, "\\");
1367 r = MPDM_MBS(tmp);
1369 #endif
1371 /* still none? get the configured directory */
1372 if (r == NULL)
1373 r = MPDM_MBS(CONFOPT_PREFIX "/share/");
1375 return r;