]> git.pond.sub.org Git - empserver/blob - src/lib/subs/show.c
Remove option FUEL
[empserver] / src / lib / subs / show.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2008, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See files README, COPYING and CREDITS in the root of the source
23  *  tree for related information and legal notices.  It is expected
24  *  that future projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  show.c: General show routines
29  * 
30  *  Known contributors to this file:
31  *     Julian Onions, 1988
32  *     Jeff Bailey, 1990
33  *     Steve McClure, 1996
34  *     Ron Koenderink, 2005
35  *     Markus Armbruster, 2006-2008
36  */
37
38 #include <config.h>
39
40 #if defined(_WIN32)
41 #include <Windows.h>
42 #endif
43
44 #include <math.h>
45 #include "file.h"
46 #include "game.h"
47 #include "item.h"
48 #include "land.h"
49 #include "nat.h"
50 #include "news.h"
51 #include "nuke.h"
52 #include "optlist.h"
53 #include "plane.h"
54 #include "player.h"
55 #include "product.h"
56 #include "prototypes.h"
57 #include "sect.h"
58 #include "server.h"
59 #include "ship.h"
60
61 static char *fmttime2822(time_t);
62
63 struct look_list {
64     union {
65         struct lchrstr *lp;
66         struct plchrstr *pp;
67         struct mchrstr *mp;
68     } l_u;
69     int tech;
70 };
71
72 /*
73  * Change this if there are ever more than 200 ships, plane or land
74  * unit types.
75  */
76 static struct look_list lookup_list[200];
77 static int lookup_list_cnt = 0;
78
79 static void
80 sort_lookup_list(void)
81 {
82     struct natstr *np = getnatp(player->cnum);
83     struct look_list tmp;
84     int i;
85     int j;
86
87     if (!(np->nat_flags & NF_TECHLISTS))
88         return;
89     for (i = 0; i < lookup_list_cnt; i++) {
90         for (j = i; j < lookup_list_cnt; j++) {
91             if (lookup_list[j].tech < lookup_list[i].tech) {
92                 tmp = lookup_list[j];
93                 lookup_list[j] = lookup_list[i];
94                 lookup_list[i] = tmp;
95             }
96         }
97     }
98 }
99
100 static void
101 make_new_list(int tlev, int type)
102 {
103     struct plchrstr *pp;
104     struct lchrstr *lp;
105     struct mchrstr *mp;
106
107     lookup_list_cnt = 0;
108     if (type == EF_PLANE) {
109         for (pp = plchr; pp->pl_name; pp++) {
110             if (pp->pl_tech > tlev)
111                 continue;
112             lookup_list[lookup_list_cnt].l_u.pp = pp;
113             lookup_list[lookup_list_cnt].tech = pp->pl_tech;
114             lookup_list_cnt++;
115         }
116     } else if (type == EF_SHIP) {
117         for (mp = mchr; mp->m_name; mp++) {
118             if (mp->m_tech > tlev)
119                 continue;
120             lookup_list[lookup_list_cnt].l_u.mp = mp;
121             lookup_list[lookup_list_cnt].tech = mp->m_tech;
122             lookup_list_cnt++;
123         }
124     } else if (type == EF_LAND) {
125         for (lp = lchr; lp->l_name; lp++) {
126             if (lp->l_tech > tlev)
127                 continue;
128             lookup_list[lookup_list_cnt].l_u.lp = lp;
129             lookup_list[lookup_list_cnt].tech = lp->l_tech;
130             lookup_list_cnt++;
131         }
132     } else
133         return;
134
135     sort_lookup_list();
136 }
137
138 void
139 show_bridge(int tlev)
140 {
141     if (tlev < buil_bt)
142         return;
143     pr("Bridges require %g tech, %d hcm, 0 workers,\n",
144        buil_bt, buil_bh);
145     pr("%d available workforce, and cost $%g\n",
146        (SCT_BLD_WORK(0, buil_bh) * SCT_MINEFF + 99) / 100,
147        buil_bc);
148 }
149
150 void
151 show_tower(int tlev)
152 {
153     if (tlev < buil_tower_bt)
154         return;
155     pr("Bridge Towers require %g tech, %d hcm, 0 workers,\n",
156        buil_tower_bt, buil_tower_bh);
157     pr("%d available workforce, and cost $%g\n",
158        (SCT_BLD_WORK(0, buil_tower_bh) * SCT_MINEFF + 99) / 100,
159        buil_tower_bc);
160 }
161
162 void
163 show_nuke_stats(int tlev)
164 {
165     show_nuke_capab(tlev);
166 }
167
168 void
169 show_nuke_build(int tlev)
170 {
171     struct nchrstr *np;
172     int avail;
173
174     pr("%13s lcm hcm  oil  rad avail tech res $\n", "");
175
176     for (np = nchr; np->n_name; np++) {
177         avail = NUK_BLD_WORK(np->n_lcm, np->n_hcm, np->n_oil, np->n_rad);
178         if (np->n_tech > tlev)
179             continue;
180         pr("%-13.13s %3d %3d %4d %4d %5d %4d %3.0f $%6d\n",
181            np->n_name, np->n_lcm, np->n_hcm, np->n_oil,
182            np->n_rad, avail, np->n_tech,
183            drnuke_const > MIN_DRNUKE_CONST ?
184                 ceil(np->n_tech * drnuke_const) : 0.0,
185            np->n_cost);
186     }
187 }
188
189 void
190 show_nuke_capab(int tlev)
191 {
192     struct nchrstr *np;
193     int i, j;
194     char *p;
195
196     pr("%13s blst dam lbs tech res $%7s abilities\n", "", "");
197
198     for (np = nchr; np->n_name; np++) {
199         if (np->n_tech > tlev)
200             continue;
201         pr("%-13.13s %4d %3d %3d %4d %3.0f $%7d ",
202            np->n_name, np->n_blast, np->n_dam,
203            np->n_weight, np->n_tech,
204            drnuke_const > MIN_DRNUKE_CONST ?
205                 ceil(np->n_tech * drnuke_const) : 0.0,
206            np->n_cost);
207         for (i = j = 0; i < 32; i++) {
208             if (!(np->n_flags & bit(i)))
209                 continue;
210             if (NULL != (p = symbol_by_value(bit(i), nuke_chr_flags))) {
211                 if (j++ > 0)
212                     pr(" ");
213                 pr("%s", p);
214             }
215         }
216         pr("\n");
217     }
218 }
219
220 void
221 show_ship_build(int tlev)
222 {
223     struct mchrstr *mp;
224     int n;
225
226     pr("%25s lcm hcm avail tech $\n", "");
227     make_new_list(tlev, EF_SHIP);
228     for (n = 0; n < lookup_list_cnt; n++) {
229         mp = (struct mchrstr *)lookup_list[n].l_u.mp;
230         /* Can't show trade ships unless it's turned on */
231         if ((mp->m_flags & M_TRADE) && !opt_TRADESHIPS)
232             continue;
233
234         pr("%-25.25s %3d %3d %5d %4d $%d\n",
235            mp->m_name, mp->m_lcm, mp->m_hcm,
236            SHP_BLD_WORK(mp->m_lcm, mp->m_hcm), mp->m_tech, mp->m_cost);
237     }
238 }
239
240 void
241 show_ship_stats(int tlev)
242 {
243     struct mchrstr *mp;
244     int scount;
245
246     pr("%25s      s  v  s  r  f  l  p  h  x", "");
247     pr("\n");
248
249     pr("%25s      p  i  p  n  i  n  l  e  p", "");
250     pr("\n");
251
252     pr("%25s def  d  s  y  g  r  d  n  l  l", "");
253     pr("\n");
254
255
256     make_new_list(tlev, EF_SHIP);
257     for (scount = 0; scount < lookup_list_cnt; scount++) {
258         mp = (struct mchrstr *)lookup_list[scount].l_u.mp;
259         /* Can't show trade ships unless it's turned on */
260         if ((mp->m_flags & M_TRADE) && !opt_TRADESHIPS)
261             continue;
262
263         pr("%-25.25s %3d %2d %2d %2d %2d %2d ",
264            mp->m_name, m_armor(mp, tlev), m_speed(mp, tlev),
265            m_visib(mp, tlev), mp->m_vrnge,
266            m_frnge(mp, tlev), m_glim(mp, tlev));
267
268         pr("%2d ", mp->m_nland);
269         pr("%2d ", mp->m_nplanes);
270         pr("%2d ", mp->m_nchoppers);
271         pr("%2d ", mp->m_nxlight);
272         pr("\n");
273     }
274 }
275
276 void
277 show_ship_capab(int tlev)
278 {
279     struct mchrstr *mp;
280     i_type i;
281     int j;
282     int scount;
283     int n;
284     char *p;
285
286     pr("%25s cargos & capabilities\n", "");
287
288     make_new_list(tlev, EF_SHIP);
289     for (scount = 0; scount < lookup_list_cnt; scount++) {
290         mp = (struct mchrstr *)lookup_list[scount].l_u.mp;
291         /* Can't show trade ships unless it's turned on */
292         if ((mp->m_flags & M_TRADE) && !opt_TRADESHIPS)
293             continue;
294
295         pr("%-25.25s ", mp->m_name);
296
297         for (i = I_NONE + 1; i <= I_MAX; ++i)
298             if (mp->m_item[i])
299                 pr(" %d%c", mp->m_item[i], ichr[i].i_mnem);
300         pr(" ");
301         for (j = n = 0; j < 32; j++) {
302             if (!(mp->m_flags & bit(j)))
303                 continue;
304             if (NULL != (p = symbol_by_value(bit(j), ship_chr_flags))) {
305                 if (n++ > 0)
306                     pr(" ");
307                 pr("%s", p);
308             }
309         }
310         pr("\n");
311     }
312 }
313
314 void
315 show_plane_stats(int tlev)
316 {
317     struct plchrstr *pp;
318     int pcount;
319
320     pr("%25s acc load att def ran fuel stlth\n", "");
321     make_new_list(tlev, EF_PLANE);
322     for (pcount = 0; pcount < lookup_list_cnt; pcount++) {
323         pp = (struct plchrstr *)lookup_list[pcount].l_u.pp;
324         pr("%-25.25s %3d %4d %3d %3d %3d %4d ",
325            pp->pl_name, pl_acc(pp, tlev), pl_load(pp, tlev),
326            pl_att(pp, tlev), pl_def(pp, tlev), pl_range(pp, tlev),
327            pp->pl_fuel);
328         pr("%4d%% ", pp->pl_stealth);
329         pr("\n");
330     }
331 }
332
333 void
334 show_plane_capab(int tlev)
335 {
336     struct plchrstr *pp;
337     int i;
338     int pcount;
339     int n;
340     char *p;
341
342     pr("%25s capabilities\n", "");
343     make_new_list(tlev, EF_PLANE);
344     for (pcount = 0; pcount < lookup_list_cnt; pcount++) {
345         pp = (struct plchrstr *)lookup_list[pcount].l_u.pp;
346         pr("%-25.25s  ", pp->pl_name);
347
348         for (i = n = 0; i < 32; i++) {
349             if (!(pp->pl_flags & bit(i)))
350                 continue;
351             if (NULL != (p = symbol_by_value(bit(i), plane_chr_flags))) {
352                 if (n++ > 0)
353                     pr(" ");
354                 pr("%s", p);
355             }
356         }
357         pr("\n");
358     }
359 }
360
361 void
362 show_plane_build(int tlev)
363 {
364     struct plchrstr *pp;
365     int pcount;
366
367     pr("%25s lcm hcm crew avail tech $\n", "");
368     make_new_list(tlev, EF_PLANE);
369     for (pcount = 0; pcount < lookup_list_cnt; pcount++) {
370         pp = (struct plchrstr *)lookup_list[pcount].l_u.pp;
371         pr("%-25.25s %3d %3d %4d %5d %4d $%d\n",
372            pp->pl_name, pp->pl_lcm,
373            pp->pl_hcm, pp->pl_crew,
374            PLN_BLD_WORK(pp->pl_lcm, pp->pl_hcm), pp->pl_tech, pp->pl_cost);
375     }
376 }
377
378 void
379 show_land_build(int tlev)
380 {
381     struct lchrstr *lp;
382     int n;
383
384     pr("%25s lcm hcm guns avail tech $\n", "");
385     make_new_list(tlev, EF_LAND);
386     for (n = 0; n < lookup_list_cnt; n++) {
387         lp = (struct lchrstr *)lookup_list[n].l_u.lp;
388         if ((lp->l_flags & L_SPY) && !opt_LANDSPIES)
389             continue;
390         pr("%-25.25s %3d %3d %4d %5d %4d $%d\n",
391            lp->l_name, lp->l_lcm,
392            lp->l_hcm,
393            lp->l_gun,
394            LND_BLD_WORK(lp->l_lcm, lp->l_hcm), lp->l_tech, lp->l_cost);
395     }
396 }
397
398 void
399 show_land_capab(int tlev)
400 {
401     struct lchrstr *lcp;
402     int lcount;
403     i_type i;
404     int j, n;
405     char *p;
406
407     pr("%25s capabilities\n", "");
408
409     make_new_list(tlev, EF_LAND);
410     for (lcount = 0; lcount < lookup_list_cnt; lcount++) {
411         lcp = (struct lchrstr *)lookup_list[lcount].l_u.lp;
412         if ((lcp->l_flags & L_SPY) && !opt_LANDSPIES)
413             continue;
414
415         pr("%-25s ", lcp->l_name);
416
417         for (i = I_NONE + 1; i <= I_MAX; ++i)
418             if (lcp->l_item[i])
419                 pr(" %d%c", lcp->l_item[i], ichr[i].i_mnem);
420         pr(" ");
421         for (j = n = 0; j < 32; j++) {
422             if (!(lcp->l_flags & bit(j)))
423                 continue;
424             if (NULL != (p = symbol_by_value(bit(j), land_chr_flags))) {
425                 if (n++ > 0)
426                     pr(" ");
427                 pr("%s", p);
428             }
429         }
430         pr("\n");
431     }
432 }
433
434 void
435 show_land_stats(int tlev)
436 {
437     struct lchrstr *lcp;
438     int lcount;
439
440     pr("%25s              s  v  s  r  r  a  f  a  a  x  l\n", "");
441     pr("%25s              p  i  p  a  n  c  i  m  a  p  n\n", "");
442     pr("%25s att def vul  d  s  y  d  g  c  r  m  f  l  d\n", "");
443
444     make_new_list(tlev, EF_LAND);
445     for (lcount = 0; lcount < lookup_list_cnt; lcount++) {
446         lcp = (struct lchrstr *)lookup_list[lcount].l_u.lp;
447         if ((lcp->l_flags & L_SPY) && !opt_LANDSPIES)
448             continue;
449
450         pr("%-25s %1.1f %1.1f %3d ",
451            lcp->l_name,
452            l_att(lcp, tlev), l_def(lcp, tlev), l_vul(lcp, tlev));
453         pr("%2d %2d %2d %2d ",
454            l_spd(lcp, tlev), lcp->l_vis, lcp->l_spy, lcp->l_rad);
455         pr("%2d %2d %2d %2d %2d ",
456            l_frg(lcp, tlev), l_acc(lcp, tlev), l_dam(lcp, tlev),
457            lcp->l_ammo, lcp->l_aaf);
458         pr("\n");
459     }
460 }
461
462 void
463 show_sect_build(int foo)
464 {
465     int x, first;
466
467     first = 1;
468     for (x = 0; dchr[x].d_name; x++) {
469         if (dchr[x].d_mnem == 0)
470             continue;
471         if (dchr[x].d_cost < 0)
472             continue;
473         if ((dchr[x].d_cost > 0) || (dchr[x].d_build != 1) ||
474             (dchr[x].d_lcms > 0) || (dchr[x].d_hcms > 0)) {
475             if (first) {
476                 pr("sector type    cost to des    cost for 1%% eff   lcms for 1%%    hcms for 1%%\n");
477                 first = 0;
478             }
479             pr("%-14c %-14d %-17d %-14d %d\n",
480                dchr[x].d_mnem, dchr[x].d_cost, dchr[x].d_build,
481                dchr[x].d_lcms, dchr[x].d_hcms);
482         }
483     }
484
485     first = 1;
486     for (x = 0; intrchr[x].in_name; x++) {
487         if (!intrchr[x].in_enable)
488             continue;
489         if (first)
490             pr("\nInfrastructure building - adding 1 point of efficiency costs:\n"
491                "       type          lcms    hcms    mobility    $$$$\n");
492         pr("%-20s %4d    %4d    %8d    %4d\n",
493            intrchr[x].in_name, intrchr[x].in_lcms, intrchr[x].in_hcms,
494            intrchr[x].in_mcost, intrchr[x].in_dcost);
495         first = 0;
496     }
497 }
498
499 void
500 show_sect_stats(int foo)
501 {
502     int x, first = 1;
503     struct natstr *natp;
504
505     natp = getnatp(player->cnum);
506     for (x = 0; dchr[x].d_name; x++) {
507         if (dchr[x].d_mnem == 0)
508             continue;
509         if (first) {
510             pr("                        mob cost   max   max   --  packing bonus  --   max\n");
511             pr("  sector type            0%% 100%%   off   def   mil  uw civ bar other   pop\n");
512             first = 0;
513         }
514         pr("%c %-21.21s", dchr[x].d_mnem, dchr[x].d_name);
515         if (dchr[x].d_mob0 < 0)
516             pr("  no way ");
517         else
518             pr(" %3.1f  %3.1f", dchr[x].d_mob0, dchr[x].d_mob1);
519         pr("  %5.2f %5.2f   %3d %3d %3d %3d %5d %5d\n",
520            dchr[x].d_ostr, dchr[x].d_dstr,
521            ichr[I_MILIT].i_pkg[dchr[x].d_pkg],
522            ichr[I_UW].i_pkg[dchr[x].d_pkg],
523            ichr[I_CIVIL].i_pkg[dchr[x].d_pkg],
524            ichr[I_BAR].i_pkg[dchr[x].d_pkg],
525            ichr[I_LCM].i_pkg[dchr[x].d_pkg],
526            max_population(natp->nat_level[NAT_RLEV], x, 100));
527     }
528 }
529
530 void
531 show_sect_capab(int foo)
532 {
533     int x, first = 1, i, j;
534     char *tmpstr;
535
536     for (x = 0; dchr[x].d_name; x++) {
537         if (dchr[x].d_mnem == 0 || dchr[x].d_prd < 0)
538             continue;
539         if (first) {
540             pr("                                                 --- level ---          reso \n");
541             pr("  sector type             product use1 use2 use3 level min lag eff%% $$$ dep c\n");
542             first = 0;
543         }
544
545         j = dchr[x].d_prd;
546
547         pr("%c %-23s %-7s ",
548            dchr[x].d_mnem, dchr[x].d_name, pchr[j].p_sname);
549         (void)CANT_HAPPEN(MAXPRCON > 3); /* output has only three columns */
550         for (i = 0; i < 3; i++) {
551             if (i < MAXPRCON
552                 && pchr[j].p_camt[i]
553                 && pchr[j].p_ctype[i] > I_NONE
554                 && pchr[j].p_ctype[i] <= I_MAX) {
555                 pr("%2d %c ", pchr[j].p_camt[i],
556                    ichr[pchr[j].p_ctype[i]].i_name[0]);
557             } else {
558                 pr("     ");
559             }
560         }
561         switch (pchr[j].p_nlndx) {
562         case NAT_TLEV:
563             tmpstr = "tech";
564             break;
565         case NAT_ELEV:
566             tmpstr = "edu";
567             break;
568         case NAT_RLEV:
569             tmpstr = "res";
570             break;
571         case NAT_HLEV:
572             tmpstr = "hap";
573             break;
574         default:
575             tmpstr = " ";
576             break;
577         }
578         pr("%-5s %3d %3d %4d %3d %3d %c",
579            tmpstr,
580            pchr[j].p_nlmin,
581            pchr[j].p_nllag,
582            dchr[x].d_peffic, pchr[j].p_cost, pchr[j].p_nrdep,
583            pchr[j].p_type != I_NONE ? ichr[pchr[j].p_type].i_mnem : ' ');
584
585         pr("\n");
586     }
587 }
588
589 void
590 show_item(int tlev)
591 {
592     struct ichrstr *ip;
593
594     pr("item value sell lbs    packing     melt  item\n");
595     pr("mnem                in rg wh ur bk deno  name\n");
596
597     for (ip = ichr; ip->i_name; ip++) {
598         pr("   %c %5d %4s %3d %2d %2d %2d %2d %2d %4d  %s\n",
599            ip->i_mnem, ip->i_value, ip->i_sell ? "yes" : "no", ip->i_lbs,
600            ip->i_pkg[IPKG], ip->i_pkg[NPKG], ip->i_pkg[WPKG],
601            ip->i_pkg[UPKG], ip->i_pkg[BPKG],
602            ip->i_melt_denom, ip->i_name);
603     }
604 }
605
606 void
607 show_news(int tlev)
608 {
609     int i, j;
610     
611     pr("id category           good will\n");
612     pr("    messsages\n");
613
614     for (i = 1; i < N_MAX_VERB + 1; i++) {
615         if (rpt[i].r_newspage == N_NOTUSED)
616             continue;
617         pr("%-2d %-20.20s %4d\n", rpt[i].r_uid,
618             page_headings[rpt[i].r_newspage].name, rpt[i].r_good_will);
619         for (j = 0; j < NUM_RPTS; j++)
620             pr("    %s\n", rpt[i].r_newstory[j]);
621     }
622 }
623
624 /*
625  * Show update policy and up to N scheduled updates.
626  */
627 void
628 show_updates(int n)
629 {
630     struct gamestr *game = game_tick_tick();
631     int demand = 0;
632     int i;
633
634     pr("%s, Turn %d, ETU %d\n", fmttime2822(time(NULL)),
635        game->game_turn, game->game_tick);
636
637     if (update_time[0]) {
638         if (update_demand == UPD_DEMAND_SCHED) {
639             pr("Demand updates occur according to schedule:\n");
640             demand = 1;
641         } else
642             pr("Updates occur according to schedule:\n");
643         for (i = 0; i < n && update_time[i]; i++)
644             pr("%3d.  %s\n", game->game_turn + i,
645                fmttime2822(update_time[i]));
646         if (update_window) {
647             pr("Updates occur within %d seconds after the scheduled time\n",
648                update_window);
649         }
650     } else
651         pr("There are no updates scheduled.\n");
652
653     if (update_demand == UPD_DEMAND_ASYNC) {
654         pr("Demand updates occur right after the demand is set.\n");
655         if (*update_demandtimes != 0) {
656             pr("Demand updates are allowed during: %s\n",
657                update_demandtimes);
658         }
659         demand = 1;
660     }
661
662     if (demand) {
663         pr("Demand updates require %d country(s) to want one.\n",
664            update_wantmin);
665     }
666
667     if (updates_disabled())
668         pr("\nUPDATES ARE DISABLED!\n");
669 }
670
671 /*
672  * Return T formatted according to RFC 2822.
673  * The return value is statically allocated and overwritten on
674  * subsequent calls.
675  */
676 static char *
677 fmttime2822(time_t t)
678 {
679     static char buf[32];
680 #if defined(_WIN32)
681     size_t n;
682     int nn;
683     TIME_ZONE_INFORMATION tzi;
684     long time_offset;
685     struct tm *time;
686     
687     time = localtime(&t);
688
689     n = strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S", time);
690     if (CANT_HAPPEN(n == 0)) {
691         buf[0] = 0;
692         return buf;
693     }
694     GetTimeZoneInformation(&tzi);
695     time_offset = -(tzi.Bias +
696         (time->tm_isdst ? tzi.DaylightBias : tzi.StandardBias));
697
698     nn = _snprintf(buf + n, sizeof(buf) - n, " %+03d%02d",
699         time_offset/60, abs(time_offset) % 60);
700     if (CANT_HAPPEN(nn <= 0 || nn + n >= sizeof(buf)))
701         buf[0] = 0;
702 #else
703     size_t n = strftime(buf, sizeof(buf), "%a, %d %b %Y %T %z",
704                      localtime(&t));
705     if (CANT_HAPPEN(n == 0))
706         buf[0] = 0;
707 #endif
708     return buf;
709 }