/***************************************************************************** This source code is made available to you under the terms of the Open Development License. This Package should be accompanied by a file that contains the associated licensing terms. If you are unable to find this file, please refer to its location on the Internet at www.rocklyte.com/license.html. ****************************************************************************** ###CLASS### Name: Print Version: 1.0 Status: Stable Date: June 2001 ID: ID_PRINT Category: Command Author: Rocklyte Systems Copyright: Rocklyte Systems (c) 2000-2001. All rights reserved. Keywords: print, text, file, printout, type, data ###DESCRIPTION### <p>The Print class allows you to send text information to the data channel of any object. In the majority of cases it is used in conjunction with the Text class to view text files, but could also be used to print text to computers over a network, to printers, or any object that understands text data.</p> <p>The following example prints a file to a Text object:</p> <pre> &lt;print src="athene:documents/readme.txt" object="[mytext]"/&gt; </pre> <p>This example prints "Hello World":</p> <pre> &lt;print data="Hello World" object="[mytext]"/&gt; </pre> <p>If output messages are required, you may also set the Output field to point to an object that accepts text messages. If any errors occur during the print, a human readable message will be printed to the output object to provide adequate feedback for the user.</p> ###ACTIONS### Activate: Performs the print process. ClosingTag: If the object is non-static, this action will cause the Print object to activate and then self-destruct. ###END### *****************************************************************************/ #include <pandora/system/all.h> #include <pandora/modules/strings.h> #include <pandora/files/file.h> static ERROR CMDInit(OBJECTPTR, struct KernelBase *); static ERROR CMDExpunge(void); #define VER_PRINT 1.0 EXPORT struct ModHeader ModHeader = { MODULE_HEADER_V1, CMDInit, NULL, NULL, CMDExpunge, JMP_DEFAULT, 0, CPU_PC, VER_PRINT, VER_KERNEL, "Rocklyte Systems", "Rocklyte Systems (c) 2000-2001. All rights reserved.", "June 2001", "Print" }; static struct KernelBase *KernelBase = 0; static struct StringsBase *StringsBase = 0; static OBJECTPTR PrintClass = 0; static OBJECTPTR StringsMod = 0; /***************************************************************************** ** Class definition. */ struct Print { OBJECT_HEADER /* Class header */ OBJECTID OutputID; /* Error messages will be printed to this object */ OBJECTID ObjectID; /* The object to output the data to */ LONG Static; /* Set to TRUE if we are static */ LONG Clear; /* Set to TRUE if the output object should be cleared */ PRIVATE_FIELDS STRING Data; /* Text data to be printed */ STRING Location; /* Location of the data file */ MEMORYID DataMID; MEMORYID LocationMID; }; static ERROR GET_Data(struct Print *, STRING *); static ERROR GET_Location(struct Print *, STRING *); static ERROR SET_Data(struct Print *, STRING); static ERROR SET_Location(struct Print *, STRING); static struct FieldArray PrintFields[] = { { "Output", 0, FDF_OBJECTID|FDF_RW, 0, NULL, NULL }, { "Object", 0, FDF_OBJECTID|FDF_RW, 0, NULL, NULL }, { "Static", 0, FDF_LONG|FDF_RW, 0, NULL, NULL }, { "Clear", 0, FDF_LONG|FDF_RW, 0, NULL, NULL }, /*** Virtual fields ***/ { "Data", 0, FDF_STRING|FDF_RW, 0, GET_Data, SET_Data }, { "Text", 0, FDF_STRING|FDF_RW, 0, GET_Data, SET_Data }, { "Location", 0, FDF_STRING|FDF_RW, 0, GET_Location, SET_Location }, { "Src", 0, FDF_STRING|FDF_RW, 0, GET_Location, SET_Location }, END_FIELD }; /*********************************************************************************** ** Print actions */ static ERROR PRINT_Activate(struct Print *, APTR); static ERROR PRINT_ClosingTag(struct Print *, APTR); static ERROR PRINT_DataChannel(struct Print *, struct acDataChannel *); static ERROR PRINT_Free(struct Print *, APTR); static ERROR PRINT_ReleaseObject(struct Print *, APTR); static struct ActionArray PrintActions[] = { { AC_Activate, PRINT_Activate }, { AC_ClosingTag, PRINT_ClosingTag }, { AC_DataChannel, PRINT_DataChannel }, { AC_Free, PRINT_Free }, { AC_ReleaseObject, PRINT_ReleaseObject }, { NULL, NULL } }; /***************************************************************************** ** User Instructions. */ static BYTE PrintUsage[] = { "USAGE: print [location|src]=filename\n\ \n\ This simple command will print the data of any text file that\n\ you specify.\n" }; /***************************************************************************** ** Command: Init() */ static ERROR CMDInit(OBJECTPTR argModule, struct KernelBase *argKernelBase) { KernelBase = argKernelBase; if (CreateObject(ID_MODULE, NULL, &StringsMod, NULL, FID_Name|TSTRING, "strings", TAGEND) IS ERR_Okay) { if (GetField(StringsMod, FID_ModBase, FT_POINTER, &StringsBase) != ERR_Okay) { return(ObjectError(argModule, ERH_InitModule, ERR_GetField)); } } else return(ObjectError(argModule, ERH_InitModule, ERR_CreateObject)); return(CreateObject(ID_CLASS, NULL, (OBJECTPTR *)&PrintClass, NULL, FID_BaseClassID|TLONG, ID_PRINT, FID_Version|TFLOAT, VER_PRINT, FID_Name|TSTRING, "Print", FID_Category|TLONG, CCF_COMMAND, FID_Usage|TPTR, PrintUsage, FID_Actions|TPTR, PrintActions, FID_Fields|TPTR, PrintFields, FID_Size|TLONG, sizeof(struct Print), TAGEND)); } /***************************************************************************** ** Command: Expunge() */ ERROR CMDExpunge(void) { if (StringsMod) { Action(AC_Free, StringsMod, NULL); StringsMod = NULL; } if (PrintClass) { Action(AC_Free, PrintClass, NULL); PrintClass = NULL; } return(ERR_Okay); } /***************************************************************************** ###ACTION### Name: Activate Short: Performs the printing process. ###DESCRIPTION### <p>Activating a print object results in the internal data or file contents being sent to the object specified in the <a href="#Object">Object</a> field. If the Object field has not been set then an attempt will be made to send the output to the object referenced in the <a href="#Output">Output</a> field.</p> ###END### *****************************************************************************/ static ERROR PRINT_Activate(struct Print *Self, APTR Void) { struct acRead read; struct acDataChannel channel; OBJECTPTR File; ERROR error; if (!Self->ObjectID) { if (!Self->OutputID) return(ObjectError(Self, ERH_Activate, ERR_FieldNotSet)); else Self->ObjectID = Self->OutputID; } if (Self->DataMID) { if (GetField(Self, FID_Data, FT_POINTER, &Self->Data) IS ERR_Okay) { channel.ObjectID = GetUniqueID(Self); channel.DataType = DATA_TEXT; channel.Version = 1; channel.Buffer = Self->Data; for (channel.Size=0; Self->Data[channel.Size]; channel.Size++); channel.TotalEntries = 1; error = ActionMsg(AC_DataChannel, Self->ObjectID, &channel); } else error = ObjectError(Self, ERH_Activate, ERR_GetField); } else if (Self->Location) { if (CreateObject(ID_FILE, NULL, &File, NULL, FID_Flags|TLONG, FL_READ, FID_Location|TSTRING, Self->Location, TAGEND) IS ERR_Okay) { GetField(File, FID_Size, FT_LONG, &read.Length); if (AllocMemory(read.Length+1, MEM_STRING|MEM_NOCLEAR, (APTR *)&read.Buffer, NULL) IS ERR_Okay) { if (Action(AC_Read, File, &read) IS ERR_Okay) { ((STRING)read.Buffer)[read.Length] = 0; /*** Send the data through to the Object ***/ channel.ObjectID = GetUniqueID(Self); channel.DataType = DATA_TEXT; channel.Version = 1; channel.Buffer = read.Buffer; channel.Size = read.Result; channel.TotalEntries = 1; error = ActionMsg(AC_DataChannel, Self->ObjectID, &channel); } else error = ObjectError(Self, ERH_Activate, ERR_Read); FreeMemory(read.Buffer); } else error = ObjectError(Self, ERH_Activate, ERR_Memory); Action(AC_Free, File, NULL); } else error = ObjectError(Self, ERH_Activate, ERR_NewObject); } else error = ObjectError(Self, ERH_Activate, ERR_FieldNotSet); return(error); } /***************************************************************************** ** Action: ClosingTag */ static ERROR PRINT_ClosingTag(struct Print *Self, APTR Void) { if (Self->Static IS FALSE) { Action(AC_Activate, Self, NULL); Action(AC_Free, Self, NULL); return(ERR_Okay); } else return(ERR_Okay); } /***************************************************************************** ###ACTION### Name: DataChannel Short: The Print class accepts text data through this action. ###END### *****************************************************************************/ static ERROR PRINT_DataChannel(struct Print *Self, struct acDataChannel *Args) { if (Self->ObjectID) return(ActionMsg(AC_DataChannel, Self->ObjectID, Args)); else return(ObjectError(Self, ERH_DataChannel, ERR_FieldNotSet)); } /***************************************************************************** ** Print: Free */ static ERROR PRINT_Free(struct Print *Self, APTR Void) { if (Self->Data) { ReleaseMemory(Self->Data); Self->Data = NULL; } if (Self->Location) { ReleaseMemory(Self->Location); Self->Location = NULL; } if (Self->DataMID) { FreeMemoryID(Self->DataMID); Self->DataMID = NULL; } if (Self->LocationMID) { FreeMemoryID(Self->LocationMID); Self->LocationMID = NULL; } return(ERR_Okay); } /***************************************************************************** ** Print: ReleaseObject */ static ERROR PRINT_ReleaseObject(struct Print *Self, APTR Void) { if (Self->Location) { ReleaseMemory(Self->Location); Self->Location = NULL; } if (Self->Data) { ReleaseMemory(Self->Data); Self->Data = NULL; } return(ERR_Okay); } /**************************************************************************** ###FIELD### Name: Data Synonyms: Text Short: The text information that you want to print. Type: STRING Status: Read/Write ###DESCRIPTION### <p>The text that you want to be printed should be written to this field. If the text is located in a file, you may use the Location field as an alternative to setting the Data field.</p> <p>The Data should be formatted as standard, printable ANSI text and may include return codes. Character codes such as backspace and delete are ignored.</p> ###SEE ALSO### Field: Location ###END### ****************************************************************************/ static ERROR GET_Data(struct Print *Self, STRING *Value) { if (Self->Data) { *Value = Self->Data; return(ERR_Okay); } else if (!Self->DataMID) { *Value = NULL; return(ERR_FieldNotSet); } else if (AccessMemory(Self->DataMID, MEM_READ, (void **)&Self->Data) IS ERR_Okay) { *Value = Self->Data; return(ERR_Okay); } else { *Value = NULL; return(ObjectError(Self, ERH_GetField, ERR_AccessMemory)); } } static ERROR SET_Data(struct Print *Self, STRING Value) { LONG i; if (Self->Data) { ReleaseMemory(Self->Data); Self->Data = NULL; } if (Self->DataMID) { FreeMemoryID(Self->DataMID); Self->DataMID = NULL; } if ((Value) AND (*Value)) { for (i=0; Value[i]; i++); if (AllocMemory(i+1, MEM_STRING|MEM_NOCLEAR|Self->Head.MemFlags, (void **)&Self->Data, &Self->DataMID) IS ERR_Okay) { for (i=0; Value[i]; i++) Self->Data[i] = Value[i]; Self->Data[i] = 0; } else return(ObjectError(Self, ERH_SetField, ERR_AllocMemory)); } return(ERR_Okay); } /**************************************************************************** ###FIELD### Name: Location Synonyms: Src Short: Set this field if the text originates from a file source. Type: STRING Status: Read/Write ###DESCRIPTION### <p>If the printable text is located in a text file, you may specify a pointer to that file by setting this field. If it is discovered that the file name does not exist when the print process takes place, nothing will be printed to the destination object.</p> ###SEE ALSO### Field: Data ###END### ****************************************************************************/ static ERROR GET_Location(struct Print *Self, STRING *Value) { if (Self->Location) { *Value = Self->Location; return(ERR_Okay); } else if (!Self->LocationMID) { *Value = NULL; return(ERR_FieldNotSet); } else if (AccessMemory(Self->LocationMID, MEM_READ, (void **)&Self->Location) IS ERR_Okay) { *Value = Self->Location; return(ERR_Okay); } else { *Value = NULL; return(ObjectError(Self, ERH_GetField, ERR_AccessMemory)); } } static ERROR SET_Location(struct Print *Self, STRING Value) { LONG i; if (Self->Location) { ReleaseMemory(Self->Location); Self->Location = NULL; } if (Self->LocationMID) { FreeMemoryID(Self->LocationMID); Self->LocationMID = NULL; } if ((Value) AND (*Value)) { for (i=0; Value[i]; i++); if (AllocMemory(i+1, MEM_STRING|MEM_NOCLEAR|Self->Head.MemFlags, (void **)&Self->Location, &Self->LocationMID) IS ERR_Okay) { for (i=0; Value[i]; i++) Self->Location[i] = Value[i]; Self->Location[i] = 0; } else return(ObjectError(Self, ERH_SetField, ERR_AllocMemory)); } return(ERR_Okay); } /**************************************************************************** ###FIELD### Name: Object Short: Refers to the object that will receive the text data. Type: OBJECTID Status: Read/Write ###DESCRIPTION### <p>In order to print the text information you will need to specify an object that will accept text data. The object must support the DataChannel action and include specific support for the handling of text data. It is recommended that you check the documentation for the class of the destination object to make sure that it is a suitable candidate. If the object does not meet the necessary requirements, the print process will do nothing.</p> ###END### ****************************************************************************/ /**************************************************************************** ###FIELD### Name: Output Short: Result messages will be sent to the object referred to in this field. Type: OBJECTID Status: Read/Write ###DESCRIPTION### <p>If this field is set to a valid ObjectID, text messages will be sent to the object when the print process executes. This can be helpful for notifying the user that an error has occurred during the print process.</p> <p>The object receiving the message must be capable of understanding text sent via data channels. In most cases it is recommended that a Text object is used for this purpose.</p> ###END### ****************************************************************************/ /**************************************************************************** ###FIELD### Name: Static Short: Set to TRUE to make the object static. Type: LONG Status: Read/Init ###DESCRIPTION### <p>By default, a Print object will execute itself and then self-destruct when a closing tag is received. If you would rather that the object stays in the system, set this field to TRUE. If you do this, the only way to get the Print object to perform is to call the Activate action.</p> ###END### ****************************************************************************/