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: 1999/11/01 13:31:36 $ 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