|
|
1.1 ! root 1: /* ! 2: * tkRawTCP.c -- ! 3: * ! 4: * This file contains a simple Tcl "connect" command ! 5: * that returns an standard Tcl File descriptor (as would ! 6: * be returned by Tcl_OpenCmd). ! 7: * Extended to create servers, accept connections, shutdown parts of full ! 8: * duplex connections and handle UNIX domain sockets. ! 9: * ! 10: * Author: Pekka Nikander <[email protected]> ! 11: * Modified: Tim MacKenzie <[email protected]) ! 12: * ! 13: * Copyright 1992 Telecom Finland ! 14: * ! 15: * Permission to use, copy, modify, and distribute this ! 16: * software and its documentation for any purpose and without ! 17: * fee is hereby granted, provided that this copyright ! 18: * notice appears in all copies. Telecom Finland ! 19: * makes no representations about the suitability of this ! 20: * software for any purpose. It is provided "as is" without ! 21: * express or implied warranty. ! 22: * ! 23: * Created: Sun Mar 22 18:20:29 1992 ! 24: * based on: Last modified: Sun Mar 22 21:34:31 1992 pnr ! 25: * Last modified: Mon Jun 29 15:25:14 EST 1992 tym ! 26: * ! 27: */ ! 28: ! 29: #ifndef lint ! 30: static char rcsid[] = "..."; ! 31: #endif /* not lint */ ! 32: ! 33: #include "tclint.h" ! 34: #include "tclunix.h" ! 35: ! 36: #include <assert.h> ! 37: #include <string.h> ! 38: #include <sys/types.h> ! 39: #include <sys/socket.h> ! 40: #include <netinet/in.h> ! 41: #include <netdb.h> ! 42: #include <arpa/inet.h> ! 43: #include <sys/un.h> ! 44: ! 45: #include <tk.h> ! 46: ! 47: static int inet_connect _ANSI_ARGS_((char *host, char *port,int server)); ! 48: static int unix_connect _ANSI_ARGS_((char *path, int server)); ! 49: static void HandleSocket _ANSI_ARGS_ ((ClientData clientData, int mask)); ! 50: ! 51: typedef struct { ! 52: Tcl_Interp *interp; ! 53: OpenFile *filePtr; ! 54: char *tclCmd; ! 55: char *fileId; ! 56: } FileCmd; ! 57: ! 58: /* ! 59: *------------------------------------------------------------------ ! 60: * ! 61: * Tcp_MakeOpenFile -- ! 62: * ! 63: * Set up on OpenFile structure in the interpreter for a newly ! 64: * opened file ! 65: * ! 66: * Results: ! 67: * none ! 68: * ! 69: * Side effects: ! 70: * Adds an OpenFile to the list. ! 71: *------------------------------------------------------------------ ! 72: */ ! 73: ! 74: /* ARGSUSED */ ! 75: void ! 76: Tcp_MakeOpenFile(interp,fd,r,w) ! 77: Tcl_Interp *interp; ! 78: int fd; ! 79: int r,w; ! 80: {/* Create an OpenFile structure using f and install it in the interpreter with ! 81: * Readable and Writable set to r and w ! 82: */ ! 83: Interp *iPtr = (Interp *) interp; ! 84: register OpenFile *filePtr; ! 85: ! 86: filePtr = (OpenFile *) ckalloc(sizeof(OpenFile)); ! 87: ! 88: filePtr->f = NULL; ! 89: filePtr->f2 = NULL; ! 90: ! 91: /* Open the file with the correct type (doesn't handle !r && !w) */ ! 92: #ifdef MSDOS ! 93: filePtr->f = fdopen(fd,(r&&w)?"rb+":(r?"rb":"wb")); ! 94: #else ! 95: filePtr->f = fdopen(fd,(r&&w)?"r+":(r?"r":"w")); ! 96: #endif ! 97: /* Don't do buffered communication if full-duplex... it breaks! */ ! 98: if (r&w) setbuf(filePtr->f,0); ! 99: ! 100: filePtr->readable = r; ! 101: filePtr->writable = w; ! 102: filePtr->numPids = 0; ! 103: filePtr->pidPtr = NULL; ! 104: filePtr->errorId = -1; ! 105: ! 106: /* ! 107: * Enter this new OpenFile structure in the table for the ! 108: * interpreter. May have to expand the table to do this. ! 109: */ ! 110: ! 111: TclMakeFileTable(iPtr, fd); ! 112: if (iPtr->filePtrArray[fd] != NULL) { ! 113: panic("Tcl_OpenCmd found file already open"); ! 114: } ! 115: iPtr->filePtrArray[fd] = filePtr; ! 116: } ! 117: ! 118: /* ! 119: *------------------------------------------------------------------ ! 120: * ! 121: * Tcp_ConnectCmd -- ! 122: * ! 123: * Open a socket connection to a given host and service. ! 124: * ! 125: * Results: ! 126: * A standard Tcl result. ! 127: * ! 128: * Side effects: ! 129: * An open socket connection. ! 130: * Sets the global variable connect_info(file%d) to the obtained ! 131: * port when setting up server. ! 132: *------------------------------------------------------------------ ! 133: */ ! 134: ! 135: /* ARGSUSED */ ! 136: int ! 137: Tcp_ConnectCmd(notUsed, interp, argc, argv) ! 138: ClientData notUsed; ! 139: Tcl_Interp *interp; ! 140: int argc; ! 141: char **argv; ! 142: { ! 143: Interp *iPtr = (Interp *) interp; ! 144: char *host,*port; ! 145: int fd; ! 146: int server=0; ! 147: int unicks = 0; ! 148: ! 149: if (argc != 2 && argc != 3 && ! 150: (argc != 4 || (argc == 4 && strcmp(argv[1],"-server")))) { ! 151: Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], ! 152: "[{-server}] address_spec\"", (char *) NULL); ! 153: return TCL_ERROR; ! 154: } ! 155: ! 156: if (!strcmp(argv[1],"-server")) ! 157: server = 1; ! 158: ! 159: /* ! 160: * Create the connection ! 161: */ ! 162: if (argc - server == 2) {/* Unix domain socket */ ! 163: unicks = 1; ! 164: fd = unix_connect(argv[1+server],server); ! 165: } else ! 166: fd = inet_connect(argv[1+server], argv[2+server],server); ! 167: ! 168: if (fd < 0) { ! 169: /* Tell them why it fell apart */ ! 170: if (unicks) ! 171: if (server) ! 172: Tcl_AppendResult(interp, ! 173: "Couldn't setup listening socket with path \"", ! 174: argv[1+server],"\" : ",Tcl_UnixError(interp), ! 175: (char *) NULL); ! 176: else ! 177: Tcl_AppendResult(interp, ! 178: "Couldn't connect to \"",argv[1],"\" : ", ! 179: Tcl_UnixError(interp),(char *) NULL); ! 180: else ! 181: if (server) ! 182: Tcl_AppendResult(interp, ! 183: "couldn't setup listening socket on port:", ! 184: atoi(argv[3])==0?"any":argv[3]," using address \"", ! 185: strlen(argv[2])?argv[2]:"anywhere.","\": ", ! 186: Tcl_UnixError(interp), (char *)NULL); ! 187: else ! 188: Tcl_AppendResult(interp, "couldn't open connection to \"", ! 189: argv[1], "\" port \"", argv[2], "\": ", ! 190: Tcl_UnixError(interp), (char *) NULL); ! 191: return TCL_ERROR; ! 192: } ! 193: ! 194: sprintf(interp->result, "file%d", fd); ! 195: if (server && !unicks) { ! 196: /* Find out what port we got */ ! 197: char buf[50]; ! 198: struct sockaddr_in sockaddr; ! 199: int res,len=sizeof(sockaddr); ! 200: res =getsockname(fd,(struct sockaddr *) &sockaddr, &len); ! 201: if (res < 0) { ! 202: sprintf(buf,"%d",errno); ! 203: } else ! 204: sprintf(buf,"%d",(int)ntohs(sockaddr.sin_port)); ! 205: Tcl_SetVar2(interp,"connect_info",interp->result,buf,TCL_GLOBAL_ONLY); ! 206: } ! 207: ! 208: Tcp_MakeOpenFile(iPtr,fd,1,1-server); ! 209: ! 210: return TCL_OK; ! 211: } ! 212: ! 213: /* ! 214: *------------------------------------------------------------------ ! 215: * ! 216: * Tcp_ShutdownCmd -- ! 217: * ! 218: * Shutdown a socket for reading writing or both using shutdown(2) ! 219: * ! 220: * Results: ! 221: * standard tcl result. ! 222: * ! 223: * Side effects: ! 224: * Modifies the OpenFile structure appropriately ! 225: *------------------------------------------------------------------ ! 226: */ ! 227: ! 228: /* ARGSUSED */ ! 229: int ! 230: Tcp_ShutdownCmd(notUsed, interp, argc, argv) ! 231: ClientData notUsed; ! 232: Tcl_Interp *interp; ! 233: int argc; ! 234: char **argv; ! 235: { ! 236: Interp *iPtr = (Interp *) interp; ! 237: OpenFile *filePtr; ! 238: register FILE *f; ! 239: int fd; ! 240: ! 241: if (argc != 3) { ! 242: wrong_args: ! 243: Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], ! 244: " fileid <option>\"", (char *) NULL); ! 245: return TCL_ERROR; ! 246: } ! 247: ! 248: if (TclGetOpenFile(interp, argv[1], &filePtr) != TCL_OK) { ! 249: return TCL_ERROR; ! 250: } ! 251: ! 252: f = filePtr->f; ! 253: fd = fileno(filePtr->f); ! 254: if (!strcmp(argv[2],"0") || !strcmp(argv[2],"receives") || ! 255: !strcmp(argv[2],"read")) { ! 256: if (!filePtr->readable) { ! 257: Tcl_AppendResult(interp, "File is not readable",(char *) NULL); ! 258: return TCL_ERROR; ! 259: } ! 260: if (shutdown(fd,0)) { ! 261: Tcl_AppendResult(interp, "shutdown: ", Tcl_UnixError(interp), ! 262: (char *) NULL); ! 263: return TCL_ERROR; ! 264: } ! 265: filePtr->readable=0; ! 266: } else if (!strcmp(argv[2],"1") || !strcmp(argv[2],"sends") || ! 267: !strcmp(argv[2],"write")) { ! 268: if (!filePtr->writable) { ! 269: Tcl_AppendResult(interp, "File is not writable",(char *) NULL); ! 270: return TCL_ERROR; ! 271: } ! 272: if (shutdown(fd,1)) { ! 273: Tcl_AppendResult(interp, "shutdown: ", Tcl_UnixError(interp), ! 274: (char *) NULL); ! 275: return TCL_ERROR; ! 276: } ! 277: filePtr->writable=0; ! 278: } else if (!strcmp(argv[2],"2") || !strcmp(argv[2],"all") || ! 279: !strcmp(argv[2],"both")) { ! 280: if (shutdown(fd,2)) { ! 281: Tcl_AppendResult(interp, "shutdown: ", Tcl_UnixError(interp), ! 282: (char *) NULL); ! 283: return TCL_ERROR; ! 284: } ! 285: filePtr->writable=0; ! 286: filePtr->readable=0; ! 287: } else ! 288: goto wrong_args; ! 289: return TCL_OK; ! 290: } ! 291: ! 292: ! 293: ! 294: /* ! 295: *------------------------------------------------------------------ ! 296: * ! 297: * Tcp_AcceptCmd -- ! 298: * ! 299: * Accept a connection on a listening socket ! 300: * ! 301: * Results: ! 302: * a standard tcl result ! 303: * ! 304: * Side effects: ! 305: * Opens a new file. ! 306: * Sets the global variable connect_info(file%d) to a list ! 307: * containing the remote address (host ip, port) of the ! 308: * connector. ! 309: *------------------------------------------------------------------ ! 310: */ ! 311: ! 312: /* ARGSUSED */ ! 313: int ! 314: Tcp_AcceptCmd(notUsed, interp, argc, argv) ! 315: ClientData notUsed; ! 316: Tcl_Interp *interp; ! 317: int argc; ! 318: char **argv; ! 319: { ! 320: Interp *iPtr = (Interp *) interp; ! 321: struct sockaddr_in sockaddr; ! 322: int len = sizeof sockaddr; ! 323: OpenFile *filePtr; ! 324: register FILE *f; ! 325: int fd; ! 326: ! 327: if (argc != 2) { ! 328: Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], ! 329: " listening_socket\"", (char *) NULL); ! 330: return TCL_ERROR; ! 331: } ! 332: ! 333: if (TclGetOpenFile(interp, argv[1], &filePtr) != TCL_OK) { ! 334: return TCL_ERROR; ! 335: } ! 336: if (!filePtr->readable) { ! 337: Tcl_AppendResult(interp, "\"", argv[1], ! 338: "\" wasn't opened for reading", (char *) NULL); ! 339: return TCL_ERROR; ! 340: } ! 341: ! 342: f = filePtr->f; ! 343: fd = fileno(filePtr->f); ! 344: ! 345: fd = accept(fd,(struct sockaddr *)&sockaddr,&len); ! 346: if (fd < 0) { ! 347: Tcl_AppendResult(interp, "system error in accept()", (char *)NULL); ! 348: return TCL_ERROR; ! 349: } ! 350: ! 351: {/* Set the global connect_info */ ! 352: char buf[100]; ! 353: char nm[10]; ! 354: if (sockaddr.sin_family == AF_INET) ! 355: sprintf(buf,"%s %d",inet_ntoa(sockaddr.sin_addr), ! 356: ntohs(sockaddr.sin_port)); ! 357: else ! 358: buf[0]=0; /* Empty string for UNIX domain sockets */ ! 359: sprintf(nm,"file%d",fd); ! 360: Tcl_SetVar2(interp,"connect_info",nm,buf,TCL_GLOBAL_ONLY); ! 361: } ! 362: ! 363: /* ! 364: * Create the FILE* ! 365: */ ! 366: Tcp_MakeOpenFile(iPtr,fd,1,1); ! 367: ! 368: sprintf(interp->result, "file%d", fd); ! 369: return TCL_OK; ! 370: } ! 371: ! 372: /* ! 373: *---------------------------------------------------------------- ! 374: * ! 375: * unix_connect -- ! 376: * ! 377: * Create a (unix_domain) fd connection using given rendeavous ! 378: * ! 379: * Results: ! 380: * An open fd or -1. ! 381: * ! 382: * Side effects: ! 383: * None. ! 384: *---------------------------------------------------------------- ! 385: */ ! 386: ! 387: static int ! 388: unix_connect(path,server) ! 389: char *path; /* Path name to create or use */ ! 390: int server; /* 1->make server, 0->connect to server */ ! 391: { ! 392: struct sockaddr_un sockaddr; ! 393: int sock, status; ! 394: extern int errno; ! 395: ! 396: sock = socket(PF_UNIX, SOCK_STREAM, 0); ! 397: if (sock < 0) { ! 398: return -1; ! 399: } ! 400: ! 401: sockaddr.sun_family = AF_UNIX; ! 402: strncpy(sockaddr.sun_path,path,sizeof(sockaddr.sun_path)-1); ! 403: sockaddr.sun_path[sizeof(sockaddr.sun_path)-1] = 0; /* Just in case */ ! 404: ! 405: if (server) ! 406: status = bind(sock,(struct sockaddr *) &sockaddr, sizeof(sockaddr)); ! 407: else ! 408: status = connect(sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr)); ! 409: ! 410: if (status < 0) { ! 411: close (sock); ! 412: return -1; ! 413: } ! 414: ! 415: if (server) { ! 416: listen(sock,5); ! 417: return sock; ! 418: } ! 419: ! 420: return sock; ! 421: } ! 422: ! 423: /* ! 424: *---------------------------------------------------------------- ! 425: * ! 426: * inet_connect -- ! 427: * ! 428: * Create a (inet domain) fd connection to given host and port. ! 429: * ! 430: * Results: ! 431: * An open fd or -1. ! 432: * ! 433: * Side effects: ! 434: * None. ! 435: *---------------------------------------------------------------- ! 436: */ ! 437: ! 438: static int ! 439: inet_connect(host, service,server) ! 440: char *host; /* Host to connect, name or IP address */ ! 441: char *service; /* Port to use, service name or port number */ ! 442: int server; ! 443: { ! 444: struct hostent *hostent, _hostent; ! 445: struct servent *servent, _servent; ! 446: struct protoent *protoent; ! 447: struct sockaddr_in sockaddr; ! 448: int sock, status; ! 449: int hostaddr, hostaddrPtr[2]; ! 450: int servport; ! 451: extern int errno; ! 452: ! 453: hostent = gethostbyname(host); ! 454: if (hostent == NULL) { ! 455: hostaddr = inet_addr(host); ! 456: if (hostaddr == -1) { ! 457: if (server && !strlen(host)) ! 458: hostaddr = INADDR_ANY; ! 459: else { ! 460: errno = EINVAL; ! 461: return -1; ! 462: } ! 463: } ! 464: _hostent.h_addr_list = (char **)hostaddrPtr; ! 465: _hostent.h_addr_list[0] = (char *)&hostaddr; ! 466: _hostent.h_addr_list[1] = NULL; ! 467: _hostent.h_length = sizeof(hostaddr); ! 468: _hostent.h_addrtype = AF_INET; ! 469: hostent = &_hostent; ! 470: } ! 471: servent = getservbyname(service, "tcp"); ! 472: if (servent == NULL) { ! 473: servport = htons(atoi(service)); ! 474: if (servport == -1) { ! 475: errno = EINVAL; ! 476: return -1; ! 477: } ! 478: _servent.s_port = servport; ! 479: _servent.s_proto = "tcp"; ! 480: servent = &_servent; ! 481: } ! 482: protoent = getprotobyname(servent->s_proto); ! 483: if (protoent == NULL) { ! 484: errno = EINVAL; ! 485: return -1; ! 486: } ! 487: ! 488: sock = socket(PF_INET, SOCK_STREAM, protoent->p_proto); ! 489: if (sock < 0) { ! 490: return -1; ! 491: } ! 492: ! 493: sockaddr.sin_family = AF_INET; ! 494: memcpy((char *)&(sockaddr.sin_addr.s_addr), ! 495: (char *) hostent->h_addr_list[0], ! 496: (size_t) hostent->h_length); ! 497: sockaddr.sin_port = servent->s_port; ! 498: ! 499: if (server) ! 500: status = bind(sock,(struct sockaddr *) &sockaddr, sizeof(sockaddr)); ! 501: else ! 502: status = connect(sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr)); ! 503: ! 504: if (status < 0) { ! 505: close (sock); ! 506: return -1; ! 507: } ! 508: ! 509: if (server) { ! 510: listen(sock,5); ! 511: return sock; ! 512: } ! 513: ! 514: return sock; ! 515: } ! 516: ! 517: /* ! 518: *---------------------------------------------------------------- ! 519: * ! 520: * Tcp_FileHandlerCmd -- ! 521: * ! 522: * Register a file handler with an open file. If there is ! 523: * already and existing handler, it will be no longer called. ! 524: * If no mask and command are given, any existing handler ! 525: * will be deleted. ! 526: * ! 527: * Results: ! 528: * A standard Tcl result. (Always OK). ! 529: * ! 530: * Side effects: ! 531: * A new file handler is associated with a give TCL open file. ! 532: * Whenever the file is readable, writeable and/or there is ! 533: * an expection condition on the file, a user supplied TCL ! 534: * command is called. ! 535: * ! 536: *---------------------------------------------------------------- ! 537: */ ! 538: ! 539: /* ARGSUSED */ ! 540: int ! 541: Tcp_FileHandlerCmd(notUsed, interp, argc, argv) ! 542: ClientData notUsed; ! 543: Tcl_Interp *interp; ! 544: int argc; ! 545: char **argv; ! 546: { ! 547: FileCmd *cmdPtr; ! 548: OpenFile *filePtr; ! 549: int mask; ! 550: ! 551: if (argc != 2 && argc != 4) { ! 552: Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], ! 553: " fileId ?mode command?\"", (char *) NULL); ! 554: return TCL_ERROR; ! 555: } ! 556: ! 557: if (TclGetOpenFile(interp, argv[1], &filePtr) != TCL_OK) { ! 558: return TCL_ERROR; ! 559: } ! 560: ! 561: if (argc == 2) { ! 562: /* ! 563: * NOTE! Currently the cmdPtr structure will be left ! 564: * *unfreed* if the file handler is deleted ! 565: * via this code. Tough. Would need a hash table ! 566: * or something... ! 567: */ ! 568: Tk_DeleteFileHandler(fileno(filePtr->f)); ! 569: return TCL_OK; ! 570: } ! 571: ! 572: /* ! 573: * Find out on what situations the user is interested in. ! 574: * This is not the most elegant or efficient way to do this, ! 575: * but who cares? (I do, but not much enough :-) ! 576: */ ! 577: mask = 0; ! 578: if (strchr(argv[2], 'r')) { ! 579: mask |= TK_READABLE; ! 580: } ! 581: if (strchr(argv[2], 'w')) { ! 582: mask |= TK_WRITABLE; ! 583: } ! 584: if (strchr(argv[2], 'e')) { ! 585: mask |= TK_EXCEPTION; ! 586: } ! 587: if (mask == 0 || (strlen(argv[2]) != strspn(argv[2], "rwe"))) { ! 588: Tcl_AppendResult(interp, "bad mask argument \"", argv[2], ! 589: "\": should be any combination of \"r\", \"w\" and \"e\"", ! 590: (char *) NULL); ! 591: fclose(filePtr->f); ! 592: return TCL_ERROR; ! 593: } ! 594: ! 595: cmdPtr = (FileCmd *)ckalloc(sizeof(FileCmd)); ! 596: cmdPtr->interp = interp; ! 597: cmdPtr->filePtr = filePtr; ! 598: cmdPtr->tclCmd = ckalloc(strlen(argv[3]) + 1); ! 599: strcpy(cmdPtr->tclCmd, argv[3]); ! 600: cmdPtr->fileId = ckalloc(strlen(argv[1]) + 1); ! 601: strcpy(cmdPtr->fileId, argv[1]); ! 602: ! 603: /* ! 604: * NOTE! There may be an earlier file handler. Should do something. ! 605: */ ! 606: Tk_CreateFileHandler(fileno(filePtr->f), mask, HandleSocket, ! 607: (ClientData) cmdPtr); ! 608: ! 609: return TCL_OK; ! 610: } ! 611: /* ! 612: *---------------------------------------------------------------- ! 613: * ! 614: * HandleSocket -- ! 615: * ! 616: * This procedure is called from Tk_DoOneEvent whenever there is ! 617: * a desired condition on a given open socket. An Tcl command ! 618: * given by the user is executed to handle the connection. If ! 619: * and EOF or ERROR condition is noticed, all memory resources ! 620: * associated with the socket are released and the socket is closed. ! 621: * ! 622: * Results: ! 623: * None. ! 624: * ! 625: * Side effects: ! 626: * The user supplied command can do anything. ! 627: * ! 628: *---------------------------------------------------------------- ! 629: */ ! 630: ! 631: static void ! 632: HandleSocket(clientData, mask) ! 633: ClientData clientData; ! 634: int mask; ! 635: { ! 636: int result; ! 637: FileCmd *cmdPtr = (FileCmd *) clientData; ! 638: OpenFile *filePtr = cmdPtr->filePtr; ! 639: Tcl_Interp *interp = cmdPtr->interp; ! 640: OpenFile *dummy; ! 641: int delete; ! 642: int fd = fileno(filePtr->f); ! 643: ! 644: Tk_Preserve((ClientData)cmdPtr); ! 645: ! 646: delete = 0; ! 647: if (TclGetOpenFile(interp, cmdPtr->fileId, &dummy) != TCL_OK) { ! 648: /* File is closed! */ ! 649: Tcl_ResetResult(interp); ! 650: delete = 1; ! 651: } else { ! 652: assert(dummy == cmdPtr->filePtr); ! 653: ! 654: if (mask & TK_READABLE) { ! 655: result = Tcl_VarEval(interp, cmdPtr->tclCmd, " r ", cmdPtr->fileId, ! 656: (char *) NULL); ! 657: if (result != TCL_OK) { ! 658: TkBindError(interp); ! 659: } ! 660: } ! 661: if (mask & TK_WRITABLE) { ! 662: result = Tcl_VarEval(interp, cmdPtr->tclCmd, " w ", cmdPtr->fileId, ! 663: (char *) NULL); ! 664: if (result != TCL_OK) { ! 665: TkBindError(interp); ! 666: } ! 667: } ! 668: if (mask & TK_EXCEPTION) { ! 669: result = Tcl_VarEval(interp, cmdPtr->tclCmd, " e ", cmdPtr->fileId, ! 670: (char *) NULL); ! 671: if (result != TCL_OK) { ! 672: TkBindError(interp); ! 673: } ! 674: } ! 675: ! 676: if (feof(filePtr->f) || ferror(filePtr->f)) { ! 677: result = Tcl_VarEval(interp, "close ", cmdPtr->fileId, ! 678: (char *) NULL); ! 679: if (result != TCL_OK) { ! 680: TkBindError(interp); ! 681: } ! 682: delete = 1; ! 683: } ! 684: } ! 685: ! 686: Tk_Release((ClientData)cmdPtr); ! 687: ! 688: if (delete) { ! 689: Tk_DeleteFileHandler(fd); ! 690: Tk_EventuallyFree((ClientData)cmdPtr, (Tk_FreeProc *)free); ! 691: } ! 692: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.