modified: SpatialOmicsCoord.py
[GalaxyCodeBases.git] / c_cpp / etc / calc / input.c
blobeb2eb82bec391a5bbfbf47333da530d061bb954f
1 /*
2 * input - nested input source file reader
4 * Copyright (C) 1999-2007 David I. Bell
6 * Calc is open software; you can redistribute it and/or modify it under
7 * the terms of the version 2.1 of the GNU Lesser General Public License
8 * as published by the Free Software Foundation.
10 * Calc is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
13 * Public License for more details.
15 * A copy of version 2.1 of the GNU Lesser General Public License is
16 * distributed with calc under the filename COPYING-LGPL. You should have
17 * received a copy with calc; if not, write to Free Software Foundation, Inc.
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * @(#) $Revision: 30.3 $
21 * @(#) $Id: input.c,v 30.3 2013/08/11 08:41:38 chongo Exp $
22 * @(#) $Source: /usr/local/src/bin/calc/RCS/input.c,v $
24 * Under source code control: 1990/02/15 01:48:16
25 * File existed as early as: before 1990
27 * Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/
31 * Nested input source file reader.
32 * For terminal input, this also provides a simple command stack.
36 #include <stdio.h>
37 #include <ctype.h>
38 #if !defined(_WIN32)
39 # include <pwd.h>
40 #else
41 # include <stdlib.h>
42 #endif
43 #include <sys/types.h>
44 #include <sys/stat.h>
46 #include "have_unistd.h"
47 #if defined(HAVE_UNISTD_H)
48 #include <unistd.h>
49 #endif
51 #if defined(__MSDOS__)
52 #include <limits.h>
53 #define _fullpath(f,n,s) (_fixpath(n,f),f)
54 #define _MAX_PATH PATH_MAX
55 #endif
57 #include "calc.h"
58 #include "conf.h"
59 #include "hist.h"
61 EXTERN int stdin_tty; /* TRUE if stdin is a tty */
62 E_FUNC FILE *f_open(char *name, char *mode);
63 E_FUNC FILE *curstream(void);
66 #define TTYSIZE 100 /* reallocation size for terminal buffers */
67 #define MAXDEPTH 10 /* maximum depth of input */
68 #define IS_READ 1 /* reading normally */
69 #define IS_REREAD 2 /* reread current character */
70 #define chartoint(ch) ((ch) & 0xff) /* make sure char is not negative */
71 #define READSET_ALLOC 8 /* readset to allocate chunk size */
74 typedef struct {
75 int i_state; /* state (read, reread) */
76 int i_char; /* currently read char */
77 long i_line; /* line number */
78 char *i_cp; /* pointer to string character to be read */
79 char *i_str; /* start of string copy to be read, or NULL */
80 long i_num; /* number of string characters remaining */
81 char *i_ttystr; /* current character of tty line (or NULL) */
82 FILE *i_fp; /* current file for input (if not NULL) */
83 char *i_name; /* file name if known */
84 } INPUT;
87 /* files that calc has read or included */
88 typedef struct {
89 int active; /* != 0 => active entry, 0 => unused entry */
90 char *name; /* name used to read file */
91 char *path; /* real path used to open file */
92 struct stat inode; /* inode information for file */
93 } READSET;
95 STATIC READSET *readset = NULL; /* array of files read */
96 STATIC int maxreadset = 0; /* length of readset */
98 STATIC int linesize; /* current max size of input line */
99 STATIC char *linebuf; /* current input line buffer */
100 STATIC char *prompt; /* current prompt for terminal */
101 STATIC BOOL noprompt; /* TRUE if should not print prompt */
103 STATIC int depth; /* current input depth */
104 STATIC INPUT *cip; /* current input source */
105 STATIC INPUT inputs[MAXDEPTH]; /* input sources */
108 S_FUNC int openfile(char *name);
109 S_FUNC int ttychar(void);
110 S_FUNC int isinoderead(struct stat *sbuf);
111 S_FUNC int findfreeread(void);
112 S_FUNC int addreadset(char *name, char *path, struct stat *sbuf);
113 S_FUNC char *homeexpand(char *name);
117 * Open an input file by possibly searching through a path list
118 * and also possibly applying the specified extension. For example:
120 * opensearchfile("barf", ".:/tmp", ".c", rd_once)
122 * searches in order for the files:
124 * "./barf", "./barf.c", "/tmp/barf", and "/tmp/barf.c".
126 * Returns -1 if we could not open a file or error.
127 * Returns 1 if file was opened and added to/updated in the readset
128 * Returns 0 if file was already in the readset and reopen was 0.
130 * given:
131 * name file name to be read
132 * pathlist list of colon separated paths (or NULL)
133 * extension extra extension to try (or NULL)
134 * rd_once TRUE => do not reread a file
137 opensearchfile(char *name, char *pathlist, char *extension, int rd_once)
139 int i;
140 char *cp;
141 char *path; /* name being searched for */
142 struct stat statbuf; /* stat of the path */
143 size_t namelen; /* length of name */
144 size_t extlen; /* length of the extension if non-NULL or 0 */
145 size_t pathlen; /* length of the pathlist if non-NULL or 0 */
147 /* firewall */
148 if (name == NULL) {
149 math_error("NULL name given to opensearchfile");
150 /*NOTREACHED*/
154 * We ignore the pathlist of the file is absolute, dot-relative
155 * or tilde-relative or if there is no search path.
157 if (name[0] == PATHCHAR ||
158 name[0] == HOMECHAR ||
159 (name[0] == DOTCHAR && name[1] == '\0') ||
160 (name[0] == DOTCHAR && name[1] == DOTCHAR && name[2] == '\0') ||
161 (name[0] == DOTCHAR && name[1] == PATHCHAR) ||
162 (name[0] == DOTCHAR && name[1] == DOTCHAR && name[2] == PATHCHAR) ||
163 pathlist == NULL) {
164 pathlist = "";
168 * allocate storage for the longest name being searched for
170 * We will allocate more than we could ever want/need.
171 * The longest we could ever need would be:
173 * pathlist (as a single long string)
175 * name
177 * extension
178 * \0
179 * guard byte
181 namelen = strlen(name);
182 if (extension != NULL) {
183 extlen = strlen(extension);
184 } else {
185 extlen = 0;
187 pathlen = strlen(pathlist);
188 path = malloc(pathlen+1 + 1 + namelen+1 + extlen+1 + 1 + 1);
189 if (path == NULL) {
190 math_error("Cannot allocate filename path buffer");
191 /*NOTREACHED*/
195 * Don't try the extension if the filename already contains it.
197 if (extension != NULL && namelen >= extlen &&
198 strcmp(&name[namelen-extlen], extension) == 0) {
199 extension = NULL;
203 * Search through the path list for the file
205 pathlist--;
206 do {
207 pathlist++;
208 cp = path;
209 while (*pathlist && (*pathlist != LISTCHAR))
210 *cp++ = *pathlist++;
211 if (cp != path)
212 *cp++ = PATHCHAR;
213 strncpy(cp, name, namelen+1);
214 i = openfile(path);
215 if ((i < 0) &&
216 (extension != NULL && extension[0] != '\0')) {
217 strcat(path, extension);
218 i = openfile(path);
220 } while ((i < 0) && *pathlist);
222 /* examine what our search produced */
223 if (i < 0) {
224 free(path);
225 return i;
227 if (cip->i_fp == NULL) {
228 /* cannot find a file to open */
229 free(path);
230 return -3;
232 if (fstat(fileno(cip->i_fp), &statbuf) < 0) {
233 /* unable to fstat the open file */
234 free(path);
235 return -4;
238 /* note if we will reopen a file and if that is allowed */
239 if (rd_once == TRUE && isinoderead(&statbuf) >= 0) {
240 /* file is in readset and reopen is false */
241 closeinput();
242 free(path);
243 return 1;
246 /* add this name to the readset if allowed */
247 if (addreadset(name, path, &statbuf) < 0) {
248 /* cannot add to readset */
249 closeinput();
250 free(path);
251 return -1;
254 /* file was added to/updated in readset */
255 free(path);
256 return 0;
261 * f_pathopen - open an absolute or relative filename along a search path
263 * Open a file by possibly searching through a path list. For example:
265 * f_pathopen("curds", ".:/tmp:~/pub", "r", NULL)
267 * searches in order for a file that it can open for reading:
269 * "./curds", "/tmp/curds", "~/pub/curds"
271 * NOTE: ~ is expanded accordingly (see homeexpand() below).
273 * However is the file is /absolue/path/name or a ./dot/relative/name, or
274 * a ~/home/dir/name, or a ~user/home/name, then the pathlist is ignored
275 * we just attempt to open name.
277 * and opens the first one that exists and allows the mode.
279 * name file name to be read
280 * mode fopen() mode argument
281 * (one of "r", "w", "a", "r+", "w+", "a+")
282 * pathlist list of colon separated paths (or NULL)
283 * openpath if non-NULL, and file was opened, set to malloced
284 * path used to open
286 * returns:
287 * open file stream, NULL ==> file was not found or error
288 * If file was open and openpath was non-NULL, changed to point
289 * to path used to open
291 FILE *
292 f_pathopen(char *name, char *mode, char *pathlist, char **openpath)
294 char *cp;
295 char *path; /* name being searched for */
296 size_t namelen; /* length of name */
297 size_t pathlen; /* length of the pathlist if non-NULL or 0 */
298 FILE *ret; /* return open stream or NULL */
300 /* firewall */
301 if (name == NULL) {
302 math_error("NULL name given to f_pathopen");
303 /*NOTREACHED*/
305 if (mode == NULL) {
306 math_error("NULL mode given to f_pathopen");
307 /*NOTREACHED*/
311 * We ignore the pathlist of the file is absolute, dot-relative
312 * or tilde-relative or if there is no search path.
314 if (name[0] == PATHCHAR ||
315 name[0] == HOMECHAR ||
316 (name[0] == DOTCHAR && name[1] == '\0') ||
317 (name[0] == DOTCHAR && name[1] == DOTCHAR && name[2] == '\0') ||
318 (name[0] == DOTCHAR && name[1] == PATHCHAR) ||
319 (name[0] == DOTCHAR && name[1] == DOTCHAR && name[2] == PATHCHAR) ||
320 pathlist == NULL) {
321 pathlist = "";
325 * allocate storage for the longest name being searched for
327 * We will allocate more than we could ever want/need.
328 * The longest we could ever need would be:
330 * pathlist (as a single long string)
332 * name
333 * \0
334 * guard byte
336 namelen = strlen(name);
337 pathlen = strlen(pathlist);
338 path = malloc(pathlen+1 + 1 + namelen+1 + 1 + 1);
339 if (path == NULL) {
340 math_error("Cannot allocate f_pathopen buffer");
341 /*NOTREACHED*/
345 * Search through the path list for the file
347 pathlist--;
348 do {
349 pathlist++;
350 cp = path;
351 while (*pathlist && (*pathlist != LISTCHAR))
352 *cp++ = *pathlist++;
353 if (cp != path)
354 *cp++ = PATHCHAR;
355 strncpy(cp, name, namelen+1);
356 ret = f_open(path, mode);
357 } while ((ret == NULL) && *pathlist);
359 /* if caller wants to know the path, malloc it and return it */
360 if (openpath != NULL && ret != NULL) {
361 if (path[0] == HOMECHAR) {
362 *openpath = homeexpand(path);
363 } else {
364 *openpath = strdup(path);
366 if (*openpath == NULL) {
367 free(path);
368 fclose(ret);
369 math_error("cannot malloc return openpath buffer");
370 /*NOTREACHED*/
373 free(path);
375 /* return open file or NULL */
376 return ret;
381 * Given a filename with a leading ~, expand it into a home directory for
382 * that user. This function will malloc the space for the expanded path.
384 * If the path is just ~, or begins with ~/, expand it to the home
385 * directory of the current user. If the environment variable $HOME
386 * is known, it will be used, otherwise the password file will be
387 * consulted.
389 * If the path is just ~username, or ~username/, expand it to the home
390 * directory of that user by looking it up in the password file.
392 * If the password file must be consulted and the username is not found
393 * a NULL pointer is returned.
395 * given:
396 * name a filename with a leading ~
398 S_FUNC char *
399 homeexpand(char *name)
401 #if defined(_WIN32)
403 return NULL;
405 #else /* Windoz free systems */
407 struct passwd *ent; /* password entry */
408 char *home2; /* fullpath of the home directory */
409 char *fullpath; /* the malloced expanded path */
410 char *after; /* after the ~user or ~ */
411 char *username; /* extracted username */
412 size_t fullpath_len; /* length of fullpath */
414 /* firewall */
415 if (name[0] != HOMECHAR)
416 return NULL;
419 * obtain the home directory component
421 switch (name[1]) {
422 case PATHCHAR: /* ~/... */
423 case '\0': /* ~ */
424 home2 = home;
425 after = name+1;
426 break;
427 default: /* ~username or ~username/... */
429 /* extract the username after the ~ */
430 after = (char *)strchr(name+2, PATHCHAR);
431 if (after == NULL) {
432 /* path is just ~username */
433 ent = (struct passwd *)getpwnam(name+1);
434 if (ent == NULL) {
435 /* unknown user */
436 return NULL;
438 /* just malloc the home directory and return it */
439 fullpath_len = strlen(ent->pw_dir);
440 fullpath = (char *)malloc(fullpath_len+1);
441 if (fullpath == NULL) {
442 return NULL;
444 strncpy(fullpath, ent->pw_dir, fullpath_len+1);
445 return fullpath;
447 username = (char *) malloc(after-name + 1 + 1);
448 if (username == NULL) {
449 /* failed to malloc username */
450 return NULL;
452 strncpy(username, name+1, after-name-1);
453 username[after-name-1] = '\0';
455 /* get that user's home directory */
456 ent = (struct passwd *)getpwnam(username);
457 free(username);
458 if (ent == NULL) {
459 /* unknown user */
460 return NULL;
462 home2 = ent->pw_dir;
463 break;
467 * build the fullpath given the home directory
469 fullpath = (char *)malloc(strlen(home2)+strlen(after)+1);
470 if (fullpath == NULL) {
471 return NULL;
473 sprintf(fullpath, "%s%s", home2, after);
474 return fullpath;
475 #endif /* Windoz free systems */
480 * f_open - ~-expand a filename and fopen() it
482 * given:
483 * name the filename to open
484 * mode fopen() mode argument
485 * (one of "r", "w", "a", "r+", "w+", "a+")
487 FILE *
488 f_open(char *name, char *mode)
490 FILE *fp; /* open file descriptor */
491 char *fullname; /* file name with HOMECHAR expansion */
494 * be sore we are allowed to open a file in this mode
496 if (!allow_read && !allow_write) {
497 /* no reads and no writes means no opens! */
498 if (run_state > RUN_BEGIN) {
499 fprintf(stderr,
500 "open of %s mode %s - %s\n", name, mode,
501 "open for read or write disallowed by -m\n");
503 return NULL;
504 } else if (!allow_read && strchr(mode, 'r') != NULL) {
505 /* reading new files disallowed */
506 if (run_state > RUN_BEGIN) {
507 fprintf(stderr,
508 "open of %s mode %s - %s\n", name, mode,
509 "open for read disallowed by -m\n");
511 return NULL;
512 } else if (!allow_write &&
513 (strchr(mode, 'w') != NULL ||
514 strchr(mode, 'a') != NULL ||
515 strchr(mode, '+') != NULL)) {
516 /* writing new files disallowed */
517 if (run_state > RUN_BEGIN) {
518 fprintf(stderr,
519 "open of %s mode %s - %s\n", name, mode,
520 "open for write disallowed by -m\n");
522 return NULL;
526 * expand ~ if needed
528 if (name[0] == HOMECHAR) {
529 fullname = homeexpand(name);
530 if (fullname == NULL)
531 return NULL;
532 fp = fopen(fullname, mode);
533 free(fullname);
534 } else {
535 fp = fopen(name, mode);
537 return fp;
542 * Setup for reading from a input file.
543 * Returns -1 if file could not be opened.
545 * given:
546 * name file name to be read
548 S_FUNC int
549 openfile(char *name)
551 FILE *fp; /* open file descriptor */
552 size_t namelen;
554 if (depth >= MAXDEPTH)
555 return -2;
556 fp = f_open(name, "r");
557 if (fp == NULL)
558 return -1;
559 cip = inputs + depth++;
560 cip->i_state = IS_READ;
561 cip->i_char = '\0';
562 cip->i_str = NULL;
563 cip->i_ttystr = NULL;
564 cip->i_fp = fp;
565 cip->i_line = 1;
566 namelen = strlen(name);
567 cip->i_name = (char *)malloc(namelen+1);
568 if (cip->i_name == NULL) {
569 return -1;
571 strncpy(cip->i_name, name, namelen+1);
572 return 0;
577 * Return the current input file stream, or NULL if none.
579 FILE *
580 curstream(void)
582 if (depth <= 0 || depth > MAXDEPTH)
583 return NULL;
584 return cip->i_fp;
589 * Open a string for scanning, num characters to be read.
590 * String is copied into local memory so it can be trashed afterwards.
591 * Returns -1 if cannot open string.
593 * given:
594 * str string to be opened
595 * num lengh of string to open
598 openstring(char *str, size_t num)
600 char *cp; /* copied string */
602 if ((depth >= MAXDEPTH) || (str == NULL))
603 return -2;
604 cp = (char *) malloc(num + 1);
605 if (cp == NULL)
606 return -1;
607 strncpy(cp, str, num);
608 cp[num] = '\0'; /* firewall */
609 cip = inputs + depth++;
610 cip->i_state = IS_READ;
611 cip->i_char = '\0';
612 cip->i_cp = cp;
613 cip->i_str = cp;
614 cip->i_num = num;
615 cip->i_fp = NULL;
616 cip->i_name = NULL;
617 cip->i_ttystr = NULL;
618 cip->i_line = 1;
619 return 0;
624 * Set to read input from the terminal.
625 * Returns -1 if there is no more depth for input.
628 openterminal(void)
630 if (depth >= MAXDEPTH)
631 return -2;
632 cip = inputs + depth++;
633 cip->i_state = IS_READ;
634 cip->i_char = '\0';
635 cip->i_str = NULL;
636 cip->i_ttystr = NULL;
637 cip->i_fp = NULL;
638 cip->i_name = NULL;
639 cip->i_line = 1;
640 return 0;
645 * Close the current input source.
647 void
648 closeinput(void)
650 if (depth <= 0)
651 return;
652 if (cip->i_str)
653 free(cip->i_str);
654 if (cip->i_fp)
655 fclose(cip->i_fp);
656 if (cip->i_name)
657 free(cip->i_name);
658 depth--;
659 cip = depth ? &inputs[depth - 1] : NULL;
664 * Reset the input sources back to the initial state.
666 void
667 resetinput(void)
669 while (depth > 0)
670 closeinput();
671 noprompt = FALSE;
676 * Set the prompt for terminal input.
678 void
679 setprompt(char *str)
681 prompt = str;
682 noprompt = FALSE;
687 * Read the next character from the current input source.
688 * End of file closes current input source, and returns EOF character.
691 nextchar(void)
693 int ch; /* current input character */
695 if (depth == 0) /* input finished */
696 return EOF;
697 if (cip->i_state == IS_REREAD) { /* rereading current char */
698 ch = cip->i_char;
699 cip->i_state = IS_READ;
700 if (ch == '\n')
701 cip->i_line++;
702 return ch;
704 if (cip->i_str) { /* from string */
705 if (cip->i_num) {
706 ch = chartoint(*cip->i_cp++);
707 cip->i_num--;
708 } else {
709 ch = EOF;
711 } else if (cip->i_fp) { /* from file */
712 ch = fgetc(cip->i_fp);
713 } else if (!stdin_tty) { /* from file */
714 ch = fgetc(stdin);
715 } else { /* from terminal */
716 ch = ttychar();
718 if (depth > 0)
719 cip->i_char = ch; /* save for rereads */
720 if (ch == '\n')
721 cip->i_line++;
722 return ch;
727 * Read in the next line of input from the current input source.
728 * The line is terminated with a null character, and does not contain
729 * the final newline character. The returned string is only valid
730 * until the next such call, and so must be copied if necessary.
731 * Returns NULL on end of file.
733 char *
734 nextline(void)
736 char *cp;
737 int ch;
738 int len;
740 cp = linebuf;
741 if (linesize == 0) {
742 cp = (char *)malloc(TTYSIZE + 1);
743 if (cp == NULL) {
744 math_error("Cannot allocate line buffer");
745 /*NOTREACHED*/
747 linebuf = cp;
748 linesize = TTYSIZE;
750 len = 0;
751 for (;;) {
752 noprompt = TRUE;
753 ch = nextchar();
754 noprompt = FALSE;
755 if (ch == EOF)
756 return NULL;
757 if (ch == '\0')
758 continue;
759 if (ch == '\n')
760 break;
761 if (len >= linesize) {
762 cp = (char *)realloc(cp, linesize + TTYSIZE + 1);
763 if (cp == NULL) {
764 math_error("Cannot realloc line buffer");
765 /*NOTREACHED*/
767 linebuf = cp;
768 linesize += TTYSIZE;
770 cp[len++] = (char)ch;
772 cp[len] = '\0';
773 return linebuf;
778 * Read the next character from the terminal.
779 * The routines in the history module are called so that the user
780 * can use a command history and emacs-like editing of the line.
782 S_FUNC int
783 ttychar(void)
785 int ch; /* current char */
786 int len; /* length of current command */
787 STATIC char charbuf[1024];
790 * If we have more to read from the saved command line, then do that.
791 * When we see a newline character, then clear the pointer so we will
792 * read a new line on the next call.
794 if (cip->i_ttystr) {
795 ch = chartoint(*cip->i_ttystr++);
796 if (ch == '\n')
797 cip->i_ttystr = NULL;
798 return ch;
802 * We need another complete line.
804 abortlevel = 0;
805 inputwait = TRUE;
806 len = hist_getline(noprompt ? "" : prompt, charbuf, sizeof(charbuf));
807 if (len == 0) {
808 inputwait = FALSE;
809 return EOF;
811 inputwait = FALSE;
814 * Handle shell escape if present
816 if (charbuf[0] == '!') { /* do a shell command */
817 char *cmd;
819 cmd = charbuf + 1;
820 if (*cmd == '\0' || *cmd == '\n')
821 cmd = shell;
822 if (allow_exec) {
823 if (conf->calc_debug & CALCDBG_SYSTEM) {
824 printf("%s\n", cmd);
826 system(cmd);
827 } else {
828 fprintf(stderr, "execution disallowed by -m flag\n");
830 return '\n';
832 hist_saveline(charbuf, len);
835 * Return the first character of the line, and set up to
836 * return the rest of it with later calls.
838 ch = chartoint(charbuf[0]);
839 if (ch != '\n')
840 cip->i_ttystr = charbuf + 1;
841 return ch;
846 * Return whether or not the input source is the terminal.
848 BOOL
849 inputisterminal(void)
851 return ((depth <= 0) || ((cip->i_str == NULL) && (cip->i_fp == NULL)));
856 * Return depth of current input source
859 inputlevel(void)
861 return depth - 1;
866 * Return the name of the current input file.
867 * Returns NULL for terminal or strings.
869 char *
870 inputname(void)
872 if (depth <= 0)
873 return NULL;
874 return cip->i_name;
879 * Return the current line number.
881 long
882 linenumber(void)
884 if (depth > 0)
885 return cip->i_line;
886 return 1;
891 * Restore the next character to be read again on the next nextchar call.
893 void
894 reread(void)
896 if ((depth <= 0) || (cip->i_state == IS_REREAD))
897 return;
898 cip->i_state = IS_REREAD;
899 if (cip->i_char == '\n')
900 cip->i_line--;
905 * Process all startup files found in the $CALCRC path.
907 void
908 runrcfiles(void)
910 char path[MAX_CALCRC+1+1]; /* name being searched for */
911 char *cp;
912 char *p;
914 /* execute each file in the list */
915 while (calcrc != NULL && *calcrc) {
916 cp = calcrc;
917 calcrc = (char *) strchr(calcrc + 1, LISTCHAR);
919 /* load file name into the path */
920 if (calcrc == NULL) {
921 strncpy(path, cp, MAX_CALCRC+1);
922 } else {
923 strncpy(path, cp, calcrc - cp);
924 path[calcrc - cp] = '\0';
927 /* find the start of the path */
928 p = (path[0] == ':') ? path + 1 : path;
929 if (p[0] == '\0') {
930 continue;
933 /* process the current file in the list */
934 if (openfile(p) < 0) {
935 /* Unable to open rcfile */
936 if (c_flag && !d_flag)
937 fprintf(stderr,
938 "Unable to open rcfile \"%s\"\n", p);
939 continue;
941 getcommands(FALSE);
942 closeinput();
948 * isinoderead - determine if we have read a given dev/inode
950 * This function returns the index of the readset element that matches
951 * a given device/inode, -1 otherwise.
954 * WIN32 NOTE:
956 * This function does not work under WIN32. The sbuf->st_ino is always
957 * zero because the FAT and NTFS filesystems do not support inodes.
958 * They also don't support links, which is why you need this function
959 * under UNIX. For WIN32, use _fullpath() to determine if you have
960 * already opened a file.
962 * given:
963 * sbuf stat of the inode in question
966 S_FUNC int
967 isinoderead(struct stat *sbuf)
969 int i;
971 /* deal with the empty case */
972 if (readset == NULL || maxreadset <= 0) {
973 /* readset is empty */
974 return -1;
977 /* scan the entire readset */
978 for (i=0; i < maxreadset; ++i) {
979 #if defined(_WIN32) || defined(__MSDOS__)
980 char tmp[_MAX_PATH+1];
981 tmp[_MAX_PATH] = '\0';
982 if (_fullpath(tmp, cip->i_name, _MAX_PATH) &&
983 readset[i].active &&
984 strcasecmp(readset[i].path, tmp) == 0) {
985 /* found a match */
986 return i;
988 #else /* Windoz free systems */
989 if (readset[i].active &&
990 sbuf->st_dev == readset[i].inode.st_dev &&
991 sbuf->st_ino == readset[i].inode.st_ino) {
992 /* found a match */
993 return i;
995 #endif /* Windoz free systems */
998 /* no match found */
999 return -1;
1004 * findfreeread - find the next free readset element
1006 * This function will return the index of the next free readset element.
1007 * If needed, this function will allocate new readset elements.
1009 * This function returns the index of the next free element, or -1.
1011 S_FUNC int
1012 findfreeread(void)
1014 int i;
1016 /* deal with an empty readset case */
1017 if (readset == NULL || maxreadset <= 0) {
1019 /* malloc a new readset */
1020 readset = (READSET *)malloc((READSET_ALLOC+1)*sizeof(READSET));
1021 if (readset == NULL) {
1022 return -1;
1024 maxreadset = READSET_ALLOC;
1025 for (i=0; i < READSET_ALLOC; ++i) {
1026 readset[i].active = 0;
1029 /* return first entry */
1030 return 0;
1033 /* try to find a free readset entry */
1034 for (i=0; i < maxreadset; ++i) {
1035 if (readset[i].active == 0) {
1036 /* found a free readset entry */
1037 return i;
1041 /* all readset entries are in use, allocate more */
1042 readset = (READSET *)realloc(readset,
1043 (maxreadset+READSET_ALLOC) * sizeof(READSET));
1044 if (readset == NULL) {
1045 return -1;
1047 for (i=0; i < READSET_ALLOC; ++i) {
1048 readset[i+maxreadset].active = 0;
1050 maxreadset += READSET_ALLOC;
1052 /* return the first newly allocated free entry */
1053 return maxreadset-READSET_ALLOC;
1058 * addreadset - add a entry to the readset array if it is not already there
1060 * This function attempts to add a file into the readset. If the readset
1061 * has an entry with a matching dev/inode, then that entry is updated with
1062 * the new name and path. If no such readset entry is found, a new entry
1063 * is added.
1065 * This function returns the index of the readset entry, or -1 if error.
1067 * given:
1068 * name name given to read or include
1069 * path full pathname of file
1070 * sbuf stat of the path
1072 S_FUNC int
1073 addreadset(char *name, char *path, struct stat *sbuf)
1075 int ret; /* index to return */
1076 size_t name_len; /* length of read set name */
1077 size_t path_len; /* length of path to read set name */
1079 /* find the inode */
1080 ret = isinoderead(sbuf);
1081 if (ret < 0) {
1082 /* not in readset, find a free node */
1083 ret = findfreeread();
1084 if (ret < 0) {
1085 /* cannot find/form a free readset entry */
1086 return -1;
1088 } else {
1089 /* found an readset entry, free old readset data */
1090 if (readset[ret].name != NULL) {
1091 free(readset[ret].name);
1093 if (readset[ret].path != NULL) {
1094 free(readset[ret].path);
1098 /* load our information into the readset entry */
1099 name_len = strlen(name);
1100 readset[ret].name = (char *)malloc(name_len+1);
1101 if (readset[ret].name == NULL) {
1102 return -1;
1104 strncpy(readset[ret].name, name, name_len+1);
1105 #if defined(_WIN32) || defined(__MSDOS__)
1107 * For WIN32, _fullpath expands the path to a fully qualified
1108 * path name, which under WIN32 FAT and NTFS is unique, just
1109 * like UNIX inodes. _fullpath also allocated the memory for
1110 * this new longer path name.
1113 readset[ret].path = _fullpath(NULL, path, _MAX_PATH);
1114 if (readset[ret].path == NULL) {
1115 return -1;
1118 #else /* Windoz free systems */
1119 path_len = strlen(path);
1120 readset[ret].path = (char *)malloc(path_len+1);
1121 if (readset[ret].path == NULL) {
1122 return -1;
1124 strncpy(readset[ret].path, path, path_len+1);
1125 #endif /* Windoz free systems */
1126 readset[ret].inode = *sbuf;
1127 readset[ret].active = 1;
1129 /* return index of the newly added entry */
1130 return ret;