home *** CD-ROM | disk | FTP | other *** search
- /*
- * MODULE NAME: expand.c Revision: 1.0
- *
- * AUTHOR: Ian Stewartson
- *
- * LOCATION: Data Logic,
- * Greenford,
- * Middlesex,
- * England.
- *
- #include <logo.h>
- * MODULE DEFINITION: This function expandes the command line parameters
- * in a UNIX like manner. Wild character *?[] are
- * allowed in file names. @filename causes command lines
- * to be read from filename. Strings between " or ' are
- * not expanded. All entries in the array are malloced.
- *
- * This function replaces the standard MS-DOS command
- * line processing function (_setargv in stdargv.obj).
- *
- * Support for OS2 added. Compile with -DOS2
- *
- * CALLING SEQUENCE: The following calling sequences are used:
- *
- * void _setargv ();
- *
- * ERROR MESSAGES: Out of memory
- *
- * INCLUDE FILES:
- */
-
- #include <sys/types.h> /* MS-DOS type definitions */
- #include <sys/stat.h> /* File status definitions */
- #include <stdio.h> /* Standard I/O delarations */
- #include <stdlib.h> /* Standard library functions */
- #include <errno.h> /* Error number declarations */
- #ifdef OS2
- #include <os2.h> /* OS2 functions declarations */
- #else
- #include <dos.h> /* DOS functions declarations */
- #include <bios.h> /* BIOS functions declarations */
- #endif
- #include <ctype.h> /* Character type declarations */
- #include <string.h> /* String library functions */
- #include <limits.h> /* String library functions */
- #include <fcntl.h> /* File Control Declarations */
- #include <dirent.h> /* Direction I/O functions */
- #include <unistd.h>
-
- /*
- * DATA DEFINITIONS:
- */
-
- #define MAX_LINE 160 /* Max line length */
- #define S_ENTRY sizeof (char *)
-
- /*
- * DATA DECLARATIONS:
- */
- #ifdef MSDOS
-
- extern void _setargv (void);
- static void exp_line (char *); /* Expand file */
- static int ex_pfield (char *, char *); /* Expand field */
- static void ex_pfile (char *);
- static char *ex_gspace (int, char *); /* Get space */
- static void ex_add_arg (char *); /* Add argument */
- static char *ex_skip_sp (char *); /* Skip spaces */
- static char *ex_tounix (char *); /* Convert name to Unix format */
- static int ex_find (char*, int); /* Split file name */
- static void ex_fatal (int, char *, char *); /* Fatal error processing*/
- static char *ex_environment (char *); /* Process environment */
- static char *_ex_multi_drive (char *); /* Check for multidrive */
- static int N_floppy_disks (void);
- static char *ex_nomem = "%s: %s\n";
-
- extern char far *_pgmptr; /* Program name */
- extern char **__argv; /* Current argument address */
- extern int __argc; /* Current argument count */
-
- #ifdef OS2
- static void _dos_setdrive (unsigned int, unsigned int *);
- static void _dos_getdrive (unsigned int *);
- extern ushort _aenvseg; /* Environment seg */
- extern ushort _acmdln; /* Command line offset */
- #endif
-
- /*
- * MODULE ABSTRACT: _setargv
- *
- * UNIX like command line expansion
- */
-
- void _setargv ()
- {
- #ifdef OS2
- char far *argvp = (char far *)((((long)_aenvseg) << 16));
- ushort off = _acmdln;
-
- while (--off)
- {
- if (argvp[off - 1] == 0)
- break;
- }
-
- /* Add program name */
-
- _pgmptr = &argvp[off];
-
- if (argvp[_acmdln] == 0)
- ex_add_arg (ex_tounix (_pgmptr)); /* Add the program name */
-
- else
- {
- argvp += _acmdln;
- ex_add_arg (ex_tounix (argvp)); /* Add the program name */
- argvp += strlen (argvp) + 1;
- exp_line (argvp);
- }
- #else
- /* Set up pointer to command line */
- char far *argvp = (char far *)((((long)_psp) << 16) + 0x081L);
- unsigned int envs = *(int far *)((((long)_psp) << 16) + 0x02cL);
- char far *s; /* Temporary string pointer */
- # ifndef M_I86LM
- char buf[MAX_LINE]; /* Temporary space */
- char *cp;
- # endif
-
- /* Command line can be null or 0x0d terminated - convert to null */
-
- s = argvp;
-
- while (*s && (*s != 0x0d))
- ++s;
-
- if (*s == 0x0d)
- *s = 0;
-
- /* Set up global parameters and expand */
-
- __argc = 0;
-
- /* Get the program name */
-
- if (_osmajor <= 2)
- s = "unknown";
-
- /* In the case of DOS 3+, we look in the environment space */
-
- else
- {
- s = (char far *)(((long)envs) << 16);
-
- while (*s)
- {
- while (*(s++) != 0);
- }
-
- s += 3;
- }
-
- _pgmptr = s;
-
- # ifndef M_I86LM
- cp = buf;
- while (*(cp++) = *(s++));
-
- ex_add_arg (ex_tounix (buf)); /* Add the program name */
-
- s = argvp;
- cp = buf;
- while (*(cp++) = *(s++));
-
- exp_line (buf);
- # else
- ex_add_arg (ex_tounix (s)); /* Add the program name */
- exp_line (argvp);
- # endif
- #endif
-
- ex_add_arg ((char *)NULL);
- --__argc;
- }
-
- /*
- * Expand a line
- */
-
- static void exp_line (argvp)
- char *argvp; /* Line to expand */
- {
- char *spos; /* End of string pointer */
- char *cpos; /* Start of string pointer */
- char *fn; /* Extracted file name string */
-
- /* Search for next separator */
-
- spos = argvp;
-
- while (*(cpos = ex_skip_sp (spos)))
- {
-
- /* Extract string argument */
-
- if ((*cpos == '"') || (*cpos == '\''))
- {
- spos = cpos + 1;
-
- do
- {
- if ((spos = strchr (spos, *cpos)) != NULL)
- {
- spos++;
- if (spos[-2] != '\\')
- break;
- }
-
- else
- spos = &spos[strlen (cpos)];
-
- }
- while (*spos);
-
- fn = ex_gspace (spos - cpos - 2, cpos + 1);
- }
-
- /* Extract normal argument */
-
- else
- {
- spos = cpos;
- while (!isspace(*spos) && *spos)
- spos++;
-
- fn = ex_gspace (spos - cpos, cpos);
- }
-
- /* Process argument */
-
- if (*cpos != '"')
- fn = ex_environment (fn);
-
- switch (*cpos)
- {
- case '@': /* Expand file */
- ex_pfile (fn);
- break;
-
- case '"': /* Expand string */
- case '\'':
- ex_add_arg (fn);
- break;
-
- default: /* Expand field */
- if (!ex_find (fn, 0))
- ex_add_arg (fn);
- }
-
- free (fn);
- }
- }
-
- /* Expand a field if it has metacharacters in it */
-
- static int ex_pfield (prefix, postfix)
- char *prefix; /* Prefix field */
- char *postfix; /* Postfix field */
- {
- int count; /* File path length */
- int f_count = 0; /* Number of files generated */
- int slash_flag = 0; /* slash required */
- char fn[PATH_MAX + NAME_MAX + 2];/* Search file name */
- char *name; /* Match string */
- char *p, *p1;
- DIR *dp;
- struct dirent *c_de;
- unsigned int c_drive; /* Current drive */
- unsigned int m_drive; /* Max drive */
- unsigned int s_drive; /* Selected drive */
- unsigned int x_drive, y_drive; /* Dummies */
- char *multi; /* Multi-drive flag */
- char t_drive[2];
-
- /* Convert file name to lower case */
-
- strlwr (prefix);
-
- /* Search all drives ? */
-
- if ((multi = _ex_multi_drive (prefix)) != (char *)NULL)
- {
- _dos_getdrive (&c_drive); /* Get number of drives */
- _dos_setdrive (c_drive, &m_drive);
- t_drive[1] = 0;
-
- for (s_drive = 1; s_drive <= m_drive; ++s_drive)
- {
- _dos_setdrive (s_drive, &x_drive);
- _dos_getdrive (&y_drive);
- _dos_setdrive (c_drive, &x_drive);
-
- /* Check to see if the second diskette drive is really there */
-
- if ((N_floppy_disks () < 2) && (s_drive == 2))
- continue;
-
- /* If the drive exists and is in our list - process it */
-
- *multi = 0;
- *t_drive = (char)(s_drive + 'a' - 1);
-
- if ((y_drive == s_drive) && pnmatch (t_drive, prefix, 0))
- {
- *multi = ':';
- *fn = *t_drive;
- strcpy (fn + 1, multi);
- f_count += ex_pfield (fn, postfix);
- }
-
- *multi = ':';
- }
-
- return f_count;
- }
-
- /* Get the path length */
-
- p = strrchr (prefix, '/');
- p1 = strchr (prefix, ':');
-
- if ((p1 == (char *)NULL) || (p1 < p))
- {
- if (p == (char *)NULL)
- {
- count = 0;
- name = prefix;
- }
-
- else
- {
- count = p - prefix;
- name = p + 1;
- }
- }
-
- else if ((p == (char *)NULL) || (p < p1))
- {
- count = p1 - prefix;
- name = p1 + 1;
- }
-
- /* Set up file name for search */
-
- if (((count == 2) && (strncmp (prefix + 1, ":/", 2) == 0)) ||
- ((count == 0) && (*prefix == '/')))
- {
- strncpy (fn, prefix, ++count);
- fn[count] = 0;
- strcat (fn, ".");
- }
-
- else
- {
- if ((count == 1) && (*(prefix + 1) == ':'))
- count++;
-
- strncpy (fn, prefix, count);
- fn[count] = 0;
-
- if (((count == 2) && (*(prefix + 1) == ':')) || (count == 0))
- strcat (fn, ".");
-
- else
- slash_flag = 1;
- }
-
- /* Search for file names */
-
- if ((dp = opendir (fn)) == (DIR *)NULL)
- return 0;
-
- /* Are there any matches */
-
- while ((c_de = readdir (dp)) != (struct dirent *)NULL)
- {
- if ((*c_de->d_name == '.') && (*name != '.'))
- continue;
-
- /* Check for match */
-
- if (pnmatch (c_de->d_name, name, 0))
- {
- fn[count] = 0;
-
- if (slash_flag)
- strcat (fn, "/");
-
- strcat (fn, c_de->d_name);
-
- /* If the postfix is not null, this must be a directory */
-
- if (postfix != (char *)NULL)
- {
- struct stat statb;
-
- if (stat (fn, &statb) < 0 ||
- (statb.st_mode & S_IFMT) != S_IFDIR)
- continue;
-
- strcat (fn, "/");
- strcat (fn, postfix);
- }
-
- f_count += ex_find (fn, 1);
- }
- }
-
- closedir (dp);
- return f_count;
- }
-
- /* Expand file name */
-
- static void ex_pfile (file)
- char *file; /* Expand file name */
- {
- FILE *fp; /* File descriptor */
- char *p; /* Pointer */
- int c_maxlen = MAX_LINE;
- char *line; /* Line buffer */
-
- /* Grab some memory for the line */
-
- if ((line = malloc (c_maxlen)) == (char *)NULL)
- ex_fatal (ENOMEM, ex_nomem, (char *)NULL);
-
- /* If file open fails, expand as a field */
-
- if ((fp = fopen (file + 1, "rt")) == NULL)
- {
- if (!ex_find (file, 0))
- ex_add_arg (file);
-
- return;
- }
-
- /* For each line in the file, remove EOF characters and add argument */
-
- while (fgets (line, c_maxlen, fp) != (char *)NULL)
- {
- while ((p = strchr (line, '\n')) == (char *)NULL)
- {
- if ((p = strchr (line, 0x1a)) != (char *)NULL)
- break;
-
- if ((line = realloc (line, c_maxlen + MAX_LINE)) == (char *)NULL)
- ex_fatal (ENOMEM, ex_nomem, (char *)NULL);
-
- if (fgets (&line[c_maxlen - 1], MAX_LINE, fp) == (char *)NULL)
- break;
-
- c_maxlen += MAX_LINE - 1;
- }
-
- if (p != (char *)NULL)
- *p = 0;
-
- ex_add_arg (line);
- }
-
- if (ferror(fp))
- ex_fatal (errno, "%s: %s (%s)\n", file + 1);
-
- free (line);
- fclose (fp);
- }
-
- /* Get space for name */
-
- static char *ex_gspace (l, in_s)
- int l; /* String length */
- char *in_s; /* String address */
- {
- char *out_s; /* Malloced space address */
-
- if ((out_s = malloc (l + 1)) == (char *)NULL)
- ex_fatal (ENOMEM, ex_nomem, (char *)NULL);
-
- /* Copy string for specified length */
-
- strncpy (out_s, in_s, l);
- out_s[l] = 0;
-
- return (out_s);
- }
-
- /* Append an argument to the string */
-
- static void ex_add_arg (fn)
- char *fn; /* Argument to add */
- {
- if (__argc == 0)
- __argv = (char **)malloc (50 * S_ENTRY);
-
- else if ((__argc % 50) == 0)
- __argv = (char **)realloc (__argv, (__argc + 50) * S_ENTRY);
-
- if (__argv == (char **)NULL)
- ex_fatal (ENOMEM, ex_nomem, (char *)NULL);
-
- __argv[__argc++] = (fn == (char *)NULL) ? fn : ex_gspace (strlen (fn), fn);
- }
-
- /* Skip over spaces */
-
- static char *ex_skip_sp (a)
- char *a; /* String start address */
- {
- while (isspace(*a))
- a++;
-
- return (a);
- }
-
- /* Convert name to Unix format */
-
- static char *ex_tounix (a)
- char *a;
- {
- char *sp = a;
-
- while ((a = strchr (a, '\\')) != (char *)NULL)
- *(a++) = '/';
-
- return strlwr (sp);
- }
-
- /* Find the location of meta-characters. If no meta, add the argument and
- * return NULL. If meta characters, return position of end of directory
- * name. If not multiple directories, return -1
- */
-
- static int ex_find (file, must_exist)
- char *file;
- int must_exist; /* FIle must exist flag */
- {
- char *p;
- int i;
- static char ex_meta[] = "?*[]\\"; /* Metacharacters */
-
- if ((p = strpbrk (file, ex_meta)) == (char *)NULL)
- {
- if (must_exist && (access (file, 0) < 0))
- return 0;
-
- ex_add_arg (file);
- return 1;
- }
-
- else if ((p = strchr (p, '/')) != (char *)NULL)
- *(p++) = 0;
-
- i = ex_pfield (file, p);
-
- if (p != (char *)NULL)
- *(--p) = '/';
-
- return i;
- }
-
- /* Fatal errors */
-
- static void ex_fatal (ecode, format, para)
- int ecode;
- char *format;
- char *para;
- {
- fprintf (stderr, format, "stdargv", strerror (ecode), para);
- exit (1);
- }
-
- /* Process Environment - note that field is a malloc'ed field */
-
- static char *ex_environment (field)
- char *field;
- {
- char *sp, *cp, *np, *ep;
- char save;
- int b_flag;
-
- sp = field;
-
- /* Replace any $ strings */
-
- while ((sp = strchr (sp, '$')) != (char *)NULL)
- {
- if (*(cp = ++sp) == '{')
- {
- b_flag = 1;
- ++cp;
-
- while (*cp && (*cp != '}'))
- cp++;
- }
-
- else
- {
- b_flag;
-
- while (isalnum(*cp))
- cp++;
- }
-
- /* Grab the environment variable */
-
- if (cp == sp)
- continue;
-
- save = *cp;
- *cp = 0;
- ep = getenv (sp + b_flag);
- *cp = save;
-
- if (ep != (char *)NULL)
- {
- np = ex_gspace (strlen(field) - (cp - sp) + strlen (ep) - 1, field);
- strcpy (&np[sp - field - 1], ep);
- ex_tounix (&np[sp - field - 1]);
- free (field);
- strcpy ((sp = &np[strlen(np)]), cp + b_flag);
- field = np;
- }
- }
-
- return field;
- }
-
- /* Check for multi_drive prefix */
-
- static char *_ex_multi_drive (prefix)
- char *prefix;
- {
- if (strlen (prefix) < 2)
- return (char *)NULL;
-
- if (((*prefix == '*') || (*prefix == '?')) && (prefix[1] == ':'))
- return prefix + 1;
-
- if (*prefix != '[')
- return (char *)NULL;
-
- while (*prefix && (*prefix != ']'))
- {
- if ((*prefix == '\\') && (*(prefix + 1)))
- ++prefix;
-
- ++prefix;
- }
-
- return (*prefix && (*(prefix + 1) == ':')) ? prefix + 1 : (char *)NULL;
- }
-
- /* Some OS/2 functions to emulate the DOS functions */
-
- #ifdef OS2
- static void _dos_getdrive (cdp)
- unsigned int *cdp;
- {
- USHORT cdr;
- ULONG ndr;
-
- DosQCurDisk((PUSHORT)&cdr, (PULONG) &ndr);
- *cdp = (unsigned int)cdr;
- }
-
- static void _dos_setdrive (cdr, ndp)
- unsigned int cdr;
- unsigned int *ndp;
- {
- USHORT dummy;
- ULONG ndr;
-
- DosQCurDisk((PUSHORT)&dummy, (PULONG) &ndr);
- *ndp = (unsigned int)ndr;
-
- DosSelectDisk ((USHORT)cdr);
- }
- #endif
-
- /* Return the number of floppy disks */
-
- static int N_floppy_disks ()
- {
- #ifdef OS2
- BYTE nflop = 1;
- DosDevConfig (&nflop, 2, 0);
- return nflop;
- #else
- return ((_bios_equiplist () & 0x00c0) >> 6) + 1;
- #endif
- }
- #endif
-