#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <ctype.h>
#include <string.h>
#include <curses.h>
#include <fcntl.h>
#include <malloc.h>
#include <time.h>
#include <osbind.h>

#ifndef FILENAME_MAX
#define FILENAME_MAX  256
#endif


struct dlist     /* list of all subdirectories */
{
   char         *name;
   struct dlist *nxt;
};


int          rflag = 0;   /* recursive search  */
int          hflag = 0;   /* date/time by hand */

struct tm    *u_time;
struct ftime u_ftime;


void usage ()
{
   printf ("xtouch [-?] [-r] [-h] filespec [filespec] [...]\n");
   exit (-1);
}


void help ()
{
   printf ("xtouch : update date/time of files\n");
   printf ("options: -?  this help\n");
   printf ("         -r  recursive search\n");
   printf ("         -h  date/time by hand\n");
   exit (-1);
}


void no_mem ()
{
   printf ("\rnot enought memory");
   clrtoeol ();
   printf ("\n");
   exit (-1);
}


void get_datime ()
{
   char buf[256], *p;
   char *delim = " -.\t\r\n";

   printf ("date (mm-dd-yyyy): ");
   gets (buf);
   p = strtok (buf, delim);
   if (p)
   {
      u_time->tm_year = 80;
      u_time->tm_mday  = 0;
      u_time->tm_mon = atoi (p) - 1;
      p = strtok (NULL, delim);
      if (p)
      {
         u_time->tm_mday = atoi (p) - 1;
         p = strtok (NULL, delim);
         if (p)
         {
            u_time->tm_year = atoi (p);
            if (u_time->tm_year > 100)
               u_time->tm_year -= 1900;
         }
      }
   }

   printf ("time (hh.mm.ss)  : ");
   gets (buf);
   p = strtok (buf, delim);
   if (p)
   {
      u_time->tm_sec  = 0;
      u_time->tm_min   = 0;
      u_time->tm_hour  = atoi (p);
      p = strtok (NULL, delim);
      if (p)
      {
         u_time->tm_min = atoi (p);
         p = strtok (NULL, delim);
         if (p)
            u_time->tm_sec = atoi (p);
      }
   }
}

void search_dir (name, append)
   char         *name;
   struct dlist **append;
{
   register struct dlist *dl_tmp = *append;
   struct ffblk          f_info;
   int                   status;
   char                  buf[FILENAME_MAX + 1];
   char                  fmsk[FILENAME_MAX + 1];
   char                  *mask;

   strcpy (buf, name);
   mask = strrchr (buf, '\\');
   if (mask)
      mask++;
   else
      mask = buf;
   strcpy (fmsk, mask);
   strcpy (mask, "*.*");

   status = findfirst (buf, &f_info, FA_SUBDIR);
   while (status == 0)
   {
      if ((f_info.ff_attrib & FA_SUBDIR) &&
          (f_info.ff_name[0] != '.'))
      {
         sprintf (mask, "%s\\%s", f_info.ff_name, fmsk);

         dl_tmp->nxt = (struct dlist *) malloc ((size_t) sizeof (struct dlist));
         dl_tmp = dl_tmp->nxt;
         if (dl_tmp == NULL)
            no_mem ();

         dl_tmp->name = (char *) malloc ((size_t) (strlen (buf) + 4));
         if (dl_tmp->name == NULL)
            no_mem ();

         strcpy (dl_tmp->name, buf);
         dl_tmp->nxt = NULL;
         *append = dl_tmp;

      }
      status = findnext (&f_info);
   }
}


int touch (mask)
   char *mask;
{
   struct ffblk          f_info;
   int                   status, h, n = 0;
   char                  buf[FILENAME_MAX + 1];
   char                  *fname;

   strcpy (buf, mask);
   fname = strrchr (buf, '\\');
   if (fname)
      fname++;
   else
      fname = buf;

   status = findfirst (buf, &f_info, FA_READONLY | FA_ARCHIVE);
   while (status == 0)
   {
      if ((f_info.ff_attrib & (FA_SUBDIR | FA_VOLUME)) == 0)
      {
         strcpy (fname, f_info.ff_name);
         if (f_info.ff_attrib & FA_READONLY)
         {
            printf ("\rread only: '%s'", buf);
            clrtoeol ();
            printf ("\n");
         } else {
            printf ("\rtouching: '%s'", buf);
            clrtoeol ();
            h = open (buf, O_WRONLY);
            if (h == -1)
            {
               printf ("\rcannot touch file '%s'", buf);
               clrtoeol ();
               printf ("\n");
            } else {
               setftime (h, &u_ftime);
               close (h);
               n++;
            }
         }
      }
      status = findnext (&f_info);
   }
   return (n);
}


int check (msk)
   char *msk;
{
   int          n = 0;
   struct dlist *dl_cur, *dl_end, *dl_tmp;

   dl_cur = (struct dlist *) malloc ((size_t) sizeof (struct dlist));
   if (dl_cur == NULL)
      no_mem ();

   dl_cur->name = (char *) malloc ((size_t) (strlen (msk) + 4));
   if (dl_cur->name == NULL)
      no_mem ();

   strcpy (dl_cur->name, msk);
   dl_cur->nxt = NULL;
   dl_end = dl_cur;

   while (dl_cur)
   {
      if (rflag)
         search_dir (dl_cur->name, &dl_end);

      n += touch (dl_cur->name);

      dl_tmp = dl_cur;
      dl_cur = dl_cur->nxt;
      free (dl_tmp->name);
      free (dl_tmp);
   }

   return (n);
}


main (argc, argv)
   int  argc;
   char **argv;
{
   int    i, n, ok;
   time_t t;
   char   *p;

   if (argc < 2)
      usage ();


      /* --- check options --- */

   for (i = 1; i < argc; i++)
      if (argv[i][0] == '-')
      {
         p = &argv[i][1];
         do
         {
            switch (tolower(*p))
            {
               case '?':   help ();
               case 'r':   rflag = 1;
                           break;
               case 'h':   hflag = 1;
                           break;
               default:    printf ("unknown option '-%c'\n", *p);
                           usage ();
            }
            p++;
         } while (*p);
      }


      /* --- get time/date --- */

   time (&t);
   u_time = localtime (&t);

   if (hflag)
      get_datime ();

   u_ftime.ft_hour  = u_time->tm_hour;
   u_ftime.ft_min   = u_time->tm_min;
   u_ftime.ft_tsec  = u_time->tm_sec / 2;
   u_ftime.ft_year  = u_time->tm_year - 80;
   u_ftime.ft_month = u_time->tm_mon + 1;
   u_ftime.ft_day   = u_time->tm_mday + 1;


      /* --- use all file specifices --- */

   ok = 0;
   n  = 0;
   for (i = 1; i < argc; i++)
      if (argv[i][0] != '-')
      {
         ok = 1;
         n += check (argv[i]);
      }

   if (ok == 0)
   {
      printf ("no file specified\n");
      usage ();
   }

   printf ("\r%d files touched", n);
   clrtoeol ();
   printf ("\n");
   exit (0);
}
         
