OSDN Git Service

Rearrange header comments.
[hengband/hengband.git] / src / chuukei.c
1 /*!
2     @file chuukei.c
3     @brief Ãæ·Ñµ¡Ç½¤Î¼ÂÁõ
4     @date 2014/01/02
5     @author
6     2014 Deskull rearranged comment for Doxygen.
7  */
8
9 #include "angband.h"
10
11 #include <stdio.h>
12 #include <stdarg.h>
13 #include <ctype.h>
14 #ifdef WINDOWS
15 #include <windows.h>
16 #endif
17
18 #ifdef CHUUKEI
19 #if defined(WINDOWS)
20 #include <winsock.h>
21 #elif defined(MACINTOSH)
22 #include <OpenTransport.h>
23 #include <OpenTptInternet.h>
24 #else
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <netdb.h>
29 #include <sys/time.h>
30 #include <arpa/inet.h>
31
32 #include <setjmp.h>
33 #include <signal.h>
34 #endif
35
36 #define MAX_HOSTNAME 256
37 #endif
38
39 #define RINGBUF_SIZE 1024*1024
40 #define FRESH_QUEUE_SIZE 4096
41 #ifdef WINDOWS
42 #define WAIT 100
43 #else
44 #define WAIT 100*1000 /* ¥Ö¥é¥¦¥ºÂ¦¤Î¥¦¥¨¥¤¥È(usñ°Ì) */
45 #endif
46 #define DEFAULT_DELAY 50
47 #define RECVBUF_SIZE 1024
48
49 static long epoch_time;  /* ¥Ð¥Ã¥Õ¥¡³«»Ï»þ¹ï */
50 static int browse_delay; /* É½¼¨¤¹¤ë¤Þ¤Ç¤Î»þ´Ö(100msñ°Ì)(¤³¤Î´Ö¤Ë¥é¥°¤òµÛ¼ý¤¹¤ë) */
51 #ifdef CHUUKEI
52 static int sd; /* ¥½¥±¥Ã¥È¤Î¥Õ¥¡¥¤¥ë¥Ç¥£¥¹¥¯¥ê¥×¥¿ */
53 static long time_diff;   /* ¥×¥ì¥¤Â¦¤È¤Î»þ´Ö¤Î¤º¤ì(¤³¤ì¤ò¸«¤Ê¤¬¤é¥Ç¥£¥ì¥¤¤òÄ´À°¤·¤Æ¤¤¤¯) */
54 static int server_port;
55 static char server_name[MAX_HOSTNAME];
56 #endif
57
58 static int movie_fd;
59 static int movie_mode;
60
61 #ifdef CHUUKEI
62 #ifdef WINDOWS
63 #define close closesocket
64 #endif
65
66 #ifdef MACINTOSH
67 static InetSvcRef inet_services = nil;
68 static EndpointRef ep                   = kOTInvalidEndpointRef;
69 #endif
70 #endif
71 /* ÉÁ²è¤¹¤ë»þ¹ï¤ò³Ð¤¨¤Æ¤ª¤¯¥­¥å¡¼¹½Â¤ÂΠ*/
72 static struct
73 {
74         int time[FRESH_QUEUE_SIZE];
75         int next;
76         int tail;
77 }fresh_queue;
78
79
80 /* ¥ê¥ó¥°¥Ð¥Ã¥Õ¥¡¹½Â¤ÂΠ*/
81 static struct
82 {
83         char *buf;
84         int wptr;
85         int rptr;
86         int inlen;
87 }ring;
88
89 #ifdef MACINTOSH
90 int recv(int s, char *buffer, size_t buflen, int flags)
91 {
92         OTFlags         junkFlags;
93         int n = OTRcv(ep, (void *) buffer, buflen, &junkFlags);
94         if( n <= 0 )
95                 return n;
96         return n;
97 }
98 #endif
99
100 /*
101  * Original hooks
102  */
103 static errr (*old_xtra_hook)(int n, int v);
104 static errr (*old_curs_hook)(int x, int y);
105 static errr (*old_bigcurs_hook)(int x, int y);
106 static errr (*old_wipe_hook)(int x, int y, int n);
107 static errr (*old_text_hook)(int x, int y, int n, byte a, cptr s);
108
109 static void disable_chuukei_server(void)
110 {
111         term *t = angband_term[0];
112 #ifdef CHUUKEI
113         chuukei_server = FALSE;
114 #endif /* CHUUKEI */
115         t->xtra_hook = old_xtra_hook;
116         t->curs_hook = old_curs_hook;
117         t->bigcurs_hook = old_bigcurs_hook;
118         t->wipe_hook = old_wipe_hook;
119         t->text_hook = old_text_hook;
120 }
121
122 /* ANSI C¤Ë¤è¤ì¤ÐstaticÊÑ¿ô¤Ï0¤Ç½é´ü²½¤µ¤ì¤ë¤¬°ì±þ½é´ü²½¤¹¤ë */
123 static errr init_buffer(void)
124 {
125         fresh_queue.next = fresh_queue.tail = 0;
126         ring.wptr = ring.rptr = ring.inlen = 0;
127         fresh_queue.time[0] = 0;
128         ring.buf = malloc(RINGBUF_SIZE);
129         if (ring.buf == NULL) return (-1);
130
131         return (0);
132 }
133
134 /* ¸½ºß¤Î»þ´Ö¤ò100msñ°Ì¤Ç¼èÆÀ¤¹¤ë */
135 static long get_current_time(void)
136 {
137 #ifdef WINDOWS
138         return timeGetTime() / 100;
139 #elif defined(MACINTOSH)
140         return TickCount();
141 #else
142         struct timeval tv;
143         gettimeofday(&tv, NULL);
144
145         return (tv.tv_sec * 10 + tv.tv_usec / 100000);
146 #endif
147 }
148
149
150 /* ¥ê¥ó¥°¥Ð¥Ã¥Õ¥¡¹½Â¤ÂΤˠbuf ¤ÎÆâÍƤò²Ã¤¨¤ë */
151 static errr insert_ringbuf(char *buf)
152 {
153         int len;
154         len = strlen(buf) + 1; /* +1¤Ï½ªÃ¼Ê¸»úʬ */
155
156         if (movie_mode)
157         {
158                 fd_write(movie_fd, buf, len);
159 #ifdef CHUUKEI
160                 if (!chuukei_server) return 0;
161 #else
162                 return 0;
163 #endif
164         }
165
166         /* ¥Ð¥Ã¥Õ¥¡¤ò¥ª¡¼¥Ð¡¼ */
167         if (ring.inlen + len >= RINGBUF_SIZE)
168         {
169 #ifdef CHUUKEI
170                 if (chuukei_server) disable_chuukei_server();
171                 else chuukei_client = FALSE;
172
173                 prt("Á÷¼õ¿®¥Ð¥Ã¥Õ¥¡¤¬°î¤ì¤Þ¤·¤¿¡£¥µ¡¼¥Ð¤È¤ÎÀܳ¤òÀÚÃǤ·¤Þ¤¹¡£", 0, 0);
174                 inkey();
175
176                 close(sd);
177 #endif
178                 return (-1);
179         }
180
181         /* ¥Ð¥Ã¥Õ¥¡¤Î½ªÃ¼¤Þ¤Ç¤Ë¼ý¤Þ¤ë */
182         if (ring.wptr + len < RINGBUF_SIZE)
183         {
184                 memcpy(ring.buf + ring.wptr, buf, len);
185                 ring.wptr += len;
186         }
187         /* ¥Ð¥Ã¥Õ¥¡¤Î½ªÃ¼¤Þ¤Ç¤Ë¼ý¤Þ¤é¤Ê¤¤(¥Ô¥Ã¥¿¥ê¼ý¤Þ¤ë¾ì¹ç¤â´Þ¤à) */
188         else
189         {
190                 int head = RINGBUF_SIZE - ring.wptr;  /* Á°È¾ */
191                 int tail = len - head;               /* ¸åȾ */
192
193                 memcpy(ring.buf + ring.wptr, buf, head);
194                 memcpy(ring.buf, buf + head, tail);
195                 ring.wptr = tail;
196         }
197
198         ring.inlen += len;
199
200         /* Success */
201         return (0);
202 }
203
204 #ifdef CHUUKEI
205 void flush_ringbuf(void)
206 {
207 #ifndef MACINTOSH
208         fd_set fdset;
209         struct timeval tv;
210
211         if (!chuukei_server) return;
212
213         if (ring.inlen == 0) return;
214
215         tv.tv_sec = 0;
216         tv.tv_usec = 0;
217
218         FD_ZERO(&fdset);
219         FD_SET(sd, &fdset);
220
221         while (1)
222         {
223                 fd_set tmp_fdset;
224                 int result;
225
226                 tmp_fdset = fdset;
227
228                 /* ¥½¥±¥Ã¥È¤Ë¥Ç¡¼¥¿¤ò½ñ¤­¹þ¤á¤ë¤«¤É¤¦¤«Ä´¤Ù¤ë */
229                 select(sd+1, (fd_set *)NULL, &tmp_fdset, (fd_set *)NULL, &tv);
230
231                 /* ½ñ¤­¹þ¤á¤Ê¤±¤ì¤ÐÌá¤ë */
232                 if (FD_ISSET(sd, &tmp_fdset) == 0) break;
233
234                 result = send(sd, ring.buf + ring.rptr, ((ring.wptr > ring.rptr ) ? ring.wptr : RINGBUF_SIZE) - ring.rptr, 0);
235
236                 if (result <= 0)
237                 {
238                         /* ¥µ¡¼¥Ð¤È¤ÎÀܳÃÇ¡© */
239                         if (chuukei_server) disable_chuukei_server();
240
241                         prt("¥µ¡¼¥Ð¤È¤ÎÀܳ¤¬ÀÚÃǤµ¤ì¤Þ¤·¤¿¡£", 0, 0);
242                         inkey();
243                         close(sd);
244
245                         return;
246                 }
247
248                 ring.rptr += result;
249                 ring.inlen -= result;
250
251                 if (ring.rptr == RINGBUF_SIZE) ring.rptr = 0;
252                 if (ring.inlen == 0) break;
253         }
254 #else
255         if (!chuukei_server) return;
256
257         if (ring.inlen == 0) return;
258
259         while (1)
260         {
261                 int result;
262
263                 /* ¥½¥±¥Ã¥È¤Ë¥Ç¡¼¥¿¤ò½ñ¤­¹þ¤á¤ë¤«¤É¤¦¤«Ä´¤Ù¤ë */
264                 result = OTSnd(ep, ring.buf + ring.rptr, ((ring.wptr > ring.rptr ) ? ring.wptr : RINGBUF_SIZE) - ring.rptr, 0);
265
266                 if (result <= 0)
267                 {
268                         /* ¥µ¡¼¥Ð¤È¤ÎÀܳÃÇ¡© */
269                         if (chuukei_server) disable_chuukei_server();
270
271                         prt("¥µ¡¼¥Ð¤È¤ÎÀܳ¤¬ÀÚÃǤµ¤ì¤Þ¤·¤¿¡£", 0, 0);
272                         inkey();
273                         close(sd);
274
275                         return;
276                 }
277
278                 ring.rptr += result;
279                 ring.inlen -= result;
280
281                 if (ring.rptr == RINGBUF_SIZE) ring.rptr = 0;
282                 if (ring.inlen == 0) break;
283         }
284 #endif
285 }
286
287
288 static int read_chuukei_prf(cptr prf_name)
289 {
290         char buf[1024];
291         FILE *fp;
292
293         path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA, prf_name);
294         fp = my_fopen(buf, "r");
295
296         if (!fp) return (-1);
297
298         /* ½é´ü²½ */
299         server_port = -1;
300         server_name[0] = 0;
301         browse_delay = DEFAULT_DELAY;
302
303         while (0 == my_fgets(fp, buf, sizeof(buf)))
304         {
305                 /* ¥µ¡¼¥Ð̾ */
306                 if (!strncmp(buf, "server:", 7))
307                 {
308                         strncpy(server_name, buf + 7, MAX_HOSTNAME - 1);
309                         server_name[MAX_HOSTNAME - 1] = '\0';
310                 }
311
312                 /* ¥Ý¡¼¥ÈÈÖ¹æ */
313                 if (!strncmp(buf, "port:", 5))
314                 {
315                         server_port = atoi(buf + 5);
316                 }
317
318                 /* ¥Ç¥£¥ì¥¤ */
319                 if (!strncmp(buf, "delay:", 6))
320                 {
321                         browse_delay = atoi(buf + 6);
322                 }
323         }
324
325         my_fclose(fp);
326
327         /* prf¥Õ¥¡¥¤¥ë¤¬´°Á´¤Ç¤Ê¤¤ */
328         if (server_port == -1 || server_name[0] == 0) return (-1);
329
330         return (0);
331 }
332
333 int connect_chuukei_server(char *prf_name)
334 {
335 #ifndef MACINTOSH
336
337 #ifdef WINDOWS
338         WSADATA wsaData;
339         WORD wVersionRequested = (WORD) (( 1) |  ( 1 << 8));
340 #endif
341
342         struct sockaddr_in ask;
343         struct hostent *hp;
344
345         if (read_chuukei_prf(prf_name) < 0)
346         {
347                 printf("Wrong prf file\n");
348                 return (-1);
349         }
350
351         if (init_buffer() < 0)
352         {
353                 printf("Malloc error\n");
354                 return (-1);
355         }
356
357 #ifdef WINDOWS
358         if (WSAStartup(wVersionRequested, &wsaData))
359         {
360                 msg_print("Report: WSAStartup failed.");
361                 return (-1);
362         }
363 #endif
364
365         printf("server = %s\nport = %d\n", server_name, server_port);
366
367         if ((hp = gethostbyname(server_name)) != NULL)
368         {
369                 memset(&ask, 0, sizeof(ask));
370                 memcpy(&ask.sin_addr, hp->h_addr_list[0], hp->h_length);
371         }
372         else
373         {
374                 if ((ask.sin_addr.s_addr=inet_addr(server_name)) == 0)
375                 {
376                         printf("Bad hostname\n");
377                         return (-1);
378                 }
379         }
380
381         ask.sin_family = AF_INET;
382         ask.sin_port = htons((unsigned short)server_port);
383
384 #ifndef WINDOWS
385         if ((sd=socket(PF_INET,SOCK_STREAM, 0)) < 0)
386 #else
387         if ((sd=socket(PF_INET,SOCK_STREAM, 0)) == INVALID_SOCKET)
388 #endif
389         {
390                 printf("Can't create socket\n");
391                 return (-1);
392         }
393
394         if (connect(sd, (struct sockaddr *)&ask, sizeof(ask)) < 0)
395         {
396                 close(sd);
397                 printf("Can't connect %s port %d\n", server_name, server_port);
398                 return (-1);
399         }
400
401         return (0);
402 #else   /* MACINTOSH */
403         OSStatus err;
404         InetHostInfo    response;
405         InetHost                host_addr;
406         InetAddress     inAddr;
407         TCall                   sndCall;
408         Boolean                 bind    = false;
409         OSStatus        junk;
410
411         if (read_chuukei_prf(prf_name) < 0){
412                 printf("Wrong prf file\n");
413                 return (-1);
414         }
415         
416         init_buffer();
417         
418         printf("server = %s\nport = %d\n", server_name, server_port);
419
420
421 #if TARGET_API_MAC_CARBON
422         err = InitOpenTransportInContext(kInitOTForApplicationMask, NULL);
423 #else
424         err = InitOpenTransport();
425 #endif
426
427         memset(&response, 0, sizeof(response));
428
429
430 #if TARGET_API_MAC_CARBON
431         inet_services = OTOpenInternetServicesInContext(kDefaultInternetServicesPath, 0, &err, NULL);
432 #else
433         inet_services = OTOpenInternetServices(kDefaultInternetServicesPath, 0, &err);
434 #endif
435         
436         if (err == noErr) {
437                 err = OTInetStringToAddress(inet_services, (char *)server_name, &response);
438                 
439                 if (err == noErr) {
440                         host_addr = response.addrs[0];
441                 } else {
442                         printf("Bad hostname\n");
443                 }
444                 
445 #if TARGET_API_MAC_CARBON
446                 ep = (void *)OTOpenEndpointInContext(OTCreateConfiguration(kTCPName), 0, nil, &err, NULL);
447 #else
448                 ep = (void *)OTOpenEndpoint(OTCreateConfiguration(kTCPName), 0, nil, &err);
449 #endif
450
451                 if (err == noErr) {
452                         err = OTBind(ep, nil, nil);
453                         bind = (err == noErr);
454             }
455             if (err == noErr){
456                 OTInitInetAddress(&inAddr, server_port, host_addr);
457                         
458                         sndCall.addr.len        = sizeof(InetAddress);                          
459                         sndCall.addr.buf        = (unsigned char*) &inAddr;
460                         sndCall.opt.buf         = nil;          /* no connection options */
461                         sndCall.opt.len         = 0;
462                         sndCall.udata.buf       = nil;          /* no connection data */
463                         sndCall.udata.len       = 0;
464                         sndCall.sequence        = 0;            /* ignored by OTConnect */
465                         
466                         err = OTConnect(ep, &sndCall, NULL);
467                         
468                         if( err != noErr ){
469                                 printf("Can't connect %s port %d\n", server_name, server_port);
470                         }
471                 }
472                 
473                 err = OTSetSynchronous(ep);
474                 if (err == noErr)               
475                         err = OTSetBlocking(ep);
476                 
477         }
478         
479         if( err != noErr ){
480                 if( bind ){
481                         OTUnbind(ep);
482                 }
483                 /* Clean up. */
484                 if (ep != kOTInvalidEndpointRef) {
485                         OTCloseProvider(ep);
486                         ep = nil;
487                 }
488                 if (inet_services != nil) {
489                         OTCloseProvider(inet_services);
490                         inet_services = nil;
491                 }
492         
493                 return -1;
494         }
495         
496         return 0;
497
498 #endif
499 }
500 #endif /* CHUUKEI */
501
502 /* str¤¬Æ±¤¸Ê¸»ú¤Î·«¤êÊÖ¤·¤«¤É¤¦¤«Ä´¤Ù¤ë */
503 static bool string_is_repeat(char *str, int len)
504 {
505         char c = str[0];
506         int i;
507
508         if (len < 2) return (FALSE);
509 #ifdef JP
510         if (iskanji(c)) return (FALSE);
511 #endif
512
513         for (i = 1; i < len; i++)
514         {
515 #ifdef JP
516                 if(c != str[i] || iskanji(str[i])) return (FALSE);
517 #else
518                 if(c != str[i]) return (FALSE);
519 #endif
520         }
521
522         return (TRUE);
523 }
524
525 static errr send_text_to_chuukei_server(int x, int y, int len, byte col, cptr str)
526 {
527         char buf[1024];
528         char buf2[1024];
529
530         strncpy(buf2, str, len);
531         buf2[len] = '\0';
532
533         if (len == 1)
534         {
535                 sprintf(buf, "s%c%c%c%c", x+1, y+1, col, buf2[0]);
536         }
537         else if(string_is_repeat(buf2, len))
538         {
539                 int i;
540                 for (i = len; i > 0; i -= 127)
541                 {
542                         sprintf(buf, "n%c%c%c%c%c", x+1, y+1, MIN(i, 127), col, buf2[0]);
543                 }
544         }
545         else
546         {
547 #ifdef SJIS
548                 sjis2euc(buf2);
549 #endif
550                 sprintf(buf, "t%c%c%c%c%s", x+1, y+1, len, col, buf2);
551         }
552
553         insert_ringbuf(buf);
554
555         return (*old_text_hook)(x, y, len, col, str);
556 }
557
558 static errr send_wipe_to_chuukei_server(int x, int y, int len)
559 {
560         char buf[1024];
561
562         sprintf(buf, "w%c%c%c", x+1, y+1, len);
563
564         insert_ringbuf(buf);
565
566         return (*old_wipe_hook)(x, y, len);
567 }
568
569 static errr send_xtra_to_chuukei_server(int n, int v)
570 {
571         char buf[1024];
572
573         if (n == TERM_XTRA_CLEAR || n == TERM_XTRA_FRESH || n == TERM_XTRA_SHAPE)
574         {
575                 sprintf(buf, "x%c", n+1);
576                 
577                 insert_ringbuf(buf);
578                 
579                 if (n == TERM_XTRA_FRESH)
580                 {
581                         sprintf(buf, "d%ld", get_current_time() - epoch_time);
582                         insert_ringbuf(buf);
583                 }
584         }
585
586         /* Verify the hook */
587         if (!old_xtra_hook) return -1;
588
589         return (*old_xtra_hook)(n, v);
590 }
591
592 static errr send_curs_to_chuukei_server(int x, int y)
593 {
594         char buf[1024];
595
596         sprintf(buf, "c%c%c", x+1, y+1);
597
598         insert_ringbuf(buf);
599
600         return (*old_curs_hook)(x, y);
601 }
602
603 static errr send_bigcurs_to_chuukei_server(int x, int y)
604 {
605         char buf[1024];
606
607         sprintf(buf, "C%c%c", x+1, y+1);
608
609         insert_ringbuf(buf);
610
611         return (*old_bigcurs_hook)(x, y);
612 }
613
614
615 /*
616  * Prepare z-term hooks to call send_*_to_chuukei_server()'s
617  */
618 void prepare_chuukei_hooks(void)
619 {
620         term *t0 = angband_term[0];
621
622         /* Save original z-term hooks */
623         old_xtra_hook = t0->xtra_hook;
624         old_curs_hook = t0->curs_hook;
625         old_bigcurs_hook = t0->bigcurs_hook;
626         old_wipe_hook = t0->wipe_hook;
627         old_text_hook = t0->text_hook;
628
629         /* Prepare z-term hooks */
630         t0->xtra_hook = send_xtra_to_chuukei_server;
631         t0->curs_hook = send_curs_to_chuukei_server;
632         t0->bigcurs_hook = send_bigcurs_to_chuukei_server;
633         t0->wipe_hook = send_wipe_to_chuukei_server;
634         t0->text_hook = send_text_to_chuukei_server;
635 }
636
637
638 /*
639  * Prepare z-term hooks to call send_*_to_chuukei_server()'s
640  */
641 void prepare_movie_hooks(void)
642 {
643         char buf[1024];
644         char tmp[80];
645
646         if (movie_mode)
647         {
648                 movie_mode = 0;
649 #ifdef CHUUKEI
650                 if (!chuukei_server) disable_chuukei_server();
651 #else
652                 disable_chuukei_server();
653 #endif
654                 fd_close(movie_fd);
655 #ifdef JP
656                 msg_print("Ï¿²è¤ò½ªÎ»¤·¤Þ¤·¤¿¡£");
657 #else
658                 msg_print("Stopped recording.");
659 #endif
660         }
661         else
662         {
663                 sprintf(tmp, "%s.amv", player_base);
664 #ifdef JP
665                 if (get_string("¥à¡¼¥Ó¡¼µ­Ï¿¥Õ¥¡¥¤¥ë: ", tmp, 80))
666 #else
667                 if (get_string("Movie file name: ", tmp, 80))
668 #endif
669                 {
670                         int fd;
671
672                         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, tmp);
673
674                         fd = fd_open(buf, O_RDONLY);
675
676                         /* Existing file */
677                         if (fd >= 0)
678                         {
679                                 char out_val[160];
680
681                                 /* Close the file */
682                                 (void)fd_close(fd);
683
684                                 /* Build query */
685 #ifdef JP
686                                 (void)sprintf(out_val, "¸½Â¸¤¹¤ë¥Õ¥¡¥¤¥ë¤Ë¾å½ñ¤­¤·¤Þ¤¹¤«? (%s)", buf);
687 #else
688                                 (void)sprintf(out_val, "Replace existing file %s? ", buf);
689 #endif
690
691                                 /* Ask */
692                                 if (!get_check(out_val)) return;
693
694                                 movie_fd = fd_open(buf, O_WRONLY | O_TRUNC);
695                         }
696                         else
697                         {
698                                 movie_fd = fd_make(buf, 0644);
699                         }
700
701                         if (!movie_fd)
702                         {
703 #ifdef JP
704                                 msg_print("¥Õ¥¡¥¤¥ë¤ò³«¤±¤Þ¤»¤ó¡ª");
705 #else
706                                 msg_print("Can not open file.");
707 #endif
708                                 return;
709                         }
710
711                         movie_mode = 1;
712 #ifdef CHUUKEI
713                         if (!chuukei_server) prepare_chuukei_hooks();
714 #else
715                         prepare_chuukei_hooks();
716 #endif
717                         do_cmd_redraw();
718                 }
719         }
720 }
721
722 #ifdef CHUUKEI
723 static int handle_timestamp_data(int timestamp)
724 {
725         long current_time = get_current_time();
726
727         /* ÉÁ²è¥­¥å¡¼¤Ï¶õ¤«¤É¤¦¤«¡© */
728         if (fresh_queue.tail == fresh_queue.next)
729         {
730                 /* ¥Ð¥Ã¥Õ¥¡¥ê¥ó¥°¤·»Ï¤á¤Î»þ´Ö¤òÊݸ¤·¤Æ¤ª¤¯ */
731                 epoch_time = current_time;
732                 epoch_time += browse_delay;
733                 epoch_time -= timestamp;
734                 time_diff = current_time - timestamp;
735         }
736
737         /* ÉÁ²è¥­¥å¡¼¤ËÊݸ¤·¡¢Êݸ°ÌÃÖ¤ò¿Ê¤á¤ë */
738         fresh_queue.time[fresh_queue.tail] = timestamp;
739         fresh_queue.tail ++;
740
741         /* ¥­¥å¡¼¤ÎºÇ¸åÈø¤ËÅþ㤷¤¿¤éÀèƬ¤ËÌ᤹ */
742         fresh_queue.tail %= FRESH_QUEUE_SIZE;
743
744         if (fresh_queue.tail == fresh_queue.next)
745         {
746                 /* ÉÁ²è¥­¥å¡¼°î¤ì */
747                 prt("ÉÁ²è¥¿¥¤¥ß¥ó¥°¥­¥å¡¼¤¬°î¤ì¤Þ¤·¤¿¡£¥µ¡¼¥Ð¤È¤ÎÀܳ¤òÀÚÃǤ·¤Þ¤¹¡£", 0, 0);
748                 inkey();
749                 close(sd);
750
751                 return -1;
752         }
753
754         /* ¥×¥ì¥¤Â¦¤È¤Î¥Ç¥£¥ì¥¤¤òÄ´À° */
755         if (time_diff != current_time - timestamp)
756         {
757                 long old_time_diff = time_diff;
758                 time_diff = current_time - timestamp;
759                 epoch_time -= (old_time_diff - time_diff);
760         }
761
762         /* Success */
763         return 0;
764 }
765 #endif /* CHUUKEI */
766
767 static int handle_movie_timestamp_data(int timestamp)
768 {
769         static int initialized = FALSE;
770
771         /* ÉÁ²è¥­¥å¡¼¤Ï¶õ¤«¤É¤¦¤«¡© */
772         if (!initialized)
773         {
774                 /* ¥Ð¥Ã¥Õ¥¡¥ê¥ó¥°¤·»Ï¤á¤Î»þ´Ö¤òÊݸ¤·¤Æ¤ª¤¯ */
775                 epoch_time = get_current_time();
776                 epoch_time += browse_delay;
777                 epoch_time -= timestamp;
778                 //time_diff = current_time - timestamp;
779                 initialized = TRUE;
780         }
781
782         /* ÉÁ²è¥­¥å¡¼¤ËÊݸ¤·¡¢Êݸ°ÌÃÖ¤ò¿Ê¤á¤ë */
783         fresh_queue.time[fresh_queue.tail] = timestamp;
784         fresh_queue.tail ++;
785
786         /* ¥­¥å¡¼¤ÎºÇ¸åÈø¤ËÅþ㤷¤¿¤éÀèƬ¤ËÌ᤹ */
787         fresh_queue.tail %= FRESH_QUEUE_SIZE;
788
789         /* Success */
790         return 0;
791 }
792
793 #ifdef CHUUKEI
794 static int read_sock(void)
795 {
796         static char recv_buf[RECVBUF_SIZE];
797         static int remain_bytes = 0;
798         int recv_bytes;
799         int i;
800
801         /* Á°²ó»Ä¤Ã¤¿¥Ç¡¼¥¿¤Î¸å¤Ë¤Ä¤Å¤±¤ÆÇÛ¿®¥µ¡¼¥Ð¤«¤é¥Ç¡¼¥¿¼õ¿® */
802         recv_bytes = recv(sd, recv_buf + remain_bytes, RECVBUF_SIZE - remain_bytes, 0);
803
804         if (recv_bytes <= 0)
805                 return -1;
806
807         /* Á°²ó»Ä¤Ã¤¿¥Ç¡¼¥¿Î̤˺£²óÆɤó¤À¥Ç¡¼¥¿Î̤òÄɲà*/
808         remain_bytes += recv_bytes;
809
810         for (i = 0; i < remain_bytes; i ++)
811         {
812                 /* ¥Ç¡¼¥¿¤Î¤¯¤®¤ê('\0')¤òõ¤¹ */
813                 if (recv_buf[i] == '\0')
814                 {
815                         /* 'd'¤Ç»Ï¤Þ¤ë¥Ç¡¼¥¿(¥¿¥¤¥à¥¹¥¿¥ó¥×)¤Î¾ì¹ç¤Ï
816                            ÉÁ²è¥­¥å¡¼¤ËÊݸ¤¹¤ë½èÍý¤ò¸Æ¤Ö */
817                         if ((recv_buf[0] == 'd') &&
818                             (handle_timestamp_data(atoi(recv_buf + 1)) < 0))
819                                 return -1;
820
821                         /* ¼õ¿®¥Ç¡¼¥¿¤òÊݸ */
822                         if (insert_ringbuf(recv_buf) < 0) 
823                                 return -1;
824
825                         /* ¼¡¤Î¥Ç¡¼¥¿°Ü¹Ô¤òrecv_buf¤ÎÀèƬ¤Ë°ÜÆ° */
826                         memmove(recv_buf, recv_buf + i + 1, remain_bytes - i - 1);
827
828                         remain_bytes -= (i+1);
829                         i = 0;
830                 }
831         }
832
833         return 0;
834 }
835 #endif
836
837 static int read_movie_file(void)
838 {
839         static char recv_buf[RECVBUF_SIZE];
840         static int remain_bytes = 0;
841         int recv_bytes;
842         int i;
843
844         recv_bytes = read(movie_fd, recv_buf + remain_bytes, RECVBUF_SIZE - remain_bytes);
845
846         if (recv_bytes <= 0)
847                 return -1;
848
849         /* Á°²ó»Ä¤Ã¤¿¥Ç¡¼¥¿Î̤˺£²óÆɤó¤À¥Ç¡¼¥¿Î̤òÄɲà*/
850         remain_bytes += recv_bytes;
851
852         for (i = 0; i < remain_bytes; i ++)
853         {
854                 /* ¥Ç¡¼¥¿¤Î¤¯¤®¤ê('\0')¤òõ¤¹ */
855                 if (recv_buf[i] == '\0')
856                 {
857                         /* 'd'¤Ç»Ï¤Þ¤ë¥Ç¡¼¥¿(¥¿¥¤¥à¥¹¥¿¥ó¥×)¤Î¾ì¹ç¤Ï
858                            ÉÁ²è¥­¥å¡¼¤ËÊݸ¤¹¤ë½èÍý¤ò¸Æ¤Ö */
859                         if ((recv_buf[0] == 'd') &&
860                             (handle_movie_timestamp_data(atoi(recv_buf + 1)) < 0))
861                                 return -1;
862
863                         /* ¼õ¿®¥Ç¡¼¥¿¤òÊݸ */
864                         if (insert_ringbuf(recv_buf) < 0) 
865                                 return -1;
866
867                         /* ¼¡¤Î¥Ç¡¼¥¿°Ü¹Ô¤òrecv_buf¤ÎÀèƬ¤Ë°ÜÆ° */
868                         memmove(recv_buf, recv_buf + i + 1, remain_bytes - i - 1);
869
870                         remain_bytes -= (i+1);
871                         i = 0;
872                 }
873         }
874
875         return 0;
876 }
877
878
879 #ifndef WINDOWS
880 /* WinÈǤÎÃæÅÀ¤ÈÊɤÎƦÉå¤ò¥Ô¥ê¥ª¥É¤È¥·¥ã¡¼¥×¤Ë¤¹¤ë¡£*/
881 static void win2unix(int col, char *buf)
882 {
883         char kabe;
884         if ( col == 9 ) kabe = '%';
885         else            kabe = '#';
886
887         while (*buf)
888         {
889 #ifdef JP
890                 if (iskanji(*buf))
891                 {
892                         buf += 2;
893                         continue;
894                 }
895 #endif
896                 if (*buf == 127) *buf = kabe;
897                 else if(*buf == 31) *buf = '.';
898                 buf++;
899         }
900 }
901 #endif
902
903 static bool get_nextbuf(char *buf)
904 {
905         char *ptr = buf;
906
907         while (1)
908         {
909                 *ptr = ring.buf[ring.rptr ++];
910                 ring.inlen --;
911                 if (ring.rptr == RINGBUF_SIZE) ring.rptr = 0;
912                 if (*ptr++ == '\0') break;
913         }
914
915         if (buf[0] == 'd') return (FALSE);
916
917         return (TRUE);
918 }
919
920 /* ¥×¥ì¥¤¥Û¥¹¥È¤Î¥Þ¥Ã¥×¤¬Â礭¤¤¤È¤­¥¯¥é¥¤¥¢¥ó¥È¤Î¥Þ¥Ã¥×¤â¥ê¥µ¥¤¥º¤¹¤ë */
921 static void update_term_size(int x, int y, int len)
922 {
923         int ox, oy;
924         int nx, ny;
925         Term_get_size(&ox, &oy);
926         nx = ox;
927         ny = oy;
928
929         /* ²£Êý¸þ¤Î¥Á¥§¥Ã¥¯ */
930         if (x + len > ox) nx = x + len;
931         /* ½ÄÊý¸þ¤Î¥Á¥§¥Ã¥¯ */
932         if (y + 1 > oy) ny = y + 1;
933
934         if (nx != ox || ny != oy) Term_resize(nx, ny);
935 }
936
937 static bool flush_ringbuf_client(void)
938 {
939         char buf[1024];
940
941         /* ½ñ¤¯¥Ç¡¼¥¿¤Ê¤· */
942         if (fresh_queue.next == fresh_queue.tail) return (FALSE);
943
944         /* ¤Þ¤À½ñ¤¯¤Ù¤­»þ¤Ç¤Ê¤¤ */
945         if (fresh_queue.time[fresh_queue.next] > get_current_time() - epoch_time) return (FALSE);
946
947         /* »þ´Ö¾ðÊó(¶èÀÚ¤ê)¤¬ÆÀ¤é¤ì¤ë¤Þ¤Ç½ñ¤¯ */
948         while (get_nextbuf(buf))
949         {
950                 char id;
951                 int x, y, len, col;
952                 int i;
953                 unsigned char tmp1, tmp2, tmp3, tmp4;
954                 char *mesg;
955
956                 sscanf(buf, "%c%c%c%c%c", &id, &tmp1, &tmp2, &tmp3, &tmp4);
957                 x = tmp1-1; y = tmp2-1; len = tmp3; col = tmp4;
958                 if (id == 's')
959                 {
960                         col = tmp3;
961                         mesg = &buf[4];
962                 }
963                 else mesg = &buf[5];
964 #ifndef WINDOWS
965                 win2unix(col, mesg);
966 #endif
967
968                 switch (id)
969                 {
970                 case 't': /* Ä̾ï */
971 #ifdef SJIS
972                         euc2sjis(mesg);
973 #endif
974                         update_term_size(x, y, len);
975                         (void)((*angband_term[0]->text_hook)(x, y, len, (byte)col, mesg));
976                         strncpy(&Term->scr->c[y][x], mesg, len);
977                         for (i = x; i < x+len; i++)
978                         {
979                                 Term->scr->a[y][i] = col;
980                         }
981                         break;
982
983                 case 'n': /* ·«¤êÊÖ¤· */
984                         for (i = 1; i < len; i++)
985                         {
986                                 mesg[i] = mesg[0];
987                         }
988                         mesg[i] = '\0';
989                         update_term_size(x, y, len);
990                         (void)((*angband_term[0]->text_hook)(x, y, len, (byte)col, mesg));
991                         strncpy(&Term->scr->c[y][x], mesg, len);
992                         for (i = x; i < x+len; i++)
993                         {
994                                 Term->scr->a[y][i] = col;
995                         }
996                         break;
997
998                 case 's': /* °ìʸ»ú */
999                         update_term_size(x, y, 1);
1000                         (void)((*angband_term[0]->text_hook)(x, y, 1, (byte)col, mesg));
1001                         strncpy(&Term->scr->c[y][x], mesg, 1);
1002                         Term->scr->a[y][x] = col;
1003                         break;
1004
1005                 case 'w':
1006                         update_term_size(x, y, len);
1007                         (void)((*angband_term[0]->wipe_hook)(x, y, len));
1008                         break;
1009
1010                 case 'x':
1011                         if (x == TERM_XTRA_CLEAR) Term_clear();
1012                         (void)((*angband_term[0]->xtra_hook)(x, 0));
1013                         break;
1014
1015                 case 'c':
1016                         update_term_size(x, y, 1);
1017                         (void)((*angband_term[0]->curs_hook)(x, y));
1018                         break;
1019                 case 'C':
1020                         update_term_size(x, y, 1);
1021                         (void)((*angband_term[0]->bigcurs_hook)(x, y));
1022                         break;
1023                 }
1024         }
1025
1026         fresh_queue.next++;
1027         if (fresh_queue.next == FRESH_QUEUE_SIZE) fresh_queue.next = 0;
1028         return (TRUE);
1029 }
1030
1031 #ifdef CHUUKEI
1032 void browse_chuukei()
1033 {
1034 #ifndef MACINTOSH
1035         fd_set fdset;
1036         struct timeval tv;
1037
1038         tv.tv_sec = 0;
1039         tv.tv_usec = WAIT;
1040
1041         FD_ZERO(&fdset);
1042         FD_SET(sd, &fdset);
1043
1044         Term_clear();
1045         Term_fresh();
1046         Term_xtra(TERM_XTRA_REACT, 0);
1047
1048         while (1)
1049         {
1050                 fd_set tmp_fdset;
1051                 struct timeval tmp_tv;
1052
1053                 if (flush_ringbuf_client()) continue;
1054
1055                 tmp_fdset = fdset;
1056                 tmp_tv = tv;
1057
1058                 /* ¥½¥±¥Ã¥È¤Ë¥Ç¡¼¥¿¤¬Íè¤Æ¤¤¤ë¤«¤É¤¦¤«Ä´¤Ù¤ë */
1059                 select(sd+1, &tmp_fdset, (fd_set *)NULL, (fd_set *)NULL, &tmp_tv);
1060                 if (FD_ISSET(sd, &tmp_fdset) == 0)
1061                 {
1062                         Term_xtra(TERM_XTRA_FLUSH, 0);
1063                         continue;
1064                 }
1065
1066                 if (read_sock() < 0)
1067                 {
1068                         chuukei_client = FALSE;
1069                 }
1070
1071                 /* Àܳ¤¬Àڤ줿¾õÂ֤ǽñ¤¯¤Ù¤­¥Ç¡¼¥¿¤¬¤Ê¤¯¤Ê¤Ã¤Æ¤¤¤¿¤é½ªÎ» */
1072                 if (!chuukei_client && fresh_queue.next == fresh_queue.tail ) break;
1073         }
1074 #else
1075         Term_clear();
1076         Term_fresh();
1077         Term_xtra(TERM_XTRA_REACT, 0);
1078
1079         while (1)
1080         {
1081                 UInt32  unreadData = 0;
1082                 int n;
1083
1084                 if (flush_ringbuf_client()) continue;
1085
1086                 /* ¥½¥±¥Ã¥È¤Ë¥Ç¡¼¥¿¤¬Íè¤Æ¤¤¤ë¤«¤É¤¦¤«Ä´¤Ù¤ë */
1087
1088                 OTCountDataBytes(ep, &unreadData);
1089                 if(unreadData <= 0 ){
1090                         Term_xtra(TERM_XTRA_FLUSH, 0);
1091                         continue;
1092                 }
1093                 if (read_sock() < 0)
1094                 {
1095                         chuukei_client = FALSE;
1096                 }
1097
1098                 /* Àܳ¤¬Àڤ줿¾õÂ֤ǽñ¤¯¤Ù¤­¥Ç¡¼¥¿¤¬¤Ê¤¯¤Ê¤Ã¤Æ¤¤¤¿¤é½ªÎ» */
1099                 if (!chuukei_client && fresh_queue.next == fresh_queue.tail ) break;
1100         }
1101 #endif /*MACINTOSH*/
1102 }
1103 #endif /* CHUUKEI */
1104
1105 void prepare_browse_movie_aux(cptr filename)
1106 {
1107         movie_fd = fd_open(filename, O_RDONLY);
1108         
1109         browsing_movie = TRUE;
1110
1111         init_buffer();
1112 }
1113
1114 void prepare_browse_movie(cptr filename)
1115 {
1116         char buf[1024];
1117         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, filename);
1118
1119         prepare_browse_movie_aux(buf);
1120 }
1121
1122 void browse_movie(void)
1123 {
1124         Term_clear();
1125         Term_fresh();
1126         Term_xtra(TERM_XTRA_REACT, 0);
1127
1128         while (read_movie_file() == 0)
1129         {
1130                 while (fresh_queue.next != fresh_queue.tail)
1131                 {
1132                         if (!flush_ringbuf_client())
1133                         {
1134                                 Term_xtra(TERM_XTRA_FLUSH, 0);
1135
1136                                 /* ¥½¥±¥Ã¥È¤Ë¥Ç¡¼¥¿¤¬Íè¤Æ¤¤¤ë¤«¤É¤¦¤«Ä´¤Ù¤ë */
1137 #ifdef WINDOWS
1138                                 Sleep(WAIT);
1139 #else
1140                                 usleep(WAIT);
1141 #endif
1142                         }
1143                 }
1144         }
1145 }