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
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 */
78int 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 */
103int HostSysExit(hsys_state *stateptr)
104{
105  free(stateptr->OSptr);
106  free(stateptr);
107  return RDIError_NoError;
108}
109
110#ifdef DEBUG
111static 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
129extern int sys_nerr;
130extern char *sys_errlist[];
131#endif
132
133static 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
141static 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
158static 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
187static 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
213int 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
876extern HWND hwndParent;
877
878void 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
903void 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