/* * ClipTool (Udklipsværktøj) - A Commodities Exchange Application * Copyright (C) 1994 Torsten Poulin * * buffers.c - the text buffer and clipboard routines. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * The author can be contacted by mail at * Torsten Poulin * Banebrinken 99, 2, 77 * DK-2400 Copenhagen NV * Denmark * or via email: torsten@diku.dk * * $Log: buffers.c,v $ * Revision 1.1 94/02/20 21:30:22 Torsten * Initial revision * */ static char const RCSid[] = "$Id: buffers.c,v 1.1 94/02/20 21:30:22 Torsten Exp $"; #include "cliptool.h" #include "ctstrings.h" #define ID_FTXT MAKE_ID('F','T','X','T') #define ID_CHRS MAKE_ID('C','H','R','S') struct bufferlisthead *currentbuffer; long ntotal, ncurrent; static struct bufferlisthead *firstlisthead; static struct bufferlisthead *lastlisthead; static void inserttextbuffer(struct textbuffer *); static void disposelistheader(void); static void readFTXTclip(struct textbuffer **); static void writeFTXTclip(struct textbuffer *); static BOOL readTEXTfile(UBYTE *, struct textbuffer **); static BOOL readFTXTfile(UBYTE *, struct textbuffer **); static BOOL writeTEXTfile(UBYTE *, struct textbuffer *); static BOOL writeFTXTfile(UBYTE *, struct textbuffer *); static void storetext(struct textbuffer **, UBYTE *, long); static void addicon(UBYTE *, BOOL); /* * Move to the previous text buffer list. */ void prevtext(void) { if (firstlisthead && firstlisthead != lastlisthead) { if (currentbuffer->prev) { currentbuffer = currentbuffer->prev; ncurrent--; } else { currentbuffer = lastlisthead; /* wrap around */ ncurrent = ntotal; } updatetitlebar(); showtext(); } } /* * Move to the next text buffer list. */ void nexttext(void) { if (firstlisthead && firstlisthead != lastlisthead) { if (currentbuffer->next) { currentbuffer = currentbuffer->next; ncurrent++; } else { currentbuffer = firstlisthead; /* wrap around */ ncurrent = 1; } updatetitlebar(); showtext(); } } /* * Private function to insert a new text buffer list * at the end of the header list. */ static void inserttextbuffer(struct textbuffer *tb) { struct bufferlisthead *newblh; if (tb) { if (newblh = malloc(sizeof(struct bufferlisthead))) { newblh->tb = tb; newblh->next = NULL; newblh->prev = lastlisthead; if (lastlisthead) lastlisthead->next = newblh; else firstlisthead = newblh; currentbuffer = lastlisthead = newblh; ncurrent = ++ntotal; updatetitlebar(); } } } /* * Private function to dispose a buffer list header * and move the current buffer header one step forward. */ static void disposelistheader(void) { if (currentbuffer) { /* list isn't empty */ if (currentbuffer == firstlisthead) { if (currentbuffer == lastlisthead) { free(currentbuffer); /* disposing the only header */ currentbuffer = firstlisthead = lastlisthead = NULL; ncurrent = ntotal = 0; } else { firstlisthead = currentbuffer->next; currentbuffer->next->prev = NULL; free(currentbuffer); /* disposing first header */ currentbuffer = firstlisthead; ncurrent = 1; ntotal--; } } else if (currentbuffer == lastlisthead) { lastlisthead = currentbuffer->prev; currentbuffer->prev->next = NULL; free(currentbuffer); /* disposing the last header */ currentbuffer = firstlisthead; ncurrent = 1; ntotal--; } else { struct bufferlisthead *temp = currentbuffer; currentbuffer = currentbuffer->next; temp->prev->next = temp->next; temp->next->prev = temp->prev; free(temp); /* disposing interior header */ ntotal--; } updatetitlebar(); } } /* * move the contents of the current buffer to the clipboard. */ void cut(void) { if (currentbuffer) { writeFTXTclip(currentbuffer->tb); freetext(); } } /* * copy the contents of the current buffer to the clipboard. */ void copy(void) { if (currentbuffer) writeFTXTclip(currentbuffer->tb); } /* * Store the contents of the clipboard in the * buffer list, and update the display. */ void paste(void) { struct textbuffer *tb = NULL; readFTXTclip(&tb); inserttextbuffer(tb); showtext(); } /* * This function removes the current buffer from * the list and frees the memory it occupied. */ void freetext(void) { struct textbuffer *tb, *temp; if (currentbuffer) { tb = currentbuffer->tb; while (tb) { temp = tb->next; free(tb); tb = temp; } disposelistheader(); showtext(); } } /* * This is a rather simplistic implementation of storetext(). * It relies on the fact that SAS/C requests memory from the * system pool in relatively large chunks to reduce fragmentation. */ static void storetext(struct textbuffer **root, UBYTE *buf, long rlen) { static struct textbuffer *last; struct textbuffer *tb; if (tb = malloc(sizeof(struct textbuffer) + rlen)) { tb->next = NULL; tb->length = rlen - 1; memcpy(tb->data, buf, rlen); if (!*root) *root = tb; else last->next = tb; last = tb; } } static void readFTXTclip(struct textbuffer **tbptr) { struct IFFHandle *iff; struct ContextNode *cn; long rlen; long error = 0; UBYTE readbuf[RBUFSZ]; if (iff = AllocIFF()) { if (iff->iff_Stream = (ULONG) OpenClipboard(unitnumber)) { InitIFFasClip(iff); if (!OpenIFF(iff, IFFF_READ)) { if (!StopChunk(iff, ID_FTXT, ID_CHRS)) { for (;;) { if ((error = ParseIFF(iff, IFFPARSE_SCAN)) == IFFERR_EOC) continue; /* go to the next context */ else if (error) break; cn = CurrentChunk(iff); if (cn && cn->cn_Type == ID_FTXT && cn->cn_ID == ID_CHRS) { while ((rlen = ReadChunkBytes(iff, readbuf, RBUFSZ)) > 0) storetext(tbptr, readbuf, rlen); } } } CloseIFF(iff); } CloseClipboard((struct ClipboardHandle *) iff->iff_Stream); } FreeIFF(iff); } } static void writeFTXTclip(struct textbuffer *tb) { struct IFFHandle *iff; if (iff = AllocIFF()) { if (iff->iff_Stream = (ULONG) OpenClipboard(unitnumber)) { InitIFFasClip(iff); if (!OpenIFF(iff, IFFF_WRITE)) { /* write FORM FTXT */ if (!PushChunk(iff, ID_FTXT, ID_FORM, IFFSIZE_UNKNOWN)) { for (; tb; tb = tb->next) { /* write a CHRS chunk... */ if (!PushChunk(iff, 0, ID_CHRS, tb->length)) { /* ...followed by its chunk data */ if (WriteChunkBytes(iff,tb->data,tb->length) != tb->length) break; PopChunk(iff); } } PopChunk(iff); } CloseIFF(iff); } CloseClipboard((struct ClipboardHandle *) iff->iff_Stream); } FreeIFF(iff); } } static BOOL readTEXTfile(UBYTE *fname, struct textbuffer **tbptr) { long rlen; UBYTE readbuf[RBUFSZ]; BPTR file; if (file = Open(fname, MODE_OLDFILE)) { while ((rlen = Read(file, readbuf, RBUFSZ)) > 0) storetext(tbptr, readbuf, rlen); Close(file); } else return FALSE; return TRUE; } static BOOL readFTXTfile(UBYTE *fname, struct textbuffer **tbptr) { struct IFFHandle *iff; struct ContextNode *cn; long rlen; long error = 0; UBYTE readbuf[RBUFSZ]; if (iff = AllocIFF()) { if (iff->iff_Stream = Open(fname, MODE_OLDFILE)) { InitIFFasDOS(iff); if (!(error = OpenIFF(iff, IFFF_READ))) { if (!(error = StopChunk(iff, ID_FTXT, ID_CHRS))) { for (;;) { if ((error = ParseIFF(iff, IFFPARSE_SCAN)) == IFFERR_EOC) continue; /* go to the next context */ else if (error) break; cn = CurrentChunk(iff); if (cn && cn->cn_Type == ID_FTXT && cn->cn_ID == ID_CHRS) { while ((rlen = ReadChunkBytes(iff, readbuf, RBUFSZ)) > 0) storetext(tbptr, readbuf, rlen); } } } CloseIFF(iff); } Close(iff->iff_Stream); } FreeIFF(iff); } return (BOOL) (error ? FALSE : TRUE); } static BOOL writeTEXTfile(UBYTE *fname, struct textbuffer *tb) { BPTR file; if (file = Open(fname, MODE_NEWFILE)) { for (; tb; tb = tb->next) { if (Write(file, tb->data, tb->length) != tb->length) break; } Close(file); addicon(fname, FALSE); } else return FALSE; return TRUE; } static BOOL writeFTXTfile(UBYTE *fname, struct textbuffer *tb) { struct IFFHandle *iff; long error = 0; if (iff = AllocIFF()) { if (iff->iff_Stream = Open(fname, MODE_NEWFILE)) { InitIFFasDOS(iff); if (!(error = OpenIFF(iff, IFFF_WRITE))) { /* write FORM FTXT */ if (!(error = PushChunk(iff, ID_FTXT, ID_FORM, IFFSIZE_UNKNOWN))) { for (; tb; tb = tb->next) { /* write a CHRS chunk... */ if (!PushChunk(iff, 0, ID_CHRS, tb->length)) { /* ...followed by its chunk data */ if (WriteChunkBytes(iff,tb->data,tb->length) != tb->length) { error = IFFERR_WRITE; break; } PopChunk(iff); } } PopChunk(iff); } CloseIFF(iff); } Close(iff->iff_Stream); } FreeIFF(iff); addicon(fname, TRUE); } return (BOOL) (error ? FALSE : TRUE); } void loaddropped(UBYTE *fname, BPTR dirlock) { BPTR curdirlock; struct textbuffer *tb = NULL; BOOL ok; curdirlock = CurrentDir(dirlock); if (!(ok = readFTXTfile(fname, &tb))) ok = readTEXTfile(fname, &tb); if (!ok) msgreq(ls(MSG_FILE_ACCESS_ERROR), fname); else { inserttextbuffer(tb); showtext(); } CurrentDir(curdirlock); } void loadtext(BOOL asFTXT) { BPTR curdirlock, dirlock; struct textbuffer *tb = NULL; BOOL ok; if (AslRequestTags(filereq, ASL_Hail, (asFTXT ? ls(MSG_LOADFTXT) : ls(MSG_LOADTEXT)), ASL_FuncFlags, 0, ASL_Window, guiwin, TAG_END)) { if (dirlock = Lock(filereq->rf_Dir, SHARED_LOCK)) { curdirlock = CurrentDir(dirlock); if (asFTXT) ok = readFTXTfile(filereq->rf_File, &tb); else ok = readTEXTfile(filereq->rf_File, &tb); if (!ok) msgreq(ls(MSG_FILE_ACCESS_ERROR), filereq->rf_File); else { inserttextbuffer(tb); showtext(); } CurrentDir(curdirlock); UnLock(dirlock); } } } /* * Save the contents of the current buffer list, * either as text or FTXT depending on 'asFTXT'. */ void savetext(BOOL asFTXT) { BPTR curdirlock, dirlock; BOOL ok; if (currentbuffer) { if (AslRequestTags(filereq, ASL_Hail, (asFTXT ? ls(MSG_SAVEASFTXT) : ls(MSG_SAVEASTEXT)), ASL_FuncFlags, FILF_SAVE, ASL_Window, guiwin, TAG_END)) { if (dirlock = Lock(filereq->rf_Dir, SHARED_LOCK)) { curdirlock = CurrentDir(dirlock); if (asFTXT) ok = writeFTXTfile(filereq->rf_File, currentbuffer->tb); else ok = writeTEXTfile(filereq->rf_File, currentbuffer->tb); if (!ok) msgreq(ls(MSG_FILE_ACCESS_ERROR), filereq->rf_File); CurrentDir(curdirlock); UnLock(dirlock); } } } } /* * This function is used by the ARexx interface to load a file. * IFF FTXT files are handled transparently. */ void rxload(UBYTE *fname, UBYTE *dname) { BPTR curdirlock, dirlock; struct textbuffer *tb = NULL; if (dirlock = Lock(dname, SHARED_LOCK)) { curdirlock = CurrentDir(dirlock); if (!readFTXTfile(fname, &tb)) readTEXTfile(fname, &tb); inserttextbuffer(tb); showtext(); CurrentDir(curdirlock); UnLock(dirlock); } } /* * This function is used by the ARexx interface to save a file. */ void rxsave(UBYTE *fname, UBYTE *dname, BOOL asFTXT) { BPTR curdirlock, dirlock; if (currentbuffer) { if (dirlock = Lock(dname, SHARED_LOCK)) { curdirlock = CurrentDir(dirlock); if (asFTXT) writeFTXTfile(fname, currentbuffer->tb); else writeTEXTfile(fname, currentbuffer->tb); CurrentDir(curdirlock); UnLock(dirlock); } } } static void addicon(UBYTE *fname, BOOL ftxt) { struct DiskObject *diskobj; synchronizechecked(); /* just in case... */ if (createicons) if (diskobj = GetDefDiskObject(WBPROJECT)) { PutDiskObject(fname, diskobj); FreeDiskObject(diskobj); } }