exec.library: Allocate/Deallocate functions must remain generic and not handler MemHe...
[AROS.git] / workbench / c / shellcommands / Clip.c
blob5e8f93ecbf6b878244c125a0d184a9c683ed825e
1 /*
2 Copyright © 2011, The AROS Development Team. All rights reserved.
3 $Id:$
5 Desc:
6 Lang: English
7 */
9 /******************************************************************************
11 NAME
13 Clip
15 TEMPLATE
17 U=UNIT/N/K,W=WAIT/S,G=GET/S,P=PUT=S=SET/S,C=COUNT/S,TEXT
19 LOCATION
23 FUNCTION
25 Handle the clipboard's units (read or write text) from the Shell.
27 FORMAT
29 CLIP [COUNT] [UNIT <unit>] [ GET [WAIT] ] [ SET [TEXT] ]
31 RESULT
33 Standard DOS return codes.
36 ******************************************************************************/
38 #include <datatypes/textclass.h>
40 #include <proto/exec.h>
41 #include <proto/dos.h>
42 #include <proto/iffparse.h>
43 #include <proto/alib.h> // __sprintf()
45 //#define DEBUG 1
46 #include <aros/debug.h>
48 #define SH_GLOBAL_SYSBASE 1
49 #include <aros/shcommands.h>
52 * otigreat: Without having used the original Clip, it's not clear if
53 * > C:Clip SET
54 * has to set an empty clip unit, or to delete the said clip unit. Though the
55 * latter seems more elegant. Without CLIP_SET_NO_TEXT_MEANS_DELETE_UNIT you
56 * get the other behaviour. The current one, however, also allows to obtain an
57 * empty clip unit by doing:
58 * > C:Clip SET ""
60 #define CLIP_SET_NO_TEXT_MEANS_DELETE_UNIT 1
62 BOOL toClip(STRPTR text, UBYTE clipUnit, struct Library *IFFParseBase);
63 STRPTR fromClip(UBYTE clipUnit, struct Library *IFFParseBase);
65 AROS_SH6H(Clip,50.1, "read from or write to clipboard\n",
66 AROS_SHAH(LONG *,U= ,UNIT,/N/K,NULL , "Clipboard unit to be used by GET or SET (default = 0)\n"
67 "\t\tUNIT must be between 0 and 255"),
68 AROS_SHAH(BOOL ,W= ,WAIT ,/S,FALSE, "Make GET wait for the UNIT to be filled with text data"),
69 AROS_SHAH(BOOL ,G= ,GET ,/S,FALSE,"\tRetrieve text data from the UNIT"),
70 AROS_SHAH(BOOL ,P=PUT=S=,SET,/S,FALSE, "Store supplied TEXT data in the UNIT"),
71 AROS_SHAH(BOOL ,C= ,COUNT ,/S,FALSE, "Output the number of filled units"),
72 AROS_SHAH(STRPTR, ,TEXT , ,NULL ,"\tText data to be SET in the UNIT, requires to be quoted\n"
73 "\t\tif there is more than a single word\n") )
75 AROS_SHCOMMAND_INIT
77 int rc = RETURN_FAIL;
78 BOOL get = ((SHArg(GET)) || (!SHArg(SET) && !SHArg(COUNT)));
79 BYTE waitSig;
80 UBYTE unit, clipUnitPath[10]; /* "CLIPS:255\0" */
81 ULONG waitMask, sigs;
82 STRPTR outstr = NULL;
83 struct Library *IFFParseBase;
84 struct NotifyRequest *clipUnitNR;
86 if (!SHArg(UNIT))
87 unit = PRIMARY_CLIP;
88 else if ((*SHArg(UNIT) < 0L) || (*SHArg(UNIT) > 255L))
90 PrintFault(ERROR_BAD_NUMBER, (CONST_STRPTR)"Clip");
91 return (RETURN_ERROR);
93 else
94 unit = *SHArg(UNIT);
96 if ((IFFParseBase = OpenLibrary((STRPTR)"iffparse.library", 36)))
98 __sprintf(clipUnitPath, (const UBYTE *)"CLIPS:%d", unit);
99 D(bug("[Clip] clipUnitPath == '%s'\n", clipUnitPath));
101 if(get && SHArg(WAIT))
103 if((waitSig = AllocSignal(-1L)) != -1)
105 if ((clipUnitNR = AllocMem(sizeof(struct NotifyRequest), MEMF_CLEAR)))
107 waitMask = 1L << waitSig;
109 clipUnitNR->nr_Name = clipUnitPath;
110 clipUnitNR->nr_Flags = NRF_SEND_SIGNAL;
111 clipUnitNR->nr_stuff.nr_Signal.nr_Task = FindTask(NULL);
112 clipUnitNR->nr_stuff.nr_Signal.nr_SignalNum = waitSig;
114 StartNotify(clipUnitNR);
115 sigs = Wait(waitMask | SIGBREAKF_CTRL_C);
116 EndNotify(clipUnitNR);
117 FreeMem(clipUnitNR, sizeof(struct NotifyRequest));
119 if (sigs & SIGBREAKF_CTRL_C)
121 SetIoErr(ERROR_BREAK);
122 rc = RETURN_ERROR;
124 else
125 rc = RETURN_OK;
126 } /* if ((clipUnitNR = AllocMem(sizeof(struct NotifyRequest), MEMF_CLEAR))) */
127 FreeSignal(waitSig);
128 } /* if((waitSig = AllocSignal(-1L)) != -1) */
129 else
131 /* :-/ AllocSignal() doesn't SetIoErr() on error... but what is the right error to set? */
132 SetIoErr(ERROR_NO_FREE_STORE);
134 } /* if(SHArg(GET) && SHArg(WAIT)) */
136 /* We don't want to proceed if we had to WAIT and it failed... */
137 if (!(SHArg(WAIT) && (rc != RETURN_OK)))
139 if (get)
141 if ((outstr = fromClip(unit, IFFParseBase)))
143 PutStr(outstr);
144 FreeVec(outstr);
145 FPutC(Output(), '\n');
146 rc = RETURN_OK;
148 else
149 rc = RETURN_ERROR;
152 if (SHArg(SET))
154 #if CLIP_SET_NO_TEXT_MEANS_DELETE_UNIT
155 if (!SHArg(TEXT))
157 if (DeleteFile(clipUnitPath) || (IoErr() == ERROR_OBJECT_NOT_FOUND))
158 rc = RETURN_OK;
160 else
161 #endif
163 if (toClip(SHArg(TEXT), unit, IFFParseBase))
164 rc = RETURN_OK;
165 else
166 rc = RETURN_ERROR;
170 /* There must be a better way??? */
171 if (SHArg(COUNT))
173 UBYTE count = 0;
174 BPTR handle;
175 unit = PRIMARY_CLIP;
178 __sprintf(clipUnitPath, (const UBYTE *)"CLIPS:%d", unit);
179 if ((handle = Open(clipUnitPath, MODE_OLDFILE)) || (IoErr() != ERROR_OBJECT_NOT_FOUND))
181 count++;
182 if (handle)
183 Close(handle);
185 } while (unit++ < 255);
186 Printf((STRPTR)"%d\n", count);
187 rc = RETURN_OK;
189 } /* if (!(SHArg(WAIT) && (rc != RETURN_OK))) */
190 CloseLibrary(IFFParseBase);
191 } /* if ((IFFParseBase = OpenLibrary((STRPTR)"iffparse.library", 36))) */
193 if (rc != RETURN_OK)
194 PrintFault(IoErr(), (CONST_STRPTR)"Clip");
196 return (rc);
198 AROS_SHCOMMAND_EXIT
202 BOOL toClip(STRPTR text, UBYTE clipUnit, struct Library *IFFParseBase)
204 struct IFFHandle *iff;
205 ULONG len;
206 BOOL ok = FALSE;
208 if ((iff = AllocIFF()))
210 if ((iff->iff_Stream = (IPTR)OpenClipboard(clipUnit)))
212 InitIFFasClip(iff);
214 if (!OpenIFF(iff, IFFF_WRITE))
216 if (!PushChunk(iff, ID_FTXT, ID_FORM, IFFSIZE_UNKNOWN))
218 if (!PushChunk(iff, 0, ID_CHRS, IFFSIZE_UNKNOWN))
220 len = text ? strlen((char *)text) : 0; /* strlen() crashes if text == NULL */
222 if (WriteChunkBytes(iff, text, len) == len)
224 ok = TRUE;
226 PopChunk(iff);
227 } /* if (!PushChunk(iff, 0, ID_CHRS, IFFSIZE_UNKNOWN)) */
228 PopChunk(iff);
229 } /* if (!PushChunk(iff, ID_FTXT, ID_FORM, IFFSIZE_UNKNOWN)) */
230 CloseIFF(iff);
231 } /* if (!OpenIFF(iff, IFFF_WRITE)) */
232 CloseClipboard((struct ClipboardHandle*)iff->iff_Stream);
233 } /* if ((iff->iff_Stream = (IPTR)OpenClipboard(clipUnit))) */
234 FreeIFF(iff);
235 } /* if (iff) */
237 return (ok);
241 STRPTR fromClip(UBYTE clipUnit, struct Library *IFFParseBase)
243 struct IFFHandle *iff;
244 struct ContextNode *cn;
245 STRPTR filebuffer = NULL,
246 new_filebuffer = NULL;
247 ULONG filebuffer_size = 0;
248 LONG error;
249 BOOL ok = FALSE;
251 iff = AllocIFF();
252 if (iff)
254 if ((iff->iff_Stream = (IPTR)OpenClipboard(clipUnit)))
256 InitIFFasClip(iff);
258 if (!OpenIFF(iff, IFFF_READ))
260 if (!StopChunk(iff, ID_FTXT, ID_CHRS))
262 for(;;)
264 error = ParseIFF(iff, IFFPARSE_SCAN);
266 if ((error != 0) && (error != IFFERR_EOC))
267 break;
269 if (NULL == (cn = CurrentChunk(iff)))
271 kprintf("[Clip] ZERO CONTEXTNODE!!!\n\n");
272 continue;
275 if ((cn->cn_Type == ID_FTXT) && (cn->cn_ID == ID_CHRS))
277 if (!filebuffer)
279 if (NULL == (filebuffer = AllocVec(cn->cn_Size + 1, MEMF_ANY)))
280 break;
282 ok = TRUE;
284 else
286 if (NULL == (new_filebuffer = AllocVec(filebuffer_size + cn->cn_Size + 1, MEMF_ANY)))
288 ok = FALSE;
289 break;
292 CopyMem(filebuffer, new_filebuffer, filebuffer_size);
293 FreeVec(filebuffer);
294 filebuffer = new_filebuffer;
297 if (ReadChunkBytes(iff, filebuffer + filebuffer_size, cn->cn_Size) != cn->cn_Size)
299 ok = FALSE;
300 break;
303 filebuffer_size += cn->cn_Size;
304 filebuffer[filebuffer_size] = '\0';
305 } /* if ((cn->cn_Type == ID_FTXT) && (cn->cn_ID == ID_CHRS)) */
306 } /* for(;;) */
308 if (filebuffer && !ok) {
309 FreeVec(filebuffer);
310 filebuffer = NULL;
312 } /* if (!StopChunk(iff, ID_FTXT, ID_CHRS)) */
313 CloseIFF(iff);
314 } /* if (!OpenIFF(iff, IFFF_READ)) */
315 CloseClipboard((struct ClipboardHandle*)iff->iff_Stream);
316 } /* if ((iff->iff_Stream = (IPTR)OpenClipboard(clipUnit))) */
317 FreeIFF(iff);
318 } /* if (iff) */
320 return (filebuffer);