1 /*
2  * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved.
3  *
4  * This software may be freely used, copied, modified, and distributed
5  * provided that the above copyright notice is preserved in all copies of the
6  * software.
7  */
8 
9 /*
10  * Host C Library support functions.
11  *
12  * $Revision: 1.3 $
13  *     $Date: 2004/12/27 14:00:54 $
14  */
15 
16 #ifdef DEBUG
17 #  include <ctype.h>
18 #endif
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdarg.h>
24 #include <errno.h>
25 #include <time.h>
26 
27 #include "adp.h"
28 #include "host.h"
29 #include "ardi.h"
30 #include "buffers.h"
31 #include "channels.h"        /* Channel interface. */
32 #include "angel_endian.h"
33 #include "logging.h"         /* Angel support functions. */
34 #include "msgbuild.h"
35 #include "sys.h"
36 #include "hsys.h"      /* Function and structure declarations. */
37 #include "hostchan.h"
38 
39 #define FILEHANDLE int
40 
41 /* Note: no statics allowed.  All globals must be malloc()ed on the heap.
42    The state struct is used for this purpose.  See 'hsys.h'.                */
43 /* This is the message handler function passed to the channel manager in
44    HostSysInit.  It is called whenever a message is received. 'buffptr'
45    points to the message body.  Functionality is provided by the debugger
46    toolkit.  The routine is very loosely based on the HandleSWI routine from
47    armos.c in the armulator source.                                         */
48 /* These routines could be tested by providing a simple interface to armsd,
49    and running them in that.   */
50 
51 
52 /* taken staight from armulator source */
53 #ifdef __riscos
54   extern int _fisatty(FILE *);
55 # define isatty_(f) _fisatty(f)
56 # define EMFILE -1
57 # define EBADF -1
_kernel_escape_seen(void)58   int _kernel_escape_seen(void) { return 0 ;}
59 #else
60 # if defined(_WINDOWS) || defined(_CONSOLE)
61 #   define isatty_(f) (f == stdin || f == stdout)
62 # else
63 #   ifdef __ZTC__
64 #     include <io.h>
65 #     define isatty_(f) isatty((f)->_file)
66 #   else
67 #     ifdef macintosh
68 #       include <ioctl.h>
69 #       define isatty_(f) (~ioctl((f)->_file,FIOINTERACTIVE,NULL))
70 #     else
71 #       define isatty_(f) isatty(fileno(f))
72 #     endif
73 #   endif
74 # endif
75 #endif
76 
77 /* Set up the state block, filetable and register the C lib callback fn */
HostSysInit(const struct Dbg_HostosInterface * hostif,char ** cmdline,hsys_state ** stateptr)78 int HostSysInit(const struct Dbg_HostosInterface *hostif, char **cmdline,
79                 hsys_state **stateptr)
80 {
81   ChannelCallback HandleMessageFPtr = (ChannelCallback) HandleSysMessage;
82   int i;
83   *stateptr = (hsys_state *)malloc(sizeof(hsys_state));
84 
85   if (*stateptr == NULL) return RDIError_OutOfStore;
86 
87   (*stateptr)->hostif=hostif;
88   (*stateptr)->last_errno=0;
89   (*stateptr)->OSptr=(OSblock *)malloc(sizeof(OSblock));
90   if ((*stateptr)->OSptr == NULL) return RDIError_OutOfStore;
91   for (i=0; i<UNIQUETEMPS; i++) (*stateptr)->OSptr->TempNames[i]=NULL;
92   for (i=0; i<HSYS_FOPEN_MAX; i++) {
93        (*stateptr)->OSptr->FileTable[i]=NULL;
94        (*stateptr)->OSptr->FileFlags[i]=0;
95   }
96   (*stateptr)->CommandLine=cmdline;
97 
98   return Adp_ChannelRegisterRead(CI_CLIB, (ChannelCallback)HandleMessageFPtr,
99                                  *stateptr);
100 }
101 
102 /* Shut down the Clib support, this will probably never get called though */
HostSysExit(hsys_state * stateptr)103 int HostSysExit(hsys_state *stateptr)
104 {
105   free(stateptr->OSptr);
106   free(stateptr);
107   return RDIError_NoError;
108 }
109 
110 #ifdef DEBUG
DebugCheckNullTermString(char * prefix,bool nl,unsigned int len,unsigned char * strp)111 static void DebugCheckNullTermString(char *prefix, bool nl,
112                                      unsigned int len, unsigned char *strp)
113 {
114     printf("%s: %d: ", prefix, len);
115     if (strp[len]=='\0')
116        printf("\"%s\"", strp);
117     else
118        printf("NOT NULL TERMINATED");
119     if (nl)
120        printf("\n");
121     else
122     {
123         printf(" ");
124         fflush(stdout);
125     }
126 }
127 
128 #ifdef NEED_SYSERRLIST
129 extern int sys_nerr;
130 extern char *sys_errlist[];
131 #endif
132 
DebugStrError(int last_errno)133 static char *DebugStrError(int last_errno)
134 {
135     if (last_errno < sys_nerr)
136        return sys_errlist[last_errno];
137     else
138        return "NO MSG (errno>sys_nerr)";
139 }
140 
DebugCheckErr(char * prefix,bool nl,int err,int last_errno)141 static void DebugCheckErr(char *prefix, bool nl, int err, int last_errno)
142 {
143     printf("\t%s: returned ", prefix);
144     if (err == 0)
145        printf("okay");
146     else
147        printf("%d, errno = %d \"%s\"", err, last_errno,
148               DebugStrError(last_errno));
149     if (nl)
150        printf("\n");
151     else
152     {
153         printf(" ");
154         fflush(stdout);
155     }
156 }
157 
DebugCheckNonNull(char * prefix,bool nl,void * handle,int last_errno)158 static void DebugCheckNonNull(char *prefix, bool nl,
159                               void *handle, int last_errno)
160 {
161     printf("\t%s: returned ", prefix);
162     if (handle != NULL)
163        printf("okay [%08x]", (unsigned int)handle);
164     else
165        printf("NULL, errno = %d \"%s\"", last_errno,
166               DebugStrError(last_errno));
167     if (nl)
168        printf("\n");
169     else
170     {
171         printf(" ");
172         fflush(stdout);
173     }
174 }
175 
176 #define DebugPrintF(c) printf c;
177 
178 #else
179 
180 #define DebugCheckNullTermString(p, n, l, s)    ((void)(0))
181 #define DebugCheckErr(p, n, e, l)               ((void)(0))
182 #define DebugCheckNonNull(p, n, h, l)           ((void)(0))
183 #define DebugPrintF(c)                          ((void)(0))
184 
185 #endif /* ifdef DEBUG ... else */
186 
hsysGetRealFileHandle(hsys_state * stateptr,int fh,char * flags)187 static FILE *hsysGetRealFileHandle(hsys_state *stateptr, int fh, char *flags)
188 {
189     FILE *file_p = NULL;
190 
191     if (fh < 0 || fh >= HSYS_FOPEN_MAX)
192     {
193         stateptr->last_errno = EBADF;
194         DebugPrintF(("\tfh %d out-of-bounds!\n", fh));
195         return NULL;
196     }
197     else
198     {
199         file_p = stateptr->OSptr->FileTable[fh];
200         if (file_p != NULL) {
201             if (flags != NULL)
202                *flags = stateptr->OSptr->FileFlags[fh];
203         }
204         else {
205           stateptr->last_errno = EBADF;
206           DebugPrintF(("\tFileTable[%d] is NULL\n", fh));
207         }
208 
209         return file_p;
210     }
211 }
212 
HandleSysMessage(Packet * packet,hsys_state * stateptr)213 int HandleSysMessage(Packet *packet, hsys_state *stateptr)
214 {
215   unsigned int reason_code, mode, len, c, nbytes, nbtotal, nbtogo = 0;
216   long posn, fl;
217   char character;
218   int err;
219 
220   /* Note: We must not free the buffer passed in as the callback handler */
221   /* expects to do this.  Freeing any other buffers we have malloced */
222   /* ourselves is acceptable */
223 
224   unsigned char *buffp = ((unsigned char *)BUFFERDATA(packet->pk_buffer))+16;
225                                           /* buffp points to the parameters*/
226                                           /* the invidual messages, excluding*/
227                                           /* standard SYS fields (debugID, */
228                                           /* osinfo and reasoncode) */
229   unsigned char *buffhead = (unsigned char *)(packet->pk_buffer);
230 
231   int DebugID, OSInfo1, OSInfo2, count;
232 
233   const char* fmode[] = {"r","rb","r+","r+b",
234                                "w","wb","w+","w+b",
235                                "a","ab","a+","a+b",
236                                "r","r","r","r"} /* last 4 are illegal */ ;
237 
238   FILEHANDLE fh;  /* fh is used as an index to the real file handle
239                          * in OSptr */
240   FILE *fhreal;
241   unpack_message(BUFFERDATA(buffhead), "%w%w%w%w", &reason_code,
242                  &DebugID, &OSInfo1, &OSInfo2);
243                                         /* Extract reason code from buffer. */
244   reason_code &= 0xFFFF;        /* Strip away direction bit, OSInfo and     */
245                                 /* DebugInfo fields.  Will want to do some  */
246                                 /* sort of validation on this later.        */
247 
248   switch(reason_code)
249   {
250 
251   case CL_WriteC:   /* Write a character to the terminal. */
252                     /* byte data -> word status           */
253     {
254 #ifdef DEBUG
255       int c = (int)(*buffp);
256       printf("CL_WriteC: [%02x]>%c<", c, isprint(c) ? c : '.');
257 #endif
258       stateptr->hostif->writec(stateptr->hostif->hostosarg, (int)(*buffp));
259       DevSW_FreePacket(packet);
260       return msgsend(CI_CLIB,"%w%w%w%w%w", CL_WriteC|HtoT,
261                     DebugID, OSInfo1, OSInfo2, NoError);
262     }
263 
264   case CL_Write0:  /* Write a null terminated string to the terminal. */
265     {
266       unpack_message(buffp, "%w", &len);
267       DebugCheckNullTermString("CL_Write0", TRUE, len, buffp+4);
268       stateptr->hostif->write(stateptr->hostif->hostosarg,
269                               (char *) buffp+4, len);
270       DevSW_FreePacket(packet);
271       return msgsend(CI_CLIB, "%w%w%w%w%w", CL_Write0|HtoT, DebugID,
272                     OSInfo1, OSInfo2, NoError);
273     }
274 
275   case CL_ReadC:   /* Read a byte from the terminal */
276     {
277       DebugPrintF(("CL_ReadC: "));
278       DevSW_FreePacket(packet);
279 
280       character = stateptr->hostif->readc(stateptr->hostif->hostosarg);
281       DebugPrintF(("\nCL_ReadC returning [%02x]>%c<\n", character,
282                    isprint(character) ? character : '.'));
283 
284       return msgsend(CI_CLIB, "%w%w%w%w%w%b", CL_ReadC|HtoT,
285                     DebugID, OSInfo1, OSInfo2, NoError, character);
286     }
287 
288   case CL_System:  /* Pass NULL terminated string to the hosts command
289                     * interpreter. As it is nULL terminated we dont need
290                     * the length
291                     */
292     {
293       unpack_message(buffp, "%w", &len);
294       DebugCheckNullTermString("CL_System", TRUE, len, buffp+4);
295 
296       err = system((char *)buffp+4); /* Use the string in the buffer */
297       stateptr->last_errno = errno;
298       DebugCheckErr("system", TRUE, err, stateptr->last_errno);
299 
300       err = msgsend(CI_CLIB, "%w%w%w%w%w%w", CL_System|HtoT,
301                     DebugID, OSInfo1, OSInfo2, NoError, err);
302       DevSW_FreePacket(packet);
303       return err;
304     }
305 
306   case CL_GetCmdLine:  /* Returns the command line used to call the program */
307     {
308       /* Note: we reuse the packet here, this may not always be desirable */
309       /* /* TODO: Use long buffers if possible */
310       DebugPrintF(("CL_GetCmdLine: \"%s\"\n", *(stateptr->CommandLine)));
311 
312       if (buffhead!=NULL) {
313         len = strlen(*(stateptr->CommandLine));
314         if (len > Armsd_BufferSize-24) len = Armsd_BufferSize-24;
315         packet->pk_length = len + msgbuild(BUFFERDATA(buffhead),
316                                            "%w%w%w%w%w%w", CL_GetCmdLine|HtoT,
317                                            DebugID, OSInfo1, OSInfo2,
318                                            NoError, len);
319         strncpy((char *) BUFFERDATA(buffhead)+24,*(stateptr->CommandLine),
320                 len);
321 
322         Adp_ChannelWrite(CI_CLIB, packet);/* Send message. */
323         return 0;
324       }
325       else return -1;
326     }
327 
328   case CL_Clock:   /* Return the number of centiseconds since the support */
329                    /* code started executing */
330     {
331       time_t retTime = time(NULL);
332       if (retTime == (time_t)-1)
333              stateptr->last_errno = errno;
334       else
335              retTime *=100;
336 
337       DebugPrintF(("CL_Clock: %lu\n", retTime));
338       DebugCheckErr("time", TRUE, (retTime == (time_t)-1),
339                     stateptr->last_errno);
340 
341       DevSW_FreePacket(packet);
342       return msgsend(CI_CLIB, "%w%w%w%w%w%w",CL_Clock|HtoT,
343                          DebugID, OSInfo1, OSInfo2, NoError, retTime);
344     }
345 
346   case CL_Time:    /* return time, in seconds since the start of 1970 */
347     {
348       time_t retTime = time(NULL);
349       if (retTime == (time_t)-1)
350               stateptr->last_errno = errno;
351 
352       DebugPrintF(("CL_Time: %lu\n", retTime));
353       DebugCheckErr("time", TRUE, (retTime == (time_t)-1),
354                     stateptr->last_errno);
355 
356       DevSW_FreePacket(packet);
357       return msgsend(CI_CLIB,"%w%w%w%w%w%w",CL_Time|HtoT,
358                          DebugID, OSInfo1, OSInfo2, NoError, retTime);
359     }
360 
361   case CL_Remove:  /* delete named in the null terminated string */
362     {
363       /* Removing an open file will cause problems but once again
364        * its not our problem, likely result is a tangled FileTable */
365       /* As the filename is passed with a null terminator we can use it
366        * straight out of the buffer without copying it.*/
367 
368       unpack_message(buffp, "%w", &len);
369       DebugCheckNullTermString("CL_Remove", TRUE, len, buffp+4);
370 
371       err=remove((char *)buffp+4);
372       stateptr->last_errno = errno;
373       DevSW_FreePacket(packet);
374       DebugCheckErr("remove", TRUE, err, stateptr->last_errno);
375 
376       return msgsend(CI_CLIB, "%w%w%w%w%w", CL_Remove|HtoT,
377                      DebugID, OSInfo1, OSInfo2, err?-1:NoError);
378     }
379 
380   case CL_Rename:  /* rename file */
381     {
382       /* Rename(word nbytes, bytes oname, word nbytes, bytes nname)
383       * return(byte status)
384       */
385       unsigned int len2;
386 
387       unpack_message(buffp, "%w", &len);
388       DebugCheckNullTermString("CL_Rename", FALSE, len, buffp+4);
389       unpack_message(buffp+5+len, "%w", &len2);
390       DebugCheckNullTermString("to", TRUE, len2, buffp+9+len);
391 
392       /* Both names are passed with null terminators so we can use them
393        * directly from the buffer. */
394       err = rename((char *)buffp+4, (char *)buffp+9+len);
395       stateptr->last_errno = errno;
396       DebugCheckErr("rename", TRUE, err, stateptr->last_errno);
397       DevSW_FreePacket(packet);
398 
399       return msgsend(CI_CLIB, "%w%w%w%w%w",  CL_Rename|HtoT,
400                      DebugID, OSInfo1, OSInfo2, (err==0)? NoError : -1);
401     }
402 
403   case CL_Open:    /* open the file */
404     {
405       /* Open(word nbytes, bytes name, byte mode)
406       * return(word handle)
407       */
408       unpack_message(buffp, "%w", &len);
409       /* get the open mode */
410       unpack_message((buffp)+4+len+1, "%w", &mode);
411       DebugCheckNullTermString("CL_Open", FALSE, len, buffp+4);
412       DebugPrintF(("mode: %d\n", mode));
413 
414       /* do some checking on the file first? */
415       /* check if its a tty */
416       if (strcmp((char *)buffp+4, ":tt")==0 && (mode==0||mode==1)) {
417         /* opening tty "r" */
418         fhreal = stdin;
419         stateptr->last_errno = errno;
420         DebugPrintF(("\tstdin "));
421       }
422       else if (strcmp((char *)buffp+4, ":tt")== 0 && (mode==4||mode==5)) {
423         /* opening tty "w" */
424         fhreal = stdout;
425         stateptr->last_errno = errno;
426         DebugPrintF(("\tstdout "));
427       }
428       else
429       {
430         fhreal = fopen((char *)buffp+4, fmode[mode&0xFF]);
431         stateptr->last_errno = errno;
432         DebugCheckNonNull("fopen", FALSE, fhreal, stateptr->last_errno);
433       }
434       DevSW_FreePacket(packet);
435 
436       c = NONHANDLE;
437       if (fhreal != NULL) {
438         /* update filetable */
439         for (c=3; c < HSYS_FOPEN_MAX; c++) {
440           /* allow for stdin, stdout, stderr (!!! WHY? MJG) */
441           if (stateptr->OSptr->FileTable[c] == NULL) {
442             stateptr->OSptr->FileTable[c]= fhreal;
443             stateptr->OSptr->FileFlags[c]= mode & 1;
444             DebugPrintF(("fh: %d\n", c));
445             break;
446           }
447           else if (c == HSYS_FOPEN_MAX) {
448           /* no filehandles free */
449           DebugPrintF(("no free fh: %d\n", c));
450           stateptr->last_errno = EMFILE;
451           }
452         }
453       }
454       else {
455         /*        c = NULL;*/
456         DebugPrintF(("error fh: %d\n", c));
457       }
458       (void) msgsend(CI_CLIB, "%w%w%w%w%w",  CL_Open|HtoT,
459                      DebugID, OSInfo1, OSInfo2, c);
460       return 0;
461     }
462 
463   case CL_Close:   /* close the file pointed to by the filehandle */
464     {
465       unpack_message(buffp, "%w", &fh);
466       DebugPrintF(("CL_Close: fh %d\n", fh));
467       DevSW_FreePacket(packet);
468 
469       fhreal = hsysGetRealFileHandle(stateptr, fh, NULL);
470       if (fhreal == NULL)
471          err = -1;
472       else {
473           if (fhreal == stdin || fhreal == stdout || fhreal == stderr) {
474               stateptr->last_errno = errno;
475               DebugPrintF(("\tskipping close of std*\n"));
476               err = 0;
477           }
478           else {
479               err = fclose(fhreal);
480               if (err == 0)
481                  stateptr->OSptr->FileTable[fh]=NULL;
482               stateptr->last_errno = errno;
483               DebugCheckErr("fclose", TRUE, err, stateptr->last_errno);
484           }
485       }
486       return msgsend(CI_CLIB,"%w%w%w%w%w",  CL_Close|HtoT, DebugID,
487                      OSInfo1, OSInfo2, err);
488     }
489 
490   case CL_Write:
491     {
492         /* Write(word handle, word nbtotal, word nbytes, bytes data)
493          * return(word nbytes)
494          * WriteX(word nbytes, bytes data)
495          * return(word nbytes)
496          */
497       unsigned char *rwdata = NULL, *rwhead = NULL;
498       unsigned char *write_source = NULL;
499       char flags;
500       FILE *fhreal;
501       unsigned int ack_reason = CL_Write; /* first ack is for CL_Write */
502 
503       err = -1;                 /* err == 0 is fwrite() error indication */
504       unpack_message(buffp, "%w%w%w", &fh, &nbtotal, &nbytes);
505       DebugPrintF(("CL_Write: fh %d nbtotal %u nbytes %u\n",
506                    fh, nbtotal, nbytes));
507 
508       fhreal = hsysGetRealFileHandle(stateptr, fh, &flags);
509       nbtogo = nbtotal;
510 
511       /* deal with the file handle */
512       if (fhreal == NULL)
513          err = 0;
514       else {
515         if (flags & READOP)
516            fseek(fhreal,0,SEEK_CUR);
517         stateptr->OSptr->FileFlags[fh] = (flags & BINARY) | WRITEOP;
518 
519         nbtogo -= nbytes;
520 
521         if (nbtogo > 0) {
522           write_source = rwdata = rwhead = (unsigned char *)malloc(nbtotal);
523           if (rwhead == NULL) {
524             fprintf(stderr, "OUT OF MEMORY at line %d in %s\n",
525                     __LINE__, __FILE__);
526             return -1;
527           }
528           memcpy(rwdata, buffp+12, nbytes);
529           rwdata += nbytes;
530         }
531         else
532            write_source = buffp+12;
533       }
534 
535       do {
536         /* at least once!! */
537 
538         if (nbtogo == 0 && err != 0) {
539           /* Do the actual write! */
540           if (fhreal == stdout || fhreal == stderr) {
541             stateptr->hostif->write(stateptr->hostif->hostosarg,
542                                     (char *)write_source, nbtotal);
543           }
544           else
545              err = fwrite(write_source, 1, nbtotal, fhreal);
546           stateptr->last_errno = errno;
547           DebugCheckErr("fwrite", TRUE, (err == 0), stateptr->last_errno);
548         }
549 
550         DevSW_FreePacket(packet);
551         if (msgsend(CI_CLIB,"%w%w%w%w%w%w", ack_reason|HtoT,
552                     DebugID, OSInfo1, OSInfo2, (err == 0), nbtogo))
553         {
554             fprintf(stderr, "COULD NOT REPLY at line %d in %s\n",
555                     __LINE__, __FILE__);
556             if (rwhead != NULL)
557                free(rwhead);
558             return -1;
559         }
560 
561         if (nbtogo == 0 || err == 0) {
562           DebugPrintF(("\twrite complete - returning\n"));
563           if (rwhead != NULL)
564              free(rwhead);
565           return 0;
566         }
567         else {
568           /* await extension */
569           ack_reason = CL_WriteX;
570 
571           packet = DevSW_AllocatePacket(Armsd_BufferSize);
572           if (packet == NULL)
573           {
574             fprintf(stderr, "COULD NOT ALLOC PACKET at line %d in %s\n",
575                     __LINE__, __FILE__);
576             if (rwhead != NULL)
577                free(rwhead);
578             return -1;
579           }
580           Adp_ChannelRegisterRead(CI_CLIB, NULL, NULL);
581           Adp_ChannelRead(CI_CLIB, &packet);
582           Adp_ChannelRegisterRead(CI_CLIB,
583                                   (ChannelCallback)HandleSysMessage,
584                                   stateptr);
585 
586           buffhead = packet->pk_buffer;
587           unpack_message(BUFFERDATA(buffhead), "%w%w%w%w%w", &reason_code,
588                          &DebugID, &OSInfo1, &OSInfo2, &nbytes);
589           if (reason_code != (CL_WriteX|TtoH)) {
590             DevSW_FreePacket(packet);
591             free(rwhead);
592             fprintf(stderr, "EXPECTING CL_WriteX GOT %u at line %d in %s\n",
593                     reason_code, __LINE__, __FILE__);
594             return -1;
595           }
596 
597           DebugPrintF(("CL_WriteX: nbytes %u\n", nbytes));
598           memcpy(rwdata, BUFFERDATA(buffhead)+20, nbytes);
599           rwdata += nbytes;
600           nbtogo -= nbytes;
601         }
602 
603       } while (TRUE);           /* will return when done */
604     }
605 
606   case CL_WriteX:     /*
607                        * NOTE: if we've got here something has gone wrong
608                        * CL_WriteX's should all be picked up within the
609                        * CL_Write loop, probably best to return an error here
610                        * do this for the moment just so we do actually return
611                        */
612     fprintf(stderr, "ERROR: unexpected CL_WriteX message received\n");
613     return -1;
614 
615   case CL_Read:
616     {
617                    /* Read(word handle, word nbtotal)
618                     * return(word nbytes, word nbmore, bytes data)
619                     */
620                    /* ReadX()
621                     * return(word nbytes, word nbmore, bytes data) */
622       unsigned char *rwdata, *rwhead;
623       int gotlen;
624       unsigned int max_data_in_buffer=Armsd_BufferSize-28;
625       char flags;
626       FILE *fhreal;
627       unsigned int nbleft = 0, reason = CL_Read;
628 
629       err = NoError;
630 
631       unpack_message(buffp, "%w%w", &fh, &nbtotal);
632       DebugPrintF(("CL_Read: fh %d, nbtotal %d: ", fh, nbtotal));
633 
634       rwdata = rwhead = (unsigned char *)malloc(nbtotal);
635       if (rwdata == NULL) {
636         fprintf(stderr, "OUT OF MEMORY at line %d in %s\n",
637                 __LINE__, __FILE__);
638         DevSW_FreePacket(packet);
639         return -1;
640       }
641 
642       /* perform the actual read */
643       fhreal = hsysGetRealFileHandle(stateptr, fh, &flags);
644       if (fhreal == NULL)
645       {
646         /* bad file handle */
647         err = -1;
648         nbytes = 0;
649         gotlen = 0;
650       }
651       else
652       {
653         if (flags & WRITEOP)
654           fseek(fhreal,0,SEEK_CUR);
655         stateptr->OSptr->FileFlags[fh] = (flags & BINARY) | WRITEOP;
656         if (isatty_(fhreal)) {
657           /* reading from a tty, so do some nasty stuff, reading into rwdata */
658           if (angel_hostif->gets(stateptr->hostif->hostosarg, (char *)rwdata,
659                                  nbtotal) != 0)
660              gotlen = strlen((char *)rwdata);
661           else
662              gotlen = 0;
663           stateptr->last_errno = errno;
664           DebugPrintF(("ttyread %d\n", gotlen));
665         }
666         else {
667           /* not a tty, reading from a real file */
668           gotlen = fread(rwdata, 1, nbtotal, fhreal);
669           stateptr->last_errno = errno;
670           DebugCheckErr("fread", FALSE, (gotlen == 0), stateptr->last_errno);
671           DebugPrintF(("(%d)\n", gotlen));
672         }
673       }
674 
675       nbtogo = gotlen;
676 
677       do {
678         /* at least once */
679 
680         if ((unsigned int) nbtogo <= max_data_in_buffer)
681            nbytes = nbtogo;
682         else
683            nbytes = max_data_in_buffer;
684         nbtogo -= nbytes;
685 
686         /* last ReadX needs subtle adjustment to returned nbtogo */
687         if (nbtogo == 0 && err == NoError && reason == CL_ReadX)
688            nbleft = nbtotal - gotlen;
689         else
690            nbleft = nbtogo;
691 
692         count = msgbuild(BUFFERDATA(buffhead), "%w%w%w%w%w%w%w",
693                          reason|HtoT, 0, ADP_HandleUnknown,
694                          ADP_HandleUnknown, err, nbytes, nbleft);
695 
696         if (err == NoError) {
697           /* copy data into buffptr */
698           memcpy(BUFFERDATA(buffhead)+28, rwdata, nbytes);
699           rwdata += nbytes;
700           count += nbytes;
701         }
702 
703         DebugPrintF(("\treplying err %d, nbytes %d, nbtogo %d\n",
704                      err, nbytes, nbtogo));
705 
706         packet->pk_length = count;
707         Adp_ChannelWrite(CI_CLIB, packet);
708 
709         if (nbtogo == 0 || err != NoError) {
710           /* done */
711           free(rwhead);
712           return 0;
713         }
714         else {
715           /* await extension */
716           reason = CL_ReadX;
717 
718           packet = DevSW_AllocatePacket(Armsd_BufferSize);
719           if (packet == NULL) {
720             fprintf(stderr, "COULD NOT ALLOC PACKET at line %d in %s\n",
721                     __LINE__, __FILE__);
722             free(rwhead);
723             return -1;
724           }
725           Adp_ChannelRegisterRead(CI_CLIB, NULL, NULL);
726           Adp_ChannelRead(CI_CLIB, &packet);
727           Adp_ChannelRegisterRead(CI_CLIB,
728                                   (ChannelCallback)HandleSysMessage,
729                                   stateptr);
730           buffhead = packet->pk_buffer;
731           unpack_message(BUFFERDATA(buffhead),"%w", &reason_code);
732           if (reason_code != (CL_ReadX|TtoH)) {
733             fprintf(stderr, "EXPECTING CL_ReadX GOT %u at line %d in %s\n",
734                     reason_code, __LINE__, __FILE__);
735             DevSW_FreePacket(packet);
736             free(rwdata);
737             return -1;
738           }
739         }
740 
741       } while (TRUE);           /* will return above on error or when done */
742     }
743 
744   case CL_ReadX:      /* If we're here something has probably gone wrong */
745     fprintf(stderr, "ERROR: Got unexpected CL_ReadX message\n");
746     return -1;
747 
748   case CL_Seek:
749     {
750       unpack_message(buffp, "%w%w", &fh, &posn);
751       DebugPrintF(("CL_Seek: fh %d, posn %ld\n", fh, posn));
752       DevSW_FreePacket(packet);
753 
754       fhreal = hsysGetRealFileHandle(stateptr, fh, NULL);
755       if (fhreal == NULL)
756          err = -1;
757       else {
758         err = fseek(fhreal, posn, SEEK_SET);
759         stateptr->last_errno = errno;
760         DebugCheckErr("fseek", TRUE, err, stateptr->last_errno);
761       }
762 
763       return msgsend(CI_CLIB, "%w%w%w%w%w", CL_Seek|HtoT,
764                          DebugID, OSInfo1, OSInfo2, err);
765     }
766 
767   case CL_Flen:
768     {
769       unpack_message(buffp, "%w", &fh);
770       DebugPrintF(("CL_Flen: fh %d ", fh));
771       DevSW_FreePacket(packet);
772 
773       fhreal = hsysGetRealFileHandle(stateptr, fh, NULL);
774       if (fhreal == NULL)
775         fl = -1;
776       else {
777         posn = ftell(fhreal);
778         if (fseek(fhreal, 0L, SEEK_END) < 0) {
779           fl=-1;
780         }
781         else {
782           fl = ftell(fhreal);
783           fseek(fhreal, posn, SEEK_SET);
784         }
785         stateptr->last_errno = errno;
786       }
787       DebugPrintF(("returning len %ld\n", fl));
788       return msgsend(CI_CLIB, "%w%w%w%w%w", CL_Flen|HtoT, DebugID, OSInfo1,
789                      OSInfo2, fl);
790     }
791 
792   case CL_IsTTY:
793     {
794       int  ttyOrNot;
795       unpack_message(buffp, "%w", &fh);
796       DebugPrintF(("CL_IsTTY: fh %d ", fh));
797       DevSW_FreePacket(packet);
798 
799       fhreal = hsysGetRealFileHandle(stateptr, fh, NULL);
800       if (fhreal == NULL)
801          ttyOrNot = FALSE;
802       else {
803         ttyOrNot = isatty_(fhreal);
804         stateptr->last_errno = errno;
805       }
806       DebugPrintF(("returning %s\n", ttyOrNot ? "tty (1)" : "not (0)"));
807 
808       return msgsend(CI_CLIB, "%w%w%w%w%w",CL_IsTTY|HtoT,
809                          DebugID, OSInfo1, OSInfo2, ttyOrNot);
810     }
811 
812   case CL_TmpNam:
813     {
814       char *name;
815       unsigned int tnamelen, TargetID;
816       unpack_message(buffp, "%w%w", &tnamelen, &TargetID);
817       DebugPrintF(("CL_TmpNam: tnamelen %d TargetID %d: ",
818                    tnamelen, TargetID));
819       DevSW_FreePacket(packet);
820 
821       TargetID = TargetID & 0xFF;
822       if (stateptr->OSptr->TempNames[TargetID] == NULL) {
823         if ((stateptr->OSptr->TempNames[TargetID] =
824              (char *)malloc(L_tmpnam)) == NULL)
825         {
826           fprintf(stderr, "OUT OF MEMORY at line %d in %s\n",
827                   __LINE__, __FILE__);
828           return -1;
829         }
830         tmpnam(stateptr->OSptr->TempNames[TargetID]);
831       }
832       name = stateptr->OSptr->TempNames[TargetID];
833       len = strlen(name) + 1;
834       packet = DevSW_AllocatePacket(Armsd_BufferSize);
835       if (packet == NULL)
836       {
837           fprintf(stderr, "COULD NOT ALLOC PACKET at line %d in %s\n",
838                   __LINE__, __FILE__);
839           return -1;
840       }
841       buffhead = packet->pk_buffer;
842       if (len > tnamelen) {
843         DebugPrintF(("TMPNAME TOO LONG!\n"));
844         count = msgbuild(BUFFERDATA(buffhead), "%w%w%w%w%w",
845                            CL_TmpNam|HtoT, DebugID, OSInfo1, OSInfo2, -1);
846       }
847       else {
848         DebugPrintF(("returning \"%s\"\n", name));
849         count = msgbuild(BUFFERDATA(buffhead), "%w%w%w%w%w%w", CL_TmpNam|HtoT,
850                          DebugID, OSInfo1, OSInfo2, 0, len);
851         strcpy((char *)BUFFERDATA(buffhead)+count, name);
852         count +=len+1;
853       }
854       packet->pk_length = count;
855       Adp_ChannelWrite(CI_CLIB, packet);/* Send message. */
856       return 0;
857     }
858 
859   case CL_Unrecognised:
860     DebugPrintF(("CL_Unrecognised!!\n"));
861     return 0;
862 
863   default:
864     fprintf(stderr, "UNRECOGNISED CL code %08x\n", reason_code);
865     break;
866 /* Need some sort of error handling here. */
867 /* A call to CL_Unrecognised should suffice */
868   }
869   return -1;  /* Stop a potential compiler warning */
870 }
871 
872 #ifdef COMPILING_ON_WINDOWS
873 
874 #include <windows.h>
875 
876 extern HWND hwndParent;
877 
panic(const char * format,...)878 void panic(const char *format, ...)
879 {
880     char buf[2048];
881     va_list args;
882 
883     Adp_CloseDevice();
884 
885     va_start(args, format);
886     vsprintf(buf, format, args);
887 
888     MessageBox(hwndParent, (LPCTSTR)buf, (LPCTSTR)"Fatal Error:", MB_OK);
889 
890     /* SJ - Not the proper way to shutdown the app */
891     exit(EXIT_FAILURE);
892 
893 /*
894     if (hwndParent != NULL)
895         SendMessage(hwndParent, WM_QUIT, 0, 0);
896 */
897 
898     va_end(args);
899 }
900 
901 #else
902 
panic(const char * format,...)903 void panic(const char *format, ...)
904 {
905     va_list args;
906 
907     va_start(args, format);
908     fprintf(stderr, "Fatal error: ");
909     vfprintf(stderr, format, args);
910     fprintf(stderr,"\n");
911 
912     exit(EXIT_FAILURE);
913 }
914 
915 #endif
916 
917 /* EOF hsys.c */
918