/*
 *      q o p e n
 *
 *  This is designed to act as a wrapper to open() to
 *  handle automatic translation of '/' and '.' characters
 *  in filenames to the QDOS/SMS standard of '_'.
 *
 *  It is automatically invoked by the fcntl.h header
 *  file if _USE_QOPEN is defined. (really ??? jh)
 *
 *  AMENDMENT HISTORY
 *  ~~~~~~~~~~~~~~~~~
 *  30 Dec 94   DJW   - First version
 *  13 Nov 98   JH    - See if we can make a useful version for perl
 */

#define  __LIBRARY__

#include <fcntl.h>
#include <libgen.h>
#include <limits.h>
#include <string.h>
#include <unistd.h>

// Crap, pure unadulterated crap this stupid, stupid QDOS file system
// Lets see if we beat some sense into it ...

// Test mode, (e)gcc -Wall -O3 -DETEST -o qopen qopen.c

#ifndef MAXNAMELEN
# include <stdio.h>
# define MAXNAMELEN PATH_MAX
#endif

int perlopen (const char *name, int mode,...)
{
    char newname[MAXNAMELEN];
    char *ptr1, *ptr2;
    int reply;
    int ls = 0;
    
    ptr1 = NULL;
    ptr2 = (char *) name;
    /*
     *  See if special characters
     *  so translation is required.
     */
    if (strpbrk (name, "\\/."))
    {
	char *s, *d;
        d = ptr1 = newname;
        s = ptr2;
        
        if(*s == '.' || *s == '/' || *s == '\\')
        {
            s++;
            ls = 1;
        }
        
	while(*s)
        {
    	  if(*s == '/' || *s == '\\')
          {
              if(d != ptr1 && *(d-1) != '_')
                  *d++ = '_';
          }
          else
          {
              if((*s != '_') || (d != ptr1 && *(d-1) != '_'))
              *d++ = *s;
          }
          
          s++;
        }
	*d = 0;
    }

#ifdef ETEST
    printf("Xlate %s into  =>%s<=\n",
           name, (ptr1) ? ptr1 : name);
    return (reply = 0);
#else
    
        /*
         *  For WRITE modes we need to find out if the file
         *  under the original name already exists, as in
         *  that case it gets precedence.
         */
    if (ls == 0 && (mode & (O_WRONLY | O_RDWR)) != 0)
    {
	int fd;
	if ((fd = __Open (name, O_RDONLY)) >= 0)
	{
	    (void) close (fd);
	    ptr1 = NULL;
	}
    }
    /*
     *  Now lets try the opens
     */
    if (ptr1 != NULL)
    {
	char *d;
	if ((reply = __Open (ptr1, mode)) >= 0)
	{
	    return reply;
	}
	else if ((d = strrchr (ptr1, '.')) != NULL)
	{
	    *d = '_';
	    if ((reply = __Open (ptr1, mode)) >= 0)
	    {
		return reply;
	    }
	}
    }
    return __Open (ptr2, mode);
#endif
}
#ifdef ETEST
int main(void)
{
    const char **p;
    const char *names[] =
    {
        "./test.me",
        "/win1///_another_one",
        "win2_test_me/here",
        ".",
        "./",
        "mdv2_____test_me/here",
        "mdv2_///\\\\\\____test_me/here",                
        NULL
    };
    for(p = names; *p; p++)
    {
        perlopen(*p, 0);
    }
    return 0;
}
#endif
