home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / trn_12.zip / src / util.c < prev    next >
C/C++ Source or Header  |  1993-12-04  |  19KB  |  804 lines

  1. /* $Id: util.c,v 4.4.4.1 1992/02/23 21:25:39 sob PATCH_4 sob $
  2.  *
  3.  * $Log: util.c,v $
  4.  * Revision 4.4.4.1  1992/02/23  21:25:39  sob
  5.  * Patch level 4
  6.  *
  7.  * Revision 4.4.3.1  1992/02/01  03:09:32  sob
  8.  * Release 4.4 Patchlevel 3
  9.  *
  10.  * Revision 4.4  1991/09/09  20:27:37  sob
  11.  * release 4.4
  12.  *
  13.  *
  14.  * 
  15.  */
  16. /* This software is Copyright 1991 by Stan Barber. 
  17.  *
  18.  * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  19.  * use this software as long as: there is no monetary profit gained
  20.  * specifically from the use or reproduction of this software, it is not
  21.  * sold, rented, traded or otherwise marketed, and this copyright notice is
  22.  * included prominently in any copy made. 
  23.  *
  24.  * The author make no claims as to the fitness or correctness of this software
  25.  * for any use whatsoever, and it is provided as is. Any use of this software
  26.  * is at the user's own risk. 
  27.  */
  28.  
  29. #include "EXTERN.h"
  30. #include "common.h"
  31. #include "final.h"
  32. #include "INTERN.h"
  33. /*#include "util.h"*/
  34.  
  35. #include "util.h"
  36.  
  37. /***OS2: util.h uses "struct tm", which is defined in time.h ***
  38.  
  39.  ***     to avoid the fork/exec-combination, we use spawn.   ***
  40.  ***     but we need process.h for this call.                ***
  41.  
  42.  ***     because the mkdir-command does not work correctly,  ***
  43.  ***     we replace it with a system call, but we need       ***
  44.  ***     the include file "OS2.H" to do that                 ***/
  45.  
  46. #include "process.h"
  47. #include "os2.h"
  48.  
  49.  
  50. void
  51. util_init()
  52. {
  53.     ;
  54. }
  55.     
  56. /* fork and exec a shell command */
  57.  
  58. int
  59. doshell(shl,s)
  60. char *s, *shl;
  61. {
  62.     int status, pid, w;
  63.     char *shell;
  64.  
  65. #ifdef SIGTSTP
  66.     sigset(SIGTSTP,SIG_DFL);
  67.     sigset(SIGTTOU,SIG_DFL);
  68.     sigset(SIGTTIN,SIG_DFL);
  69. #endif
  70.     if (shl != Nullch)
  71.     {   change_sl2bsl(shl);
  72.         shell = shl;
  73.     }
  74.     else 
  75.         if ((shell = getenv("SHELL")) == Nullch || !*shell)
  76.             shell = PREFSHELL;
  77.     change_bsl2sl(shell);
  78.  
  79. /*** OS2: fork's are not yet implemented in emx 0.8d. But here
  80.           the vfork is used in combination with an execl-call.
  81.           So lets use the spawnl-function instead.  */
  82.  
  83. /*    if ((pid = vfork()) == 0) {
  84. #ifdef SERVER
  85.         int i;   */
  86.  
  87.     /* This is necessary to keep bourne shell from puking */
  88.  
  89. /*        for (i = 3; i < 10; ++i)
  90.                 close(i);   */
  91. /* #endif * SERVER */
  92.  
  93. /*    if (*s)
  94.         execl(shell, shell, "-c", s, Nullch);
  95.     else
  96.         execl(shell, shell, Nullch, Nullch, Nullch);
  97.     _exit(127);
  98.     }               */
  99.  
  100. /*** OS2: and now the new call: */
  101.  
  102. /*** OS2: We'll have to use /c and not -c  ***/
  103.     if (*s)
  104.         pid = spawnl(P_NOWAIT, shell, shell, "/c", s, Nullch);
  105.     else
  106.         pid = spawnl(P_NOWAIT, shell, shell, Nullch, Nullch, Nullch);
  107.  
  108. /*** OS2: end of fork/exec - substitution **
  109.  
  110.   *** put fingers crossed ....****/
  111.  
  112.  
  113.     signal(SIGINT, SIG_IGN);
  114. #ifdef SIGQUIT
  115.     signal(SIGQUIT, SIG_IGN);
  116. #endif 
  117.     termlib_reset();
  118.     waiting = TRUE;
  119.     while ((w = wait(&status)) != pid)
  120.     if (w == -1 && errno != EINTR)
  121.         break;
  122.     if (w == -1)
  123.     status = -1;
  124.     termlib_init();
  125.     waiting = FALSE;
  126.     sigset(SIGINT, int_catcher);    /* always catch interrupts */
  127. #ifdef SIGQUIT
  128.     signal(SIGQUIT, SIG_DFL);
  129. #endif 
  130. #ifdef SIGTSTP
  131.     sigset(SIGTSTP,stop_catcher);
  132.     sigset(SIGTTOU,stop_catcher);
  133.     sigset(SIGTTIN,stop_catcher);
  134. #endif
  135.  
  136.     return status;
  137. }
  138.  
  139. static char nomem[] = "rn: out of memory!\n";
  140.  
  141. /* paranoid version of malloc */
  142.  
  143. char *
  144. safemalloc(size)
  145. MEM_SIZE size;
  146. {
  147.     char *ptr;
  148.     char *malloc();
  149.  
  150.     ptr = malloc(size ? size : (MEM_SIZE)1);
  151.     if (ptr == Nullch) {
  152.     fputs(nomem,stdout) ; FLUSH;
  153.     sig_catcher(0);
  154.     }
  155.     return ptr;
  156. }
  157.  
  158. /* paranoid version of realloc */
  159.  
  160. char *
  161. saferealloc(where,size)
  162. char *where;
  163. MEM_SIZE size;
  164. {
  165.     char *ptr;
  166.     char *realloc();
  167.  
  168.     ptr = realloc(where,size?size:1);    /* realloc(0) is NASTY on our system */
  169.     if (ptr == Nullch) {
  170.     fputs(nomem,stdout) ; FLUSH;
  171.     sig_catcher(0);
  172.     }
  173.     return ptr;
  174. }
  175.  
  176. /* safe version of string copy */
  177.  
  178. char *
  179. safecpy(to,from,len)
  180. char *to;
  181. register char *from;
  182. register int len;
  183. {
  184.     register char *dest = to;
  185.  
  186.     if (from != Nullch) 
  187.     for (len--; len && (*dest++ = *from++); len--) ;
  188.     *dest = '\0';
  189.     return to;
  190. }
  191.  
  192. /* safe version of string concatenate, with \n deletion and space padding */
  193.  
  194. char *
  195. safecat(to,from,len)
  196. char *to;
  197. register char *from;
  198. register int len;
  199. {
  200.     register char *dest = to;
  201.  
  202.     len--;                /* leave room for null */
  203.     if (*dest) {
  204.     while (len && *dest++) len--;
  205.     if (len) {
  206.         len--;
  207.         *(dest-1) = ' ';
  208.     }
  209.     }
  210.     if (from != Nullch)
  211.     while (len && (*dest++ = *from++)) len--;
  212.     if (len)
  213.     dest--;
  214.     if (*(dest-1) == '\n')
  215.     dest--;
  216.     *dest = '\0';
  217.     return to;
  218. }
  219.  
  220. /* copy a string up to some (non-backslashed) delimiter, if any */
  221.  
  222. char *
  223. cpytill(to,from,delim)
  224. register char *to, *from;
  225. register int delim;
  226. {
  227.     for (; *from; from++,to++) {
  228.     if (*from == '\\' && from[1] == delim)
  229.         from++;
  230.     else if (*from == delim)
  231.         break;
  232.     *to = *from;
  233.     }
  234.     *to = '\0';
  235.     return from;
  236. }
  237.  
  238. /* return ptr to little string in big string, NULL if not found */
  239.  
  240. char *
  241. instr(big, little, case_matters)
  242. char *big, *little;
  243. int case_matters;
  244. {
  245.     register char *t, *s, *x;
  246.  
  247.     for (t = big; *t; t++) {
  248.     for (x=t,s=little; *s; x++,s++) {
  249.         if (!*x)
  250.         return Nullch;
  251.         if (case_matters == TRUE) {
  252.         if(*s != *x)
  253.             break;
  254.         } else {
  255.         register char c,d;
  256.         if (isupper(*s)) 
  257.             c = tolower(*s);
  258.         else
  259.             c = *s;
  260.         if (isupper(*x)) 
  261.             d = tolower(*x);
  262.         else
  263.             d = *x;
  264.         if ( c != d )
  265.             break;
  266.        }
  267.     }
  268.     if (!*s)
  269.         return t;
  270.     }
  271.     return Nullch;
  272. }
  273.  
  274. /* effective access */
  275.  
  276. #ifdef SETUIDGID
  277. int
  278. eaccess(filename, mod)
  279. char *filename;
  280. int mod;
  281. {
  282.     int protection, euid;
  283.     
  284.     mod &= 7;                /* remove extraneous garbage */
  285.     if (stat(filename, &filestat) < 0)
  286.     return -1;
  287.     euid = geteuid();
  288.     if (euid == ROOTID)
  289.     return 0;
  290.     protection = 7 & (filestat.st_mode >>
  291.       (filestat.st_uid == euid ? 6 :
  292.         (filestat.st_gid == getegid() ? 3 : 0)
  293.       ));
  294.     if ((mod & protection) == mod)
  295.     return 0;
  296.     errno = EACCES;
  297.     return -1;
  298. }
  299. #endif
  300.  
  301. /*
  302.  * Get working directory
  303.  */
  304. #ifndef GETWD
  305. #ifdef GETCWD
  306. char *
  307. getwd(np)
  308. char *np;
  309. {
  310.     char * name;
  311.     extern char * getcwd();
  312.     name = getcwd(np,512);
  313.     return(name);
  314. }
  315. #else
  316. char *
  317. getwd(np)            /* shorter but slower */
  318. char *np;
  319. {
  320.     FILE *popen();
  321.     FILE *pipefp = popen("/bin/pwd","r");
  322.  
  323.     if (pipefp == Nullfp) {
  324.     printf("Can't run /bin/pwd\n") ; FLUSH;
  325.     finalize(1);
  326.     }
  327.     fgets(np,512,pipefp);
  328.     np[strlen(np)-1] = '\0';    /* wipe out newline */
  329.     pclose(pipefp);
  330.     return np;
  331. }
  332. #endif
  333. #endif
  334. /* just like fgets but will make bigger buffer as necessary */
  335.  
  336. char *
  337. get_a_line(original_buffer,buffer_length,fp)
  338. char *original_buffer;
  339. register int buffer_length;
  340. FILE *fp;
  341. {
  342.     register int bufix = 0;
  343.     register int nextch;
  344.     register char *some_buffer_or_other = original_buffer;
  345.  
  346.     do {
  347.     if (bufix >= buffer_length) {
  348.         buffer_length *= 2;
  349.         if (some_buffer_or_other == original_buffer) {
  350.                     /* currently static? */
  351.         some_buffer_or_other = safemalloc((MEM_SIZE)buffer_length+1);
  352.         strncpy(some_buffer_or_other,original_buffer,buffer_length/2);
  353.                     /* so we must copy it */
  354.         }
  355.         else {            /* just grow in place, if possible */
  356.         some_buffer_or_other = saferealloc(some_buffer_or_other,
  357.             (MEM_SIZE)buffer_length+1);
  358.         }
  359.     }
  360.     if ((nextch = getc(fp)) == EOF)
  361.         return Nullch;
  362.     some_buffer_or_other[bufix++] = (char) nextch;
  363.     } while (nextch && nextch != '\n');
  364.     some_buffer_or_other[bufix] = '\0';
  365.     len_last_line_got = bufix;
  366.     return some_buffer_or_other;
  367. }
  368.  
  369. /* copy a string to a safe spot */
  370.  
  371. char *
  372. savestr(str)
  373. char *str;
  374. {
  375.     register char *newaddr = safemalloc((MEM_SIZE)(strlen(str)+1));
  376.  
  377.     strcpy(newaddr,str);
  378.     return newaddr;
  379. }
  380.  
  381. int
  382. makedir(dirname,nametype)
  383. register char *dirname;
  384. int nametype;
  385. {
  386. #ifdef MAKEDIR
  387.  
  388.     register char *end;
  389.     register char *s;
  390.     char tmpbuf[1024];
  391.     register char *tbptr = tmpbuf+5;
  392. /*** OS2: we'll need the following variable, to extract
  393.           the directory name out of the tmpbuf-string, which
  394.           includes the "mkdir "-command.                      ***/
  395.     register char *tmpdirname = tmpbuf+6;
  396.     unsigned long create_return = 0;
  397.  
  398.     for (end = dirname; *end; end++) ;    /* find the end */
  399.     if (nametype == MD_FILE) {        /* not to create last component? */
  400.     for (--end; end != dirname && *end != '/'; --end) ;
  401.     if (*end != '/')
  402.         return 0;            /* nothing to make */
  403.     *end = '\0';            /* isolate file name */
  404.     }
  405.     strcpy(tmpbuf,"mkdir");
  406.  
  407.     s = end;
  408.     for (;;) {
  409.     if (stat(dirname,&filestat) >= 0 && (filestat.st_mode & S_IFDIR)) {
  410.                     /* does this much exist as a dir? */
  411.         *s = '/';            /* mark this as existing */
  412.         break;
  413.     }
  414.     s = rindex(dirname,'/');    /* shorten name */
  415.     if (!s)                /* relative path! */
  416.         break;            /* hope they know what they are doing */
  417.     *s = '\0';            /* mark as not existing */
  418.     }
  419.     
  420. /*** OS2: That's a bit of a problem, this routine will try to
  421.           make a string like
  422.           "mkdir c:\usr\news\haen\comp c:\usr\news\haen\comp\os ...."
  423.           and try to make more than one directory at one. But this
  424.           will not work with a API-Call, so we will call the
  425.           DosCreateDir every time, when orignially the sprintf
  426.           would be called.      ***/
  427.  
  428.     for (s=dirname; s <= end; s++) {    /* this is grody but efficient */
  429.     if (!*s) {            /* something to make? */
  430. /*** ok not sprintf, but DosCreateDir ***/
  431. /*        sprintf(tbptr," %s",dirname);     */
  432.         if ((create_return = DosCreateDir(dirname,0)) != 0)
  433.            return create_return;
  434.         tbptr += strlen(tbptr);    /* make it, sort of */
  435.         *s = '/';            /* mark it made */
  436.     }
  437.     }
  438.     if (nametype == MD_DIR)        /* don't need final slash unless */
  439.     *end = '\0';            /*  a filename follows the dir name */
  440.  
  441. /*** OS2: Sorry, but the doshell, which executes a "mkdir filename"
  442.           does not work under OS/2, although we have a mkdir-command.
  443.           So we'll remove "mkdir " out of "tmpbuf" and use
  444.           an OS2-system call. The mkdir and so also the doshell
  445.           returns negative return values on failure, but DosCreateDir
  446.           returns positive values. So we must invert it. ********/
  447.           /** This is now obsolete, see above **/
  448.  
  449. /*    return (tbptr==tmpbuf+5 ? 0 : doshell(sh,tmpbuf));   */
  450. /*    return (tbptr==tmpbuf+5 ? 0 : -DosCreateDir(tmpdirname,0)); */
  451. /*** OS2: if DosCreateDir didn't fail, we can return 0***/
  452.       return 0;
  453.  
  454.                     /* exercise our faith */
  455. #else
  456.     sprintf(cmd_buf,"%s %s %d", filexp(DIRMAKER), dirname, nametype);
  457.     return doshell(sh,cmd_buf);
  458. #endif
  459. }
  460.  
  461. #ifdef SETENV
  462. static bool firstsetenv = TRUE;
  463. extern char **environ;
  464.  
  465. void
  466. setenv(nam,val)
  467. char *nam, *val;
  468. {
  469.     register int i=envix(nam);        /* where does it go? */
  470.  
  471.     if (!environ[i]) {            /* does not exist yet */
  472.     if (firstsetenv) {        /* need we copy environment? */
  473.         int j;
  474. #ifndef lint
  475.         char **tmpenv = (char**)    /* point our wand at memory */
  476.         safemalloc((MEM_SIZE) (i+2) * sizeof(char*));
  477. #else
  478.         char **tmpenv = Null(char **);
  479. #endif /* lint */
  480.     
  481.         firstsetenv = FALSE;
  482.         for (j=0; j<i; j++)        /* copy environment */
  483.         tmpenv[j] = environ[j];
  484.         environ = tmpenv;        /* tell exec where it is now */
  485.     }
  486. #ifndef lint
  487.     else
  488.         environ = (char**) saferealloc((char*) environ,
  489.         (MEM_SIZE) (i+2) * sizeof(char*));
  490.                     /* just expand it a bit */
  491. #endif /* lint */
  492.     environ[i+1] = Nullch;    /* make sure it's null terminated */
  493.     }
  494.     environ[i] = safemalloc((MEM_SIZE) strlen(nam) + strlen(val) + 2);
  495.                     /* this may or may not be in */
  496.                     /* the old environ structure */
  497.     sprintf(environ[i],"%s=%s",nam,val);/* all that work just for this */
  498. }
  499.  
  500. int
  501. envix(nam)
  502. char *nam;
  503. {
  504.     register int i, len = strlen(nam);
  505.  
  506.     for (i = 0; environ[i]; i++) {
  507.     if (strnEQ(environ[i],nam,len) && environ[i][len] == '=')
  508.         break;            /* strnEQ must come first to avoid */
  509.     }                    /* potential SEGV's */
  510.     return i;
  511. }
  512. #endif
  513.  
  514. void
  515. notincl(feature)
  516. char *feature;
  517. {
  518.     printf("\nNo room for feature \"%s\" on this machine.\n",feature) ; FLUSH;
  519. }
  520.  
  521. char *
  522. getval(nam,def)
  523. char *nam,*def;
  524. {
  525.     char *val;
  526.  
  527.     if ((val = getenv(nam)) == Nullch || !*val)
  528.     val = def;
  529.     return val;
  530. }
  531.  
  532. /* grow a static string to at least a certain length */
  533.  
  534. void
  535. growstr(strptr,curlen,newlen)
  536. char **strptr;
  537. int *curlen;
  538. int newlen;
  539. {
  540.     if (newlen > *curlen) {        /* need more room? */
  541.     if (*curlen)
  542.         *strptr = saferealloc(*strptr,(MEM_SIZE)newlen);
  543.     else
  544.         *strptr = safemalloc((MEM_SIZE)newlen);
  545.     *curlen = newlen;
  546.     }
  547. }
  548.  
  549. void
  550. setdef(buffer,dflt)
  551. char *buffer,*dflt;
  552. {
  553. #ifdef STRICTCR
  554.     if (*buffer == ' ')
  555. #else
  556.     if (*buffer == ' ' || *buffer == '\n')
  557. #endif
  558.     {
  559.     if (*dflt == '^' && isupper(dflt[1]))
  560.         *buffer = Ctl(dflt[1]);
  561.     else
  562.         *buffer = *dflt;
  563.     }
  564. }
  565.  
  566. #ifdef SERVER
  567. int nntp_get(buf, len)
  568. char *buf;
  569. int  len;
  570. {
  571.      int n;
  572. #ifdef HAVESIGHOLD
  573.      sighold(SIGINT);
  574. #endif
  575.      n = get_server(buf, len);
  576. #ifdef HAVESIGHOLD
  577.      sigrelse(SIGINT);
  578. #endif
  579.      return n;
  580. }
  581. #endif
  582.  
  583. #if defined(USETHREADS) && !defined(STRFTIME)
  584. /*
  585.  * strftime: print formatted information about a given time.
  586.  * Adapted from the routine by Eric R. Smith, Michal Jaegermann,
  587.  * Arnold Robins, and Paul Close.
  588.  */
  589.  
  590. /* Configuration choices for %x and %X */
  591.  
  592. #undef LOCAL_DDMMYY    /* choose DD/MM/YY instead of MM/DD/YY */
  593. #undef LOCAL_DOTTIME    /* choose HH.MM.SS instead of HH:MM:SS */
  594.  
  595. static char *mth_name[] = {
  596.     "January", "February", "March", "April", "May", "June",
  597.     "July", "August", "September", "October", "November", "December"
  598. };
  599.  
  600. static char *day_name[] = {
  601.     "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
  602.     "Saturday"
  603. };
  604.  
  605. #ifdef TZSET
  606. extern char *tzname[];
  607. #else
  608. # ifndef TM_ZONE
  609. char tznm[16] = "";
  610. # endif
  611. #endif
  612.  
  613. size_t
  614. strftime(str, maxsize, fmt, ts)
  615. char *str;
  616. size_t maxsize;
  617. char *fmt;
  618. struct tm *ts;
  619. {
  620.     size_t num = 0, len;
  621.     char ch;
  622.     char *putstr, *s;
  623.     char tmpbuf[80];
  624.  
  625.     if (maxsize-- <= 0)
  626.     return 0;
  627.  
  628.     for (;;) {
  629.     if (!(ch = *fmt++))
  630.         break;
  631.     if (num == maxsize) {
  632.         num = 0;
  633.         break;
  634.     }
  635.     if (ch != '%') {
  636.         *str++ = ch;
  637.         num++;
  638.         continue;
  639.     }
  640.     /* assume the finished product will be sprintf'ed into tmpbuf */
  641.     putstr = tmpbuf;
  642.  
  643.     switch (ch = *fmt++) {
  644.     case 'A':
  645.     case 'a':
  646.         if (ts->tm_wday < 0 || ts->tm_wday > 6)
  647.         putstr = "?";
  648.         else
  649.         if (ch == 'A')
  650.             putstr = day_name[ts->tm_wday];
  651.         else
  652.             sprintf(tmpbuf, "%-.3s", day_name[ts->tm_wday]);
  653.         break;
  654.     case 'B':
  655.     case 'b':
  656.     case 'h':
  657.         if (ts->tm_mon < 0 || ts->tm_mon > 11)
  658.         putstr = "?";
  659.         else if (ch == 'B')
  660.         putstr = mth_name[ts->tm_mon];
  661.         else
  662.         sprintf(tmpbuf, "%-.3s", mth_name[ts->tm_mon]);
  663.         break;
  664.     case 'C':
  665.         strftime(tmpbuf, sizeof tmpbuf, "%A, %B %e, %Y", ts);
  666.         break;
  667.     case 'c':
  668.         strftime(tmpbuf, sizeof tmpbuf, "%x %X", ts);
  669.         break;
  670.     case 'D':
  671. #ifndef LOCAL_DDMMYY
  672.     case 'x':
  673. #endif
  674.         strftime(tmpbuf, sizeof tmpbuf, "%m/%d/%y", ts);
  675.         break;
  676.     case 'd':
  677.         sprintf(tmpbuf, "%02d", ts->tm_mday);
  678.         break;
  679.     case 'e':    /* day of month, blank padded */
  680.         sprintf(tmpbuf, "%2d", ts->tm_mday);
  681.         break;
  682.     case 'H':
  683.         sprintf(tmpbuf, "%02d", ts->tm_hour);
  684.         break;
  685.     case 'I':
  686.     {
  687.         int n;
  688.  
  689.         n = ts->tm_hour;
  690.         if (n == 0)
  691.         n = 12;
  692.         else if (n > 12)
  693.         n -= 12;
  694.         sprintf(tmpbuf, "%02d", n);
  695.         break;
  696.     }
  697.     case 'j':
  698.         sprintf(tmpbuf, "%03d", ts->tm_yday + 1);
  699.         break;
  700.     case 'm':
  701.         sprintf(tmpbuf, "%02d", ts->tm_mon + 1);
  702.         break;
  703.     case 'M':
  704.         sprintf(tmpbuf, "%02d", ts->tm_min);
  705.         break;
  706.     case 'p':
  707.         putstr = (ts->tm_hour < 12) ? "AM" : "PM";
  708.         break;
  709.     case 'r':
  710.         strftime(tmpbuf, sizeof tmpbuf, "%I:%M:%S %p", ts);
  711.         break;
  712.     case 'R':
  713.         strftime(tmpbuf, sizeof tmpbuf, "%H:%M", ts);
  714.         break;
  715.     case 'S':
  716.         sprintf(tmpbuf, "%02d", ts->tm_sec);
  717.         break;
  718.     case 'T':
  719. #ifndef LOCAL_DOTTIME
  720.     case 'X':
  721. #endif
  722.         strftime(tmpbuf, sizeof tmpbuf, "%H:%M:%S", ts);
  723.         break;
  724.     case 'U':    /* week of year - starting Sunday */
  725.         sprintf(tmpbuf, "%02d", (ts->tm_yday - ts->tm_wday + 10) / 7);
  726.         break;
  727.     case 'W':    /* week of year - starting Monday */
  728.         sprintf(tmpbuf, "%02d", (ts->tm_yday - ((ts->tm_wday + 6) % 7)
  729.             + 10) / 7);
  730.         break;
  731.     case 'w':
  732.         sprintf(tmpbuf, "%d", ts->tm_wday);
  733.         break;
  734.     case 'y':
  735.         sprintf(tmpbuf, "%02d", ts->tm_year % 100);
  736.         break;
  737. #ifdef LOCAL_DOTTIME
  738.     case 'X':
  739.         strftime(tmpbuf, sizeof tmpbuf, "%H.%M.%S", ts);
  740.         break;
  741. #endif
  742. #ifdef LOCAL_DDMMYY
  743.     case 'x':
  744.         strftime(tmpbuf, sizeof tmpbuf, "%d/%m/%y", ts);
  745.         break;
  746. #endif
  747.     case 'Y':
  748.         sprintf(tmpbuf, "%d", ts->tm_year + 1900);
  749.         break;
  750.     case 'Z':
  751. #ifdef TZSET
  752.         sprintf(tmpbuf, "%s", tzname[ts->tm_isdst]);
  753. #else
  754. # ifdef TM_ZONE
  755. /*** OS2: hell wie mer sin...: because timezones are not
  756.           implemented in emx 0.8d, the component tm_zone
  757.           of the "struct tm" in time.h does not exist.
  758.           Hmm,...  let's default to GMT ***/
  759. /*        sprintf(tmpbuf, "%s", ts->tm_zone); */
  760.         sprintf(tmpbuf, "%s", "GMT");
  761. # else
  762.         if (*tznm == '\0') {
  763.         char *timezone();
  764.         struct timeval tv;
  765.         struct timezone tz;
  766.  
  767.         (void) gettimeofday(&tv, &tz);
  768.         strcpy(tznm, timezone(tz.tz_minuteswest, ts->tm_isdst));
  769.         }
  770.         sprintf(tmpbuf, "%s", tznm);
  771. # endif
  772. #endif
  773.         break;
  774.     case '%':
  775.     case '\0':
  776.         putstr = "%";
  777.         break;
  778.     case 'n':    /* same as \n */
  779.         putstr = "\n";
  780.         break;
  781.     case 't':    /* same as \t */
  782.         putstr = "\t";
  783.         break;
  784.     default:
  785.         sprintf(tmpbuf, "%%%c", ch);
  786.         break;
  787.     }
  788.     len = strlen(putstr);
  789.     num += len;
  790.     if (num > maxsize) {
  791.         len -= num - maxsize;
  792.         num = 0;
  793.         ch = '\0';
  794.     }
  795.     strncpy(str, putstr, len);
  796.     str += len;
  797.     if (!ch)
  798.         break;
  799.     }
  800.     *str = '\0';
  801.     return num;
  802. }
  803. #endif /* USETHREADS && no STRFTIME */
  804.