OSDN Git Service

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