/*
 * touch: create or update times on files
 */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <fcntl.h>
#include <os2.h>		/* for DosSetFileInfo() - aka utime */
#include "glob.h"

extern int getopt();		/* getopt() */
extern int opterr, optind;
extern char *optarg;

char touch_access=1;		/* flags of interest */
char touch_modified=1;
char create_file=1;
char force_touch=0;

/*
 * badboy() complains and dies
 */
badboy(msg)
char *msg;
{
    if (msg)
	fprintf(stderr, "touch: %s\n", msg);
    fprintf(stderr, "usage: touch [-amcf] [mmddhhmm[yy]] file [...]\n");
    exit(1);
} /* badboy */


/*
 * digarg() looks to see if a string is all digits
 */
digarg(arg)
register char *arg;
{
    while (*arg)
	if (!isdigit(*arg++))
	    return 0;
    return 1;
} /* digarg */


/*
 * get_today() gets the timestamp for today
 */
get_today(dt,tm)
FDATE *dt;
FTIME *tm;
{
    DATETIME now;
    
    DosGetDateTime(&now);
    dt->year = now.year-1980;
    dt->month= now.month;
    dt->day  = now.day;
    tm->twosecs = now.seconds/2;
    tm->minutes = now.minutes;
    tm->hours   = now.hours;
} /* get_today */


/*
 * set_timestamp() sets the date and time to a user-defined value
 */
set_timestamp(argument, dt, tm)
char *argument;
FDATE *dt;
FTIME *tm;
{
    register len = strlen(argument);
    register long stime = atol(argument);

    if (len != 8 && len != 10)
	badboy("invalid time-setting");

    if (len == 10) {
	dt->year = (stime % 100L) - 80;
	stime /= 100L;
    }
    tm->twosecs= 0;
    tm->minutes= (stime % 100L); stime /= 100L;
    tm->hours  = (stime % 100L); stime /= 100L;
    dt->day    = (stime % 100L); stime /= 100L;
    dt->month  = (stime % 100L);
} /* set_timestamp */


/*
 * touch_a_file() does the work of touching a file
 */
touch_a_file(file, dt, tm)
char *file;
FDATE *dt;
FTIME *tm;
{
    char file_exists;		/* does the file already exist? */
    short attrib;		/* original attributes of file */
    register fd;		/* file descriptor */
    register mode;		/* open() mode */
    FILESTATUS dta;		/* for updating date and time */

    /* get the attributes of the file if it exists
     */
    file_exists = (DosQFileMode(file, &attrib, 0L) == 0);

    /* if we're forcing readonly files, reset the attributes
     * to not-readonly
     */
    if (force_touch && file_exists && (attrib & F_RDONLY))
	DosSetFileMode(file, attrib & (F_AMASK^F_RDONLY), 0L);

    /* if -c was specified, we don't want to make new files
     */
    mode = create_file ? (O_RDWR|O_BINARY|O_CREAT) : (O_RDWR|O_BINARY);
    
    /* open the file, set the date, then restore the file attributes
     * if we'd changed them
     */
    if ((fd=open(file, mode, 0666)) >= 0) {
	memset(&dta, 0, sizeof dta);	/* don't set anything unexpected */
	if (touch_access && _osmode != DOS_MODE) {
	    /* access times are not supported under DOS */
	    dta.fdateLastAccess = *dt;
	    dta.ftimeLastAccess = *tm;
	}
	if (touch_modified) {
	    dta.fdateLastWrite = *dt;
	    dta.ftimeLastWrite = *tm;
	}
	if (DosSetFileInfo(fd, 0x01, (PBYTE)&dta, sizeof dta) != 0)
	    fprintf(stderr, "can't touch %s\n", file);
	close(fd);

	if (file_exists && (attrib & F_RDONLY))
	    DosSetFileMode(file, attrib & F_AMASK, 0L);
    }
    else if (!force_touch)
	perror(file);
} /* touch_a_file */


/*
 * touch, in mortal flesh
 */
main(argc, argv)
char **argv;
{
    FDATE tdate;
    FTIME ttime;
    register opt;
    register i, fd;

    opterr = 1;	/* getopt will complain about missing things */
    while ((opt=getopt(argc, argv, "amcf")) != EOF)
	switch (opt) {
	case 'a': touch_modified = 0; break;
	case 'm': touch_access = 0; break;
	case 'c': create_file = 0; break;
	case 'f': force_touch = 1; break;
	default:  badboy((char*)0);
	}

    if (touch_modified == 0 && touch_access == 0)
	badboy("can't set both -a and -m");

    get_today(&tdate, &ttime);
     
    /* check if we're setting an explicit date & time
     */
    if (optind < argc && digarg(argv[optind]))
	set_timestamp(argv[optind++], &tdate, &ttime);

    optind--;
    expand_arglist(argc-optind, argv+optind, (struct args_t*)0);

    if (myargc < 1)
	badboy((char*)0);

    for (i=0; i<myargc; i++)
	touch_a_file(myargv[i], &tdate, &ttime);
} /* touch */