sl@0: /* sl@0: * tclMacUnix.c -- sl@0: * sl@0: * This file contains routines to implement several features sl@0: * available to the Unix implementation, but that require sl@0: * extra work to do on a Macintosh. These include routines sl@0: * Unix Tcl normally hands off to the Unix OS. sl@0: * sl@0: * Copyright (c) 1993-1994 Lockheed Missle & Space Company, AI Center sl@0: * Copyright (c) 1994-1997 Sun Microsystems, Inc. sl@0: * sl@0: * See the file "license.terms" for information on usage and redistribution sl@0: * of this file, and for a DISCLAIMER OF ALL WARRANTIES. sl@0: * sl@0: * RCS: @(#) $Id: tclMacUnix.c,v 1.5 2002/10/09 11:54:45 das Exp $ sl@0: */ sl@0: sl@0: #include <Files.h> sl@0: #include <Strings.h> sl@0: #include <TextUtils.h> sl@0: #include <Finder.h> sl@0: #include <FSpCompat.h> sl@0: #include <Aliases.h> sl@0: #include <Errors.h> sl@0: sl@0: #include "tclInt.h" sl@0: #include "tclMacInt.h" sl@0: sl@0: /* sl@0: * The following two Includes are from the More Files package sl@0: */ sl@0: #include "FileCopy.h" sl@0: #include "MoreFiles.h" sl@0: #include "MoreFilesExtras.h" sl@0: sl@0: /* sl@0: * The following may not be defined in some versions of sl@0: * MPW header files. sl@0: */ sl@0: #ifndef kIsInvisible sl@0: #define kIsInvisible 0x4000 sl@0: #endif sl@0: #ifndef kIsAlias sl@0: #define kIsAlias 0x8000 sl@0: #endif sl@0: sl@0: /* sl@0: * Missing error codes sl@0: */ sl@0: #define usageErr 500 sl@0: #define noSourceErr 501 sl@0: #define isDirErr 502 sl@0: sl@0: sl@0: /* sl@0: *---------------------------------------------------------------------- sl@0: * sl@0: * Tcl_EchoCmd -- sl@0: * sl@0: * Implements the TCL echo command: sl@0: * echo ?str ...? sl@0: * sl@0: * Results: sl@0: * Always returns TCL_OK. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *---------------------------------------------------------------------- sl@0: */ sl@0: sl@0: int sl@0: Tcl_EchoCmd( sl@0: ClientData dummy, /* Not used. */ sl@0: Tcl_Interp *interp, /* Current interpreter. */ sl@0: int argc, /* Number of arguments. */ sl@0: CONST char **argv) /* Argument strings. */ sl@0: { sl@0: Tcl_Channel chan; sl@0: int mode, result, i; sl@0: sl@0: chan = Tcl_GetChannel(interp, "stdout", &mode); sl@0: if (chan == (Tcl_Channel) NULL) { sl@0: return TCL_ERROR; sl@0: } sl@0: for (i = 1; i < argc; i++) { sl@0: result = Tcl_WriteChars(chan, argv[i], -1); sl@0: if (result < 0) { sl@0: Tcl_AppendResult(interp, "echo: ", Tcl_GetChannelName(chan), sl@0: ": ", Tcl_PosixError(interp), (char *) NULL); sl@0: return TCL_ERROR; sl@0: } sl@0: if (i < (argc - 1)) { sl@0: Tcl_WriteChars(chan, " ", -1); sl@0: } sl@0: } sl@0: Tcl_WriteChars(chan, "\n", -1); sl@0: return TCL_OK; sl@0: } sl@0: sl@0: /* sl@0: *---------------------------------------------------------------------- sl@0: * sl@0: * Tcl_LsObjCmd -- sl@0: * sl@0: * This procedure is invoked to process the "ls" Tcl command. sl@0: * See the user documentation for details on what it does. sl@0: * sl@0: * Results: sl@0: * A standard Tcl result. sl@0: * sl@0: * Side effects: sl@0: * See the user documentation. sl@0: * sl@0: *---------------------------------------------------------------------- sl@0: */ sl@0: int sl@0: Tcl_LsObjCmd( sl@0: ClientData dummy, /* Not used. */ sl@0: Tcl_Interp *interp, /* Current interpreter. */ sl@0: int objc, /* Number of arguments. */ sl@0: Tcl_Obj *CONST objv[]) /* Argument strings. */ sl@0: { sl@0: #define STRING_LENGTH 80 sl@0: #define CR '\n' sl@0: int i, j; sl@0: int fieldLength, len = 0, maxLen = 0, perLine; sl@0: OSErr err; sl@0: CInfoPBRec paramBlock; sl@0: HFileInfo *hpb = (HFileInfo *)¶mBlock; sl@0: DirInfo *dpb = (DirInfo *)¶mBlock; sl@0: char theFile[256]; sl@0: char theLine[STRING_LENGTH + 2]; sl@0: int fFlag = false, pFlag = false, aFlag = false, lFlag = false, sl@0: cFlag = false, hFlag = false; sl@0: char *argv; sl@0: Tcl_Obj *newObjv[2], *resultObjPtr; sl@0: sl@0: /* sl@0: * Process command flags. End if argument doesn't start sl@0: * with a dash or is a dash by itself. The remaining arguments sl@0: * should be files. sl@0: */ sl@0: for (i = 1; i < objc; i++) { sl@0: argv = Tcl_GetString(objv[i]); sl@0: if (argv[0] != '-') { sl@0: break; sl@0: } sl@0: sl@0: if (!strcmp(argv, "-")) { sl@0: i++; sl@0: break; sl@0: } sl@0: sl@0: for (j = 1 ; argv[j] ; ++j) { sl@0: switch(argv[j]) { sl@0: case 'a': sl@0: case 'A': sl@0: aFlag = true; sl@0: break; sl@0: case '1': sl@0: cFlag = false; sl@0: break; sl@0: case 'C': sl@0: cFlag = true; sl@0: break; sl@0: case 'F': sl@0: fFlag = true; sl@0: break; sl@0: case 'H': sl@0: hFlag = true; sl@0: break; sl@0: case 'p': sl@0: pFlag = true; sl@0: break; sl@0: case 'l': sl@0: pFlag = false; sl@0: lFlag = true; sl@0: break; sl@0: default: sl@0: Tcl_AppendResult(interp, "error - unknown flag ", sl@0: "usage: ls -apCFHl1 ?files? ", NULL); sl@0: return TCL_ERROR; sl@0: } sl@0: } sl@0: } sl@0: sl@0: objv += i; sl@0: objc -= i; sl@0: sl@0: /* sl@0: * No file specifications means we search for all files. sl@0: * Glob will be doing most of the work. sl@0: */ sl@0: if (!objc) { sl@0: objc = 1; sl@0: newObjv[0] = Tcl_NewStringObj("*", -1); sl@0: newObjv[1] = NULL; sl@0: objv = newObjv; sl@0: } sl@0: sl@0: if (Tcl_GlobObjCmd(NULL, interp, objc + 1, objv - 1) != TCL_OK) { sl@0: Tcl_ResetResult(interp); sl@0: return TCL_ERROR; sl@0: } sl@0: sl@0: resultObjPtr = Tcl_GetObjResult(interp); sl@0: Tcl_IncrRefCount(resultObjPtr); sl@0: if (Tcl_ListObjGetElements(interp, resultObjPtr, &objc, (Tcl_Obj ***)&objv) != TCL_OK) { sl@0: Tcl_DecrRefCount(resultObjPtr); sl@0: return TCL_ERROR; sl@0: } sl@0: sl@0: Tcl_ResetResult(interp); sl@0: sl@0: /* sl@0: * There are two major methods for listing files: the long sl@0: * method and the normal method. sl@0: */ sl@0: if (lFlag) { sl@0: char creator[5], type[5], time[16], date[16]; sl@0: char lineTag; sl@0: long size; sl@0: unsigned short flags; sl@0: Tcl_Obj *objPtr; sl@0: char *string; sl@0: int length; sl@0: sl@0: /* sl@0: * Print the header for long listing. sl@0: */ sl@0: if (hFlag) { sl@0: sprintf(theLine, "T %7s %8s %8s %4s %4s %6s %s", sl@0: "Size", "ModTime", "ModDate", sl@0: "CRTR", "TYPE", "Flags", "Name"); sl@0: Tcl_AppendResult(interp, theLine, "\n", NULL); sl@0: Tcl_AppendResult(interp, sl@0: "-------------------------------------------------------------\n", sl@0: NULL); sl@0: } sl@0: sl@0: for (i = 0; i < objc; i++) { sl@0: strcpy(theFile, Tcl_GetString(objv[i])); sl@0: sl@0: c2pstr(theFile); sl@0: hpb->ioCompletion = NULL; sl@0: hpb->ioVRefNum = 0; sl@0: hpb->ioFDirIndex = 0; sl@0: hpb->ioNamePtr = (StringPtr) theFile; sl@0: hpb->ioDirID = 0L; sl@0: err = PBGetCatInfoSync(¶mBlock); sl@0: p2cstr((StringPtr) theFile); sl@0: sl@0: if (hpb->ioFlAttrib & 16) { sl@0: /* sl@0: * For directories use zero as the size, use no Creator sl@0: * type, and use 'DIR ' as the file type. sl@0: */ sl@0: if ((aFlag == false) && (dpb->ioDrUsrWds.frFlags & 0x1000)) { sl@0: continue; sl@0: } sl@0: lineTag = 'D'; sl@0: size = 0; sl@0: IUTimeString(dpb->ioDrMdDat, false, (unsigned char *)time); sl@0: p2cstr((StringPtr)time); sl@0: IUDateString(dpb->ioDrMdDat, shortDate, (unsigned char *)date); sl@0: p2cstr((StringPtr)date); sl@0: strcpy(creator, " "); sl@0: strcpy(type, "DIR "); sl@0: flags = dpb->ioDrUsrWds.frFlags; sl@0: if (fFlag || pFlag) { sl@0: strcat(theFile, ":"); sl@0: } sl@0: } else { sl@0: /* sl@0: * All information for files should be printed. This sl@0: * includes size, modtime, moddate, creator type, file sl@0: * type, flags, anf file name. sl@0: */ sl@0: if ((aFlag == false) && sl@0: (hpb->ioFlFndrInfo.fdFlags & kIsInvisible)) { sl@0: continue; sl@0: } sl@0: lineTag = 'F'; sl@0: size = hpb->ioFlLgLen + hpb->ioFlRLgLen; sl@0: IUTimeString(hpb->ioFlMdDat, false, (unsigned char *)time); sl@0: p2cstr((StringPtr)time); sl@0: IUDateString(hpb->ioFlMdDat, shortDate, (unsigned char *)date); sl@0: p2cstr((StringPtr)date); sl@0: strncpy(creator, (char *) &hpb->ioFlFndrInfo.fdCreator, 4); sl@0: creator[4] = 0; sl@0: strncpy(type, (char *) &hpb->ioFlFndrInfo.fdType, 4); sl@0: type[4] = 0; sl@0: flags = hpb->ioFlFndrInfo.fdFlags; sl@0: if (fFlag) { sl@0: if (hpb->ioFlFndrInfo.fdFlags & kIsAlias) { sl@0: strcat(theFile, "@"); sl@0: } else if (hpb->ioFlFndrInfo.fdType == 'APPL') { sl@0: strcat(theFile, "*"); sl@0: } sl@0: } sl@0: } sl@0: sl@0: sprintf(theLine, "%c %7ld %8s %8s %-4.4s %-4.4s 0x%4.4X %s", sl@0: lineTag, size, time, date, creator, type, flags, theFile); sl@0: sl@0: Tcl_AppendResult(interp, theLine, "\n", NULL); sl@0: sl@0: } sl@0: sl@0: objPtr = Tcl_GetObjResult(interp); sl@0: string = Tcl_GetStringFromObj(objPtr, &length); sl@0: if ((length > 0) && (string[length - 1] == '\n')) { sl@0: Tcl_SetObjLength(objPtr, length - 1); sl@0: } sl@0: } else { sl@0: /* sl@0: * Not in long format. We only print files names. If the sl@0: * -C flag is set we need to print in multiple coloumns. sl@0: */ sl@0: int argCount, linePos; sl@0: Boolean needNewLine = false; sl@0: sl@0: /* sl@0: * Fiend the field length: the length each string printed sl@0: * to the terminal will be. sl@0: */ sl@0: if (!cFlag) { sl@0: perLine = 1; sl@0: fieldLength = STRING_LENGTH; sl@0: } else { sl@0: for (i = 0; i < objc; i++) { sl@0: argv = Tcl_GetString(objv[i]); sl@0: len = strlen(argv); sl@0: if (len > maxLen) { sl@0: maxLen = len; sl@0: } sl@0: } sl@0: fieldLength = maxLen + 3; sl@0: perLine = STRING_LENGTH / fieldLength; sl@0: } sl@0: sl@0: argCount = 0; sl@0: linePos = 0; sl@0: memset(theLine, ' ', STRING_LENGTH); sl@0: while (argCount < objc) { sl@0: strcpy(theFile, Tcl_GetString(objv[argCount])); sl@0: sl@0: c2pstr(theFile); sl@0: hpb->ioCompletion = NULL; sl@0: hpb->ioVRefNum = 0; sl@0: hpb->ioFDirIndex = 0; sl@0: hpb->ioNamePtr = (StringPtr) theFile; sl@0: hpb->ioDirID = 0L; sl@0: err = PBGetCatInfoSync(¶mBlock); sl@0: p2cstr((StringPtr) theFile); sl@0: sl@0: if (hpb->ioFlAttrib & 16) { sl@0: /* sl@0: * Directory. If -a show hidden files. If -f or -p sl@0: * denote that this is a directory. sl@0: */ sl@0: if ((aFlag == false) && (dpb->ioDrUsrWds.frFlags & 0x1000)) { sl@0: argCount++; sl@0: continue; sl@0: } sl@0: if (fFlag || pFlag) { sl@0: strcat(theFile, ":"); sl@0: } sl@0: } else { sl@0: /* sl@0: * File: If -a show hidden files, if -f show links sl@0: * (aliases) and executables (APPLs). sl@0: */ sl@0: if ((aFlag == false) && sl@0: (hpb->ioFlFndrInfo.fdFlags & kIsInvisible)) { sl@0: argCount++; sl@0: continue; sl@0: } sl@0: if (fFlag) { sl@0: if (hpb->ioFlFndrInfo.fdFlags & kIsAlias) { sl@0: strcat(theFile, "@"); sl@0: } else if (hpb->ioFlFndrInfo.fdType == 'APPL') { sl@0: strcat(theFile, "*"); sl@0: } sl@0: } sl@0: } sl@0: sl@0: /* sl@0: * Print the item, taking into account multi- sl@0: * coloum output. sl@0: */ sl@0: strncpy(theLine + (linePos * fieldLength), theFile, sl@0: strlen(theFile)); sl@0: linePos++; sl@0: sl@0: if (linePos == perLine) { sl@0: theLine[STRING_LENGTH] = '\0'; sl@0: if (needNewLine) { sl@0: Tcl_AppendResult(interp, "\n", theLine, NULL); sl@0: } else { sl@0: Tcl_AppendResult(interp, theLine, NULL); sl@0: needNewLine = true; sl@0: } sl@0: linePos = 0; sl@0: memset(theLine, ' ', STRING_LENGTH); sl@0: } sl@0: sl@0: argCount++; sl@0: } sl@0: sl@0: if (linePos != 0) { sl@0: theLine[STRING_LENGTH] = '\0'; sl@0: if (needNewLine) { sl@0: Tcl_AppendResult(interp, "\n", theLine, NULL); sl@0: } else { sl@0: Tcl_AppendResult(interp, theLine, NULL); sl@0: } sl@0: } sl@0: } sl@0: sl@0: Tcl_DecrRefCount(resultObjPtr); sl@0: sl@0: return TCL_OK; sl@0: }