OSDN Git Service

commit local dev ver
[rec10/rec10-git.git] / epgdump / eit.c
1 // -*- tab-width:4 -*-
2 // see TR-B14 4-296 (p.318)
3
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include "eit.h"
9
10 char            *subtitle_cnv_str[] = {
11         NULL
12 };
13 static void timecmp(int *,int *,int *,
14                                         int, int, int);
15 void append_desc(EIT_CONTROL* eittop, int service_id, int event_id, EEVTDitem* eevtitem);
16
17 int parseEIThead(unsigned char *data, EIThead *h) {
18         int boff = 0;
19
20         memset(h, 0, sizeof(EIThead));
21
22         h->table_id = getBit(data, &boff, 8);
23         h->section_syntax_indicator = getBit(data, &boff, 1);
24         h->reserved_future_use = getBit(data, &boff, 1);
25         h->reserved1 = getBit(data, &boff, 2);
26         h->section_length =getBit(data, &boff,12);
27         h->service_id = getBit(data, &boff, 16);
28         h->reserved2 = getBit(data, &boff, 2);
29         h->version_number = getBit(data, &boff, 5);
30         h->current_next_indicator = getBit(data, &boff, 1);
31         h->section_number = getBit(data, &boff, 8);
32         h->last_section_number = getBit(data, &boff, 8);
33         h->transport_stream_id = getBit(data, &boff, 16);
34         h->original_network_id = getBit(data, &boff, 16);
35         h->segment_last_section_number = getBit(data, &boff, 8);
36         h->last_table_id = getBit(data, &boff, 8);
37   
38         return 14;
39 }
40
41 int parseEITbody(unsigned char *data, EITbody *b)
42 {
43         int boff = 0;
44         int tnum;
45         char buf[4];
46
47         memset(b, 0, sizeof(EITbody));
48
49         b->event_id = getBit(data, &boff, 16);
50
51         memcpy(b->start_time, data + boff / 8, 5);
52         /* b->start_time = getBit(data, &boff, 40); */
53         boff += 40;
54         memcpy(b->duration, data + boff / 8, 3);
55         /* b->duration = getBit(data, &boff, 24); */
56         boff += 24;
57         b->running_status = getBit(data, &boff, 3);
58         b->free_CA_mode = getBit(data, &boff, 1);
59         b->descriptors_loop_length = getBit(data, &boff, 12);
60
61         /* 日付変換 */
62         tnum = (b->start_time[0] & 0xFF) << 8 | (b->start_time[1] & 0xFF);
63   
64         b->yy = (tnum - 15078.2) / 365.25;
65         b->mm = ((tnum - 14956.1) - (int)(b->yy * 365.25)) / 30.6001;
66         b->dd = (tnum - 14956) - (int)(b->yy * 365.25) - (int)(b->mm * 30.6001);
67
68         if(b->dd == 0) {
69                 printf("aa");
70         }
71
72         if(b->mm == 14 || b->mm == 15) {
73                 b->yy += 1;
74                 b->mm = b->mm - 1 - (1 * 12);
75         } else {
76                 b->mm = b->mm - 1;
77         }
78
79         b->yy += 1900;
80   
81         memset(buf, '\0', sizeof(buf));
82         sprintf(buf, "%x", b->start_time[2]);
83         b->hh = atoi(buf);
84         memset(buf, '\0', sizeof(buf));
85         sprintf(buf, "%x", b->start_time[3]);
86         b->hm = atoi(buf);
87         memset(buf, '\0', sizeof(buf));
88         sprintf(buf, "%x", b->start_time[4]);
89         b->ss = atoi(buf);
90
91         if((b->duration[0] == 0xFF) && (b->duration[1] == 0xFF) && (b->duration[2] == 0xFF)){
92                 b->dhh = b->dhm = b->dss = 0;
93         }else{
94                 memset(buf, '\0', sizeof(buf));
95                 sprintf(buf, "%x", b->duration[0]);
96                 b->dhh = atoi(buf);
97                 memset(buf, '\0', sizeof(buf));
98                 sprintf(buf, "%x", b->duration[1]);
99                 b->dhm = atoi(buf);
100                 memset(buf, '\0', sizeof(buf));
101                 sprintf(buf, "%x", b->duration[2]);
102                 b->dss = atoi(buf);
103         }
104         return 12;
105 }
106
107 int parseSEVTdesc(unsigned char *data, SEVTdesc *desc) {
108         int boff = 0;
109   
110         memset(desc, 0, sizeof(SEVTdesc));
111
112         desc->descriptor_tag = getBit(data, &boff, 8);
113         if((desc->descriptor_tag & 0xFF) != 0x4D) {
114                 return -1;
115         }
116         desc->descriptor_length = getBit(data, &boff, 8);
117         memcpy(desc->ISO_639_language_code, data + boff / 8, 3);
118         /* desc->ISO_639_language_code = getBit(data, &boff, 24); */
119         boff += 24;
120         desc->event_name_length = getBit(data, &boff, 8);
121         getStr(desc->event_name, data, &boff, desc->event_name_length);
122         desc->text_length = getBit(data, &boff, 8);
123         getStr(desc->text, data, &boff, desc->text_length);
124
125         return desc->descriptor_length + 2;
126 }
127
128 int parseContentDesc(unsigned char *data, ContentDesc *desc) {
129         int boff = 0;
130   
131         memset(desc, 0, sizeof(ContentDesc));
132
133         desc->descriptor_tag = getBit(data, &boff, 8);
134         if((desc->descriptor_tag & 0xFF) != 0x54) {
135                 return -1;
136         }
137         desc->descriptor_length = getBit(data, &boff, 8);
138         memcpy(desc->content, data+(boff/8), desc->descriptor_length);
139         /* getStr(desc->content, data, &boff, desc->descriptor_length); */
140         return desc->descriptor_length + 2;
141 }
142
143 int parseSeriesDesc(unsigned char *data, SeriesDesc *desc) {
144         int boff = 0;
145   
146         memset(desc, 0, sizeof(SeriesDesc));
147
148         desc->descriptor_tag = getBit(data, &boff, 8);
149         if((desc->descriptor_tag & 0xFF) != 0xD5) {
150                 return -1;
151         }
152         desc->descriptor_length = getBit(data, &boff, 8);
153         desc->series_id = getBit(data, &boff, 16);
154         desc->repeat_label = getBit(data, &boff, 4);
155         desc->program_pattern = getBit(data, &boff, 3);
156         desc->expire_date_valid_flag = getBit(data, &boff, 1);
157
158         desc->expire_date = getBit(data, &boff, 16);
159         //memcpy(desc->expire_date, data + boff / 8, 2);
160         //boff += 16;
161
162         desc->episode_number = getBit(data, &boff, 12);
163         desc->last_episode_number = getBit(data, &boff, 12);
164
165         getStr(desc->series_name_char, data, &boff, desc->descriptor_length - 8);
166         return desc->descriptor_length + 2;
167 }
168
169 int parseEEVTDhead(unsigned char *data, EEVTDhead *desc) {
170         int boff = 0;
171   
172         memset(desc, 0, sizeof(EEVTDhead));
173
174         desc->descriptor_tag = getBit(data, &boff, 8);
175         if((desc->descriptor_tag & 0xFF) != 0x4E) {
176                 return -1;
177         }
178         desc->descriptor_length = getBit(data, &boff, 8);
179         desc->descriptor_number = getBit(data, &boff, 4);
180         desc->last_descriptor_number = getBit(data, &boff, 4);
181         memcpy(desc->ISO_639_language_code, data + boff / 8, 3);
182         /* desc->ISO_639_language_code = getBit(data, &boff, 24); */
183         boff += 24;
184
185         desc->length_of_items = getBit(data, &boff, 8);
186
187         return 7;
188 }
189
190 int parseEEVTDitem(unsigned char *data, EEVTDitem *desc) {
191         int boff = 0;
192   
193         memset(desc, 0, sizeof(EEVTDitem));
194
195         desc->item_description_length = getBit(data, &boff, 8);
196         memset(desc->item_description, 0, MAXSECLEN);
197         getStr(desc->item_description, data, &boff, desc->item_description_length);
198
199         desc->item_length = getBit(data, &boff, 8);
200         memset(desc->item, 0, MAXSECLEN);
201         memcpy(desc->item, data + (boff / 8), desc->item_length);
202         /* getStr(desc->item, data, &boff, desc->item_length); */
203
204         return desc->item_description_length + desc->item_length + 2;
205 }
206
207 int parseEEVTDtail(unsigned char *data, EEVTDtail *desc) {
208         int boff = 0;
209   
210         memset(desc, 0, sizeof(EEVTDtail));
211
212         desc->text_length = getBit(data, &boff, 8);
213         memset(desc->text, 0, MAXSECLEN);
214         getStr(desc->text, data, &boff, desc->text_length);
215
216         return desc->text_length + 1;
217 }
218
219 int checkEEVTDitem(EEVTDitem *save, EEVTDitem *new, int descriptor_number) {
220
221         EEVTDitem swap;
222         int boff = 0;
223
224         if(new == NULL) {
225                 if(save->item_length != 0) {
226                         swap = *save;
227                         memset(save->item, 0, MAXSECLEN);
228                         getStr(save->item, (unsigned char*)swap.item, &boff, swap.item_length);
229                         return 1;
230                 } else {
231                         return 0;
232                 }
233         }
234
235         if(new->item_description_length == 0) {
236                 /* 続き 保存 */
237                 memcpy(save->item + save->item_length, new->item, new->item_length);
238                 save->item_length += new->item_length;
239                 return 0;
240         } else {
241                 /* ブレーク。saveを印刷対象にする。saveをクリア? */
242                 if(save->item_length != 0) {
243                         /* 退避済みがあり */
244                         swap = *save;
245                         memset(save->item, 0, MAXSECLEN);
246                         getStr(save->item, (unsigned char*)swap.item, &boff, swap.item_length);
247
248                         // swap save new -> swap save new
249                         //         b   c -> ( c)    c   b
250                         swap = *new;
251                         *new = *save;
252                         *save = swap;
253                         save->descriptor_number = descriptor_number;
254                         return 1;
255                 } else {
256                         *save = *new;
257                         save->descriptor_number = descriptor_number;
258                         return 0;
259                 }
260         }
261 }
262 EIT_CONTROL     *searcheit(EIT_CONTROL *top, int servid, int eventid)
263 {
264         EIT_CONTROL     *cur ;
265         cur = top ;
266
267         while(cur != NULL){
268                 if((cur->event_id == eventid) && (cur->servid == servid)){
269                         return cur ;
270                 }
271
272                 cur = cur->next ;
273         }
274         return NULL ;
275 }
276 char    *strstr_eucjp(const char *str, const char *search)
277 {
278         char *pos ;
279         pos = (char *)str ;
280
281         while (*pos != '\0') {
282                 if (*pos == *search) {
283                         if (strncmp(pos, search, strlen(search)) == 0) {
284                                 return pos ;
285                         }
286                 }
287                 if ((unsigned char)*pos == 0x8Fu) {
288                         pos += 3 ;
289                 } else if ((unsigned char)*pos >= 0x80u) {
290                         pos += 2 ;
291                 } else {
292                         pos += 1 ;
293                 }
294         }
295
296         return NULL ;
297 }
298 void    conv_title_subtitle(EIT_CONTROL *eitptr)
299 {
300         int             lp = 0 ;
301 //      size_t  addsize ;
302         char    *ptr ;
303         char    *ptr2 ;
304         char    *newsubtitle ;
305
306         for(lp = 0 ; subtitle_cnv_str[lp] != NULL ; lp++){
307                 ptr = strstr(eitptr->title, subtitle_cnv_str[lp]);
308                 if(ptr == NULL){
309                         continue ;
310                 }
311                 // タイトルがなくならないように
312                 if(ptr == eitptr->title){
313                         continue ;
314                 }
315                 /*
316                 ptr2 = ptr ;
317                 for( ; (unsigned char)*ptr2 == 0x20u ; ptr2++ );
318                 for( ; (unsigned char)*ptr2 == 0xA1u && (unsigned char)*(ptr2+1) == 0xA1u ; ptr2 += 2);
319                 for( ; (unsigned char)*ptr2 == 0x20u ; ptr2++ );
320                 newsubtitle = calloc(1, ((strlen(ptr2) + 2) + (strlen(eitptr->subtitle) + 1)));
321                 memcpy(newsubtitle, ptr2, strlen(ptr2));
322 //              *(newsubtitle+strlen(ptr)) = ' ';
323                 strcat(newsubtitle, "▽");
324                 */
325                 newsubtitle = calloc(1, ((strlen(ptr) + 1) + (strlen(eitptr->subtitle) + 1)));
326                 memcpy(newsubtitle, ptr, strlen(ptr));
327                 newsubtitle[strlen(ptr)] = ' ';
328
329                 *ptr = '\0';
330                 strcat(newsubtitle, eitptr->subtitle);
331                 free(eitptr->subtitle);
332                 eitptr->subtitle = newsubtitle ;
333                 return ;
334         }
335 }
336 void    enqueue(EIT_CONTROL *top, EIT_CONTROL *eitptr)
337 {
338         EIT_CONTROL     *cur ;
339         cur = top ;
340         int             rc ;
341
342         if(top->next == NULL){
343                 top->next = eitptr ;
344                 eitptr->prev = top ;
345                 return ;
346         }
347         cur = top->next ;
348         while(cur != NULL){
349                 rc = memcmp(&cur->yy, &eitptr->yy, (sizeof(int) * 3));
350                 if(rc == 0){
351                         rc = memcmp(&cur->hh, &eitptr->hh, (sizeof(int) * 3));
352                         if(rc == 0){
353                                 free(eitptr->title);
354                                 free(eitptr->subtitle);
355                                 free(eitptr);
356                                 return ;
357                         }
358                         if(rc > 0){
359                                 if(cur->prev != 0){
360                                         cur->prev->next = eitptr ;
361                                         eitptr->prev = cur->prev ;
362                                 }
363                                 cur->prev = eitptr ;
364                                 eitptr->next = cur ;
365                                 conv_title_subtitle(eitptr);
366                                 return ;
367                         }
368                 }
369                 if(rc > 0){
370                         if(cur->prev != 0){
371                                 cur->prev->next = eitptr ;
372                                 eitptr->prev = cur->prev ;
373                         }
374                         cur->prev = eitptr ;
375                         eitptr->next = cur ;
376                         conv_title_subtitle(eitptr);
377                         return ;
378                 }
379                 if(cur->next == NULL){
380                         cur->next = eitptr ;
381                         eitptr->prev = cur ;
382                         conv_title_subtitle(eitptr);
383                         return ;
384                 }
385                 cur = cur->next ;
386         }
387         return ;
388
389 }
390
391 void dumpEIT(unsigned char *ptr, int serv_id, int original_network_id, int transport_stream_id, EIT_CONTROL *eittop)
392 {
393
394         EIThead  eith;
395         EITbody  eitb;
396         SEVTdesc sevtd;
397
398         EEVTDhead eevthead;
399         EEVTDitem eevtitem;
400         EEVTDtail eevttail;
401
402         EEVTDitem save_eevtitem;
403
404         EIT_CONTROL     *cur ;
405         EIT_CONTROL     *curtmp ;
406
407         int len = 0;
408         int loop_len = 0;
409         int loop_blen = 0;
410         int loop_elen = 0;
411
412         int ehh, emm, ess;
413
414         /* EIT */
415         len = parseEIThead(ptr, &eith); 
416
417         ptr += len;
418         loop_len = eith.section_length - (len - 3 + 4); // 3は共通ヘッダ長 4はCRC
419         while(loop_len > 0) {
420                 /* 連続する拡張イベントは、漢字コードが泣き別れして
421                    分割されるようだ。連続かどうかは、item_description_lengthが
422                    設定されているかどうかで判断できるようだ。 */
423                 memset(&save_eevtitem, 0, sizeof(EEVTDitem));
424
425                 len = parseEITbody(ptr, &eitb);
426                 ptr += len;
427                 loop_len -= len;
428
429                 /* printf("evtid:%d\n", eitb.event_id); */
430
431                 loop_blen = eitb.descriptors_loop_length;
432                 loop_len -= loop_blen;
433
434                 while(loop_blen > 0) {
435
436                         /*yukikaze-test*/
437                         //printf("desc_tag");
438                         //int itt=getBit(*ptr,0,8);
439                         //printf("%x",itt);
440
441                         len = parseSEVTdesc(ptr, &sevtd);
442                         if(len > 0) {
443
444                                 /*
445                                   if(eith.service_id == 19304 && 
446                                   eitb.event_id == 46564) {
447                                   printf("aa");
448                                   }
449                                 */
450
451                                 ehh = eitb.hh;
452                                 emm = eitb.hm;
453                                 ess = eitb.ss;
454                                 if(eith.service_id != serv_id){
455                                         ptr += len;
456                                         loop_blen -= len;
457                                         continue ;
458                                 }
459
460                                 timecmp(&ehh, &emm, &ess,
461                                                 eitb.dhh, eitb.dhm, eitb.dss);
462                                 cur = searcheit(eittop, eith.service_id, eitb.event_id);
463                                 if(cur == NULL){
464                                         curtmp = NULL;
465                                         cur = calloc(1, sizeof(EIT_CONTROL));
466                                 }
467                                 else {
468                                         curtmp = cur;
469                                 }
470                                 cur->event_id = eitb.event_id ;
471                                 cur->servid = eith.service_id ;
472                                 cur->title = calloc(1, (strlen(sevtd.event_name) + 1));
473
474                                 memcpy(cur->title, sevtd.event_name, strlen(sevtd.event_name));
475                                 cur->subtitle = calloc(1, (strlen(sevtd.text) + 1));
476                                 memcpy(cur->subtitle, sevtd.text, strlen(sevtd.text));
477                                 cur->yy = eitb.yy;
478                                 cur->mm = eitb.mm;
479                                 cur->dd = eitb.dd;
480                                 cur->hh = eitb.hh;
481                                 cur->hm = eitb.hm;
482                                 cur->ss = eitb.ss;
483                                 cur->ehh = eitb.dhh;
484                                 cur->emm = eitb.dhm;
485                                 cur->ess = eitb.dss ;
486                                 cur->table_id = eith.table_id ;
487                                 if ( !curtmp ) enqueue(eittop, cur);
488                         } else {
489                                 len = parseEEVTDhead(ptr, &eevthead);
490
491                                 /*
492                                 if(eith.service_id == 19304 && 
493                                 eitb.event_id == 46564) {
494                                 printf("aa");
495                                 }
496                                 */
497
498                                 if(len > 0) {
499                                         ptr += len;
500                                         loop_blen -= len;
501
502                                         loop_elen = eevthead.length_of_items;
503                                         loop_len -= loop_elen;
504                                         while(loop_elen > 0) {
505                                                 len = parseEEVTDitem(ptr, &eevtitem);
506
507                                                 ptr += len;
508                                                 loop_elen -= len;
509                                                 loop_blen -= len;
510
511                                                 if(checkEEVTDitem(&save_eevtitem, &eevtitem, 
512                                                         eevthead.descriptor_number)) {
513
514                                                         {
515                                                                 if (eevtitem.descriptor_number>0){
516                                                                         //printf("descriptor_num %d\n",eevtitem.descriptor_number);
517                                                                 }
518                                                                 /* long format */
519                                                                 //printf("descriptor_num %d\n",eevtitem.descriptor_number);
520 #if 0
521                                                                 printf("EEVT,%d,%d,%d,%s,%s\n",
522                                                                         eith.service_id,
523                                                                         eitb.event_id,
524                                                                         eevtitem.descriptor_number, // 退避項目
525                                                                         eevtitem.item_description,
526                                                                         eevtitem.item);
527 #endif
528                                                         }
529                                                         append_desc(eittop, eith.service_id, eitb.event_id, &eevtitem);
530
531                                                 }
532                                         }
533
534                                         len = parseEEVTDtail(ptr, &eevttail);
535 #if 0
536                                         { /* long format */
537                                                 printf("EEVTt,%d,%d,%d,%s\n", 
538                                                                 eith.service_id,
539                                                                 eitb.event_id,
540                                                                 eevthead.descriptor_number,
541                                                                 eevttail.text);
542                                         }
543 #endif
544                                 } else {
545                                         ContentDesc contentDesc;
546                                         len = parseContentDesc(ptr, &contentDesc);
547                                         if (len > 0) {
548                                                 //int header_printed = 0;
549                                                 for (int i = 0; i < contentDesc.descriptor_length - 1; i+=2) {
550                                                         /*
551                                                         if (0xff == (unsigned char)contentDesc.content[i])
552                                                                 continue;
553                                                         */
554 #if 0
555                                                         if (!header_printed) {
556                                                                 fprintf(out, "Content,%d,%d\n",
557                                                                         eith.service_id,
558                                                                         eitb.event_id);
559                                                                 header_printed = 1;
560                                                         }
561 #endif
562
563                                                         //fprintf(out, ",%02x%02x", (unsigned char)contentDesc.content[i], (unsigned char)contentDesc.content[i+1]);
564
565                                                 }
566                                                 if((eith.original_network_id == original_network_id) && (eith.transport_stream_id == transport_stream_id)){
567                                                         cur = searcheit(eittop, eith.service_id, eitb.event_id);
568                                                         if(cur != NULL){
569                                                                 cur->content_type = (unsigned char)(contentDesc.content[0] >> 4);
570 #if 0
571                                                                 fprintf(stdout, "%s:", cur->title);
572                                                                 fprintf(stdout, ",%02x%02x", (unsigned char)contentDesc.content[0], (unsigned char)contentDesc.content[1]);
573                                                                 fprintf(stdout, ",%02x%02x\n", (unsigned char)contentDesc.content[2], (unsigned char)contentDesc.content[3]);
574 #endif
575                                                         }
576
577 #if 0
578                                                         if (header_printed) {
579                                                                 fprintf(out, "\n");
580                                                         }
581 #endif
582                                                 }
583                                         } else {
584                                                 SeriesDesc seriesDesc;
585                                                 len = parseSeriesDesc(ptr, &seriesDesc);
586                                                 if (len > 0) {
587 #if 0
588                                                         printf("Series,%d,%d,series=%d,repeat=%01x,pattern=%d,expire_valid=%d,expire=%04x,epinum=%d,lastepinum=%d,%s\n",
589                                                                 eith.service_id,
590                                                                 eitb.event_id,
591                                                                 seriesDesc.series_id,
592                                                                 seriesDesc.repeat_label,
593                                                                 seriesDesc.program_pattern,
594                                                                 seriesDesc.expire_date_valid_flag,
595                                                                 seriesDesc.expire_date,
596                                                                 seriesDesc.episode_number,
597                                                                 seriesDesc.last_episode_number,
598                                                                 seriesDesc.series_name_char);
599 #endif
600                                                 } else {
601                                                         len = parseOTHERdesc(ptr);
602                                                 }
603                                         }
604                                 }
605                         }
606                         ptr += len;
607                         loop_blen -= len;
608                 }
609                 /* 最後のブレークチェック */
610
611                 if(checkEEVTDitem(&save_eevtitem, NULL, 0)) {
612 #if 0
613                         { /* long format */
614                                 fprintf(stdout, "EEVT,%d,%d,%d,%s,%s\n", 
615                                                 eith.service_id,
616                                                 eitb.event_id,
617                                                 save_eevtitem.descriptor_number,
618                                                 save_eevtitem.item_description,
619                                                 save_eevtitem.item);
620                         }
621 #endif
622                         append_desc(eittop, eith.service_id, eitb.event_id, &save_eevtitem);
623                 }
624         }
625
626         return;
627 }
628
629 void append_desc(EIT_CONTROL* eittop, int service_id, int event_id, EEVTDitem* eevtitem) {
630         EIT_CONTROL *cur;
631         int str_alen = 0;
632
633         cur = searcheit(eittop, service_id, event_id);
634         if (cur == NULL) {
635                 return;
636         }
637
638         if ( cur->desc ) {
639                 str_alen = strlen( cur->desc );
640         }
641         else {
642                 str_alen = 0;
643         }
644         //eevtitem->item_description_length = strlen(eevtitem->item_description);
645         //eevtitem->item_length = strlen(eevtitem->item);
646         cur->desc = realloc(cur->desc, str_alen + eevtitem->item_description_length + eevtitem->item_length + 1000);
647         if ( !str_alen ) *cur->desc = '\0';
648
649         if ( eevtitem->item_description_length && !strstr(cur->desc, eevtitem->item_description) ) {
650                 strcat(cur->desc + str_alen, eevtitem->item_description);
651                 strcat(cur->desc, "\t");
652         }
653
654         if ( eevtitem->item_length && !strstr(cur->desc, eevtitem->item) ) {
655                 strcat(cur->desc + str_alen, eevtitem->item);
656         //printf("%s\n",eevtitem->item);
657                 strcat(cur->desc, "\\n");
658         }
659 }
660
661 void timecmp(int *thh, int *tmm, int *tss,
662                          int dhh, int dmm, int dss) {
663
664         int ama;
665
666         *tss += dss;
667         ama = *tss % 60;
668         *tmm += (*tss / 60);
669         *tss = ama;
670
671         *tmm += dmm;
672         ama   = *tmm % 60;
673         *thh += (*tmm / 60);
674         *tmm  = ama;
675
676         *thh += dhh;
677
678 }