/*
   <p>General purpose file name finder (uses args or -z).</p>

   <kbd>
   <b>environ - C programming support functions</b><br>
   Copyright (C) 2005  Martin C Gregorie
   
   This program is free software; you can redistribute it and/or
   modify it under the terms of the Lesser GNU General Public License.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
  
   You should have received a copy of the Lesser GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   </kbd>
  
   <p>Contact Martin Gregorie at <i>martin@gregorie.org</i></p>
*/

#include <stdio.h>
#include <ctype.h>
#include "environ.h"

#ifdef OS9
#include <strings.h>
#else
#include <string.h>
#endif

/*
   A general purpose file name handler. It retrieves filenames from the
   command line arguments <i>argc</i> and <i>argv</i> if <u>listflag</u>
   is FALSE. The filenames are read from the <u>pathlist</u> file if
   <u>listflag</u> is TRUE. <i>getpath()</i> is used in conjunction with
   the command line parsing functions <i>getopt()</i> and <i>getarg()</i>.

   <i>getpath()</i> is called repeatedly until it returns null. Each call
   returns a pointer to the next filename or null when the end of the list
   is reached. 
                    
   Assumptions are that when it is called:
   <ul>                 
      <li><i>getopt()</i> has already processed the command line</li> 
      <li><u>pathlist</u> has been opened for reading
          if <u>listflag</u> is TRUE</li>
      <li>the global variable <i>optind</i> has been reset to 1</i> 
      <li>all non-option arguments are filenames.</li> 
   </ul>

   A convention observed by all OS-9 command line utilities is the use of
   the <b>-z</b> option to provide an alternative to passing filenames as
   command line arguments. If the option is absent the filename(s) are
   passed as command line arguments.
   If the <b>-z</b> option is present they will be taken from a file.
   If the option takes the form <b>-z=filename</b> then the list of
   filenames will be read from from the filename supplied as
   the option value. If option takes the form <b>-z</b> then the list of
   files is read from <i>stdin</i>.

   <i>getpath()</i> was originally written to implement this convention.
   When <i>getopt()</i> encounters a <b>-z</b> option, <u>listflag</u>
   is set TRUE. If <i>optarg</i> contains a filename this is opened for
   reading. If <i>optarg</i> is blank <i>stdin</i> is cloned. The result
   is passed to <i>getpath()</i> as <u>pathlist</u>.
*/
char* getpath(int argc, char *argv[], FILE *pathlist, int listflag)
{
    int            r;
    static char    nextpath[256];
    int            quote;
    int            c;
    int            i;
    
    void _fillstr(FILE *p, char *s, int t, int n);
    
    if (listflag)                                 /* next name */
    {                                             /* from file */
        while (isspace((c = getc(pathlist))))
            ;
        if (c != EOF)
        {
            switch(c)
            {
                case '"':
                case '\'':
                    _fillstr(pathlist,nextpath,c,255);
                    break;
                default:
                    ungetc(c,pathlist);
                    _fillstr(pathlist,nextpath,BLANK,255);
            }
            return(nextpath);
        }
    }
    else                                          /* next param */
    {                                             /* from cmdline */
        while (!(r = getarg(argc,argv)));          /* skip -opts */
        if (r != EOF)                             /* get filename */ 
            return(optarg);
    }
    return((char*)NULL);                          /* nothing found */
}

/*
   Put the next filename from the file p into the string
   buffer s, whose length is given in n. t contains the
   terminating character for the string. It is "'" or
   '"' if the name contains spaces and is enclosed in single
   or double quotes. If t is set to BLANK the name is terminated
   by any whitespace character or the end of the file.
*/           
void _fillstr(FILE *p, char *s, int t, int n)
{
    int     run;
    int     c;
    char    *err;

    err = s;
    run = TRUE;
    while(run && n)
    {
        c = getc(p);
        if (t != BLANK)
        {
            *s = 0;
            if (c == EOF || c == '\n')
                error(progname(),"Unterminated string in file list:",err);
        }
        if (t == BLANK && (isspace(c) || c == EOF))
            run = FALSE;
        else
        if (t != BLANK && (c == t || c == EOF))
            run = FALSE;
        else
        {
            *s++ = c;
            n--;
        }
    }
    *s = 0;
}
