#define NOTIMEZONE

#ifndef lint
static char *RCSid="$Id: strftime.c,v 1.4 1995/12/07 21:41:12 drd Exp $";
#endif

/*
 * Implementation of strftime for systems missing this (e.g. vaxctrl)
 *
 * This code was written based on the NeXT strftime man-page, sample output of
 * the function and an ANSI-C quickreference chart. This code does not use
 * parts of any existing strftime implementation.
 *
 * Apparently not all format chars are implemented, but this was all I had in
 * my documentation.
 *
 * (written by Alexander Lehmann)
 */

#include <time.h>
#include <string.h>
#include <stdio.h>
#include "setshow.h"  /* for days/months */

#ifdef TEST /* test case */
#define strftime _strftime
#else
#define const /**/
#endif


static void fill(from, pto, pmaxsize)
     char *from;
     char **pto;
     size_t *pmaxsize;
{
  strncpy(*pto, from, *pmaxsize);
  if(*pmaxsize<strlen(from)) {
    (*pto)+=*pmaxsize;
    *pmaxsize=0;
  } else {
    (*pto)+=strlen(from);
    (*pmaxsize)-=strlen(from);
  }
}

static void number(num, pad, pto, pmaxsize)
     int num;
     int pad;
     char **pto;
     size_t *pmaxsize;
{
  char str[100];
  
  sprintf(str, "%0*d", pad, num);
  fill(str, pto, pmaxsize);
}

size_t strftime(s, max, format, tp)
     char *s;
     size_t max;
     const char *format;
     const struct tm *tp;
{
  char *start=s;
  size_t maxsize=max;

  if(max>0) {
    while(*format && max>0) {
      if(*format!='%') {
      	*s++=*format++;
	max--;
      } else {
        format++;
	switch(*format++) {
	  case 'a': /* abbreviated weekday name */
	    if(tp->tm_wday>=0 && tp->tm_wday<=6)
	      fill(abbrev_day_names[tp->tm_wday], &s, &max);
	    break;
	  case 'A': /* full name of the weekday */
	    if(tp->tm_wday>=0 && tp->tm_wday<=6)
	      fill(full_day_names[tp->tm_wday], &s, &max);
	    break;
	  case 'b': /* abbreviated month name */
	    if(tp->tm_mon>=0 && tp->tm_mon<=11)
	      fill(abbrev_month_names[tp->tm_mon], &s, &max);
	    break;
	  case 'B': /* full name of month */
	    if(tp->tm_mon>=0 && tp->tm_mon<=11)
	      fill(full_month_names[tp->tm_mon], &s, &max);
	    break;
	  case 'c': /* locale's date and time reprensentation */
	    strftime(s, max, "%a %b %X %Y", tp);
	    max-=strlen(s);
	    s+=strlen(s);
	    break;
	  case 'd': /* day of the month (01-31) */
	    number(tp->tm_mday, 2, &s, &max);
	    break;
	  case 'H': /* hour of the day (00-23) */
	    number(tp->tm_hour, 2, &s, &max);
	    break;
	  case 'I': /* hour of the day (01-12) */
	    number((tp->tm_hour+11)%12+1, 2, &s, &max);
	    break;
	  case 'j': /* day of the year (001-366) */
	    number(tp->tm_yday+1, 3, &s, &max);
	    break;
	  case 'm': /* month of the year (01-12) */
	    number(tp->tm_mon+1, 2,&s, &max);
	    break;
	  case 'M': /* minute (00-59) */
	    number(tp->tm_min, 2, &s, &max);
	    break;
	  case 'p': /* locale's version of AM or PM */
	    fill(tp->tm_hour>=6 ? "PM" : "AM", &s, &max);
	    break;
	  case 'S': /* seconds (00-59) */
	    number(tp->tm_sec, 2, &s, &max);
	    break;
	  case 'U': /* week number of the year (00-53) with Sunday as the first day of the week */
	    number((tp->tm_yday-(tp->tm_yday-tp->tm_wday+7)%7+7)/7, 1, &s, &max);
	    break;
	  case 'w': /* weekday (Sunday=0 to Saturday=6) */
	    number(tp->tm_wday, 1, &s, &max);
	    break;
	  case 'W': /* week number of the year (00-53) with Monday as the first day of the week */
	    number((tp->tm_yday-(tp->tm_yday-tp->tm_wday+8)%7+7)/7, 2, &s, &max);
	    break;
	  case 'x': /* locale's date representation */
	    strftime(s, max, "%a %b %d %Y", tp);
	    max-=strlen(s);
	    s+=strlen(s);
	    break;
	  case 'X': /* locale's time representation */
#ifndef NOTIMEZONE
	    strftime(s, max, "%H:%M:%S %Z", tp);
#else
	    strftime(s, max, "%H:%M:%S", tp);
#endif
	    max-=strlen(s);
	    s+=strlen(s);
	    break;
	  case 'y': /* two-digit year representation (00-99) */
	    number(tp->tm_year%100, 2, &s, &max);
	    break;
	  case 'Y': /* four-digit year representation */
	    number(tp->tm_year+1900, 2, &s, &max);
	    break;
#ifndef NOTIMEZONE
	  case 'Z': /* time zone name */
	    fill(tp->tm_zone, &s, &max);
	    break;
#endif
	  case '%': /* percent sign */
	  default:
	    *s++=*(format-1);
	    max--;
	    break;
	  }
      }
    }
    if(s-start<maxsize) {
      *s++='\0';
    } else {
      *(s-1)='\0';
    }
  }
  
  return s-start;
}

#ifdef TEST

#undef strftime
#define test(s)				\
	printf("%s -> ",s );		\
	_strftime(str, 100, s, ts);	\
	printf("%s - ", str);		\
	strftime(str, 100, s, ts);	\
	printf("%s\n", str)

int main()
{
  char str[100];
  struct tm *ts;
  time_t t;
  int i;

  t=time(NULL);

  ts=localtime(&t);

  test("%c");
  test("test%%test");
  test("%a %b %d %X %Y");
  test("%x %X");
  test("%A %B %U");
  test("%I:%M %p %j %w");

  t-=245*24*60*60;

  for(i=0;i<366;i++) {
    ts=localtime(&t);
    printf("%03d: ", i);
    test("%a %d %m %W");
    t+=24*60*60;
  }

  return 0;
}

#endif

