Test kernel compiler for -iquote instead of target compiler script that
[tangerine.git] / workbench / c / Assign.c
blob0111383048135a23b4c95df98a9669b05abeba66
1 /*
3 (C) 1995-2001 AROS - The Amiga Research OS
4 (C) 2002-2005 Harry Sintonen
5 (C) 2005-2007 Pavel Fedin
6 $Id: Assign.c,v 1.6 2007/09/21 06:51:45 sonic_amiga Exp $
8 Desc: Assign CLI command
9 Lang: English
13 /******************************************************************************
15 NAME
17 Assign
19 USAGE
21 Assign [(name):] [{(target)}] [LIST] [EXISTS] [DISMOUNT] [DEFER]
23 SYNOPSIS
25 NAME, TARGET/M, LIST/S, EXISTS/S, DISMOUNT/S, DEFER/S, PATH/S, ADD/S,
26 REMOVE/S, VOLS/S, DIRS/S, DEVICES/S
28 LOCATION
30 Sys:C
32 FUNCTION
34 ASSIGN creates a reference to a file or directory. The reference
35 is a logical device name which makes it very convenient to specify
36 assigned objects using the reference instead of their paths.
37 If the NAME and TARGET arguments are given, ASSIGN assigns
38 the given logical name to the specified target. If the NAME given is
39 already assigned to a file or directory the new target replaces the
40 previous target.
41 A colon must be included after the NAME argument.
42 If only the NAME argument is given, any assigns to that NAME are
43 removed. If no arguments whatsoever are given, all logical assigns
44 are listed.
47 INPUTS
49 NAME -- the name that should be assigned to a file or dir
50 TARGET -- one or more files or directories to assign the NAME to
51 LIST -- list all assigns made
52 EXISTS -- if NAME is not assigned, set the condition flag to
53 WARN
54 DISMOUNT -- remove the volume or device NAME from the dos list
55 DEFER -- make an ASSIGN to a path or directory that not need to
56 exist at the time of assignment. The first time the NAME
57 is referenced the NAME is bound to the object
58 PATH -- path to assign with a non-binding assign. This mean
59 that the assign is re-evaluated each time a reference
60 to NAME is done. Like for DEFER, the path doesn't have
61 to exist when the ASSIGN command is executed
62 ADD -- don't replace an assign but add another object for a
63 NAME (multi-assigns)
64 REMOVE -- remove an ASSIGN
65 VOLS -- show assigned volumes if in LIST mode
66 DIRS -- show assigned directories if in LIST mode
67 DEVICES -- show assigned devices if in LIST mode
69 RESULT
71 NOTES
73 EXAMPLE
75 BUGS
77 SEE ALSO
79 INTERNALS
81 HISTORY
83 ******************************************************************************/
85 #define AROS_ALMOST_COMPATIBLE
87 #ifdef __AROS__
88 #include <aros/asmcall.h>
89 #include <proto/arossupport.h>
90 #else
91 #include <clib/debug_protos.h>
92 #endif
94 #include <exec/types.h>
95 #include <exec/lists.h>
96 #include <exec/memory.h>
97 #include <exec/execbase.h>
98 #include <dos/dos.h>
99 #include <dos/dosextens.h>
100 #include <dos/exall.h>
101 #include <utility/tagitem.h>
102 #include <proto/dos.h>
103 #include <proto/exec.h>
105 #include <string.h>
107 #define DEBUG_ASSIGN(x)
109 /******************************************************************************
112 NAME
114 Assign [(name):] [{(target)}] [LIST] [EXISTS] [DISMOUNT] [DEFER]
115 [PATH] [ADD] [REMOVE] [VOLS] [DIRS] [DEVICES]
117 SYNOPSIS
119 NAME, TARGET/M, LIST/S, EXISTS/S, DISMOUNT/S, DEFER/S, PATH/S, ADD/S,
120 REMOVE/S, VOLS/S, DIRS/S, DEVICES/S
122 LOCATION
124 Workbench:C
126 FUNCTION
128 ASSIGN creates a reference to a file or directory. The reference
129 is a logical device name which makes it very convenient to specify
130 assigned objects using the reference instead of their paths.
132 If the NAME and TARGET arguments are given, ASSIGN assigns the
133 given logical name to the specified target. If the NAME given is
134 already assigned to a file or directory the new target replaces the
135 previous target. A colon must be included after the NAME argument.
137 If only the NAME argument is given, any assigns to that NAME are
138 removed. If no arguments whatsoever are given, all logical
139 assigns are listed.
141 INPUTS
143 NAME -- the name that should be assigned to a file or directory
144 TARGET -- one or more files or directories to assign the NAME to
145 LIST -- list all assigns made
146 EXISTS -- if NAME is not assigned, set the condition flag to
147 WARN
148 DISMOUNT -- remove the volume or device NAME from the dos list
149 DEFER -- make an ASSIGN to a path or directory that not need to
150 exist at the time of assignment. The first time the
151 NAME is referenced the NAME is bound to the object
152 PATH -- path to assign with a non-binding assign. This means
153 that the assign is re-evaluated each time a reference
154 to NAME is done. Like for DEFER, the path doesn't have
155 to exist when the ASSIGN command is executed
156 ADD -- don't replace an assign but add another object for a
157 NAME (multi-assigns)
158 REMOVE -- remove an ASSIGN
159 VOLS -- show assigned volumes if in LIST mode
160 DIRS -- show assigned directories if in LIST mode
161 DEVICES -- show assigned devices if in LIST mode
164 RESULT
166 NOTES
168 EXAMPLE
170 BUGS
172 SEE ALSO
174 INTERNALS
176 The assign command has many switches. This together with the somewhat
177 messy handling of DosList:s by dos.library makes the operation rather
178 complicated.
180 There are some fundamental building blocks that defines the semantics
181 of the Assign command.
183 Only one of the switches ADD, REMOVE, PATH and DEFER may be specified.
185 If EXISTS is specified, only the name parameter is important.
187 The implementation is split up in two fundamental procedures.
189 doAssign() -- make [a number of] assigns
190 showAssigns() -- show the available assigns
191 checkAssign() -- check if a particular assign exists
193 HISTORY
195 ******************************************************************************/
197 #ifndef __AROS__
198 #define AROS_BSTR_strlen(s) *((UBYTE *)BADDR(s))
199 #endif
201 #ifdef __MORPHOS__
202 #define AROS_ASMSYMNAME(s) (&s)
204 static const int __abox__ = 1;
205 static const char version[] = "\0$VER: Assign unofficial 50.9 (18.10.07) © AROS" ;
206 #else
207 static const char version[] = "\0$VER: Assign 50.9 (18.10.07) © AROS" ;
208 #endif
210 struct localdata
212 struct ExecBase *ld_SysBase;
213 struct DosLibrary *ld_DOSBase;
214 struct MinList ld_DeferList;
217 #define SysBase ld->ld_SysBase
218 #define DOSBase ld->ld_DOSBase
219 #define DeferList ld->ld_DeferList
222 /* Prototypes */
224 static int Main(struct ExecBase *sBase);
225 static int checkAssign(struct localdata *ld, STRPTR name);
226 static int doAssign(struct localdata *ld, STRPTR name, STRPTR *target, BOOL dismount, BOOL defer, BOOL path,
227 BOOL add, BOOL remove);
228 static void showAssigns(struct localdata *ld, BOOL vols, BOOL dirs, BOOL devices);
229 static int removeAssign(struct localdata *ld, STRPTR name);
230 static STRPTR GetFullPath(struct localdata *ld, BPTR lock);
232 static void _DeferPutStr(struct localdata *ld, CONST_STRPTR str);
233 static void _DeferVPrintf(struct localdata *ld, CONST_STRPTR fmt, IPTR *args);
234 static void _DeferFlush(struct localdata *ld, BPTR fh);
236 #define DeferPutStr(str) _DeferPutStr(ld,str)
237 #define DeferPrintf(fmt,args...) \
238 DEBUG_ASSIGN(kprintf(fmt, ## args);) \
239 do { IPTR __args[] = {0 , ## args}; _DeferVPrintf(ld, fmt, __args + 1); } while (0)
240 #define DeferFlush(fh) _DeferFlush(ld,fh)
243 static
244 const UBYTE template[] =
245 "NAME,"
246 "TARGET/M,"
247 "LIST/S,"
248 "EXISTS/S,"
249 "DISMOUNT/S,"
250 "DEFER/S,"
251 "PATH/S,"
252 "ADD/S,"
253 "REMOVE/S,"
254 "VOLS/S,"
255 "DIRS/S,"
256 "DEVICES/S";
258 struct ArgList
260 STRPTR name;
261 STRPTR *target;
262 IPTR list;
263 IPTR exists;
264 IPTR dismount;
265 IPTR defer;
266 IPTR path;
267 IPTR add;
268 IPTR remove;
269 IPTR vols;
270 IPTR dirs;
271 IPTR devices;
274 #ifdef __AROS__
275 AROS_UFH3(__startup static int, Start,
276 AROS_UFHA(char *, argstr, A0),
277 AROS_UFHA(ULONG, argsize, D0),
278 AROS_UFHA(struct ExecBase *, sBase, A6))
280 AROS_USERFUNC_INIT
281 return Main(sBase);
282 AROS_USERFUNC_EXIT
284 #else
285 int Start(void)
287 struct ExecBase *sBase;
289 sBase = *((struct ExecBase **) 4);
290 return Main(sBase);
292 #endif
294 static int Main(struct ExecBase *sBase)
296 struct localdata _ld, *ld = &_ld;
297 struct RDArgs *readarg;
298 struct ArgList arglist;
299 struct ArgList *MyArgList = &arglist;
300 int error = RETURN_OK;
302 SysBase = sBase;
303 DOSBase = (struct DosLibrary *) OpenLibrary("dos.library",37);
304 if (DOSBase)
306 memset(&arglist, 0, sizeof(arglist));
308 NEWLIST(&DeferList);
310 readarg = ReadArgs(template, (IPTR *)MyArgList, NULL);
311 if (readarg)
313 /* Verify mutually exclusive args
315 if ((MyArgList->add!=0) + (MyArgList->remove!=0) + (MyArgList->path!=0) + (MyArgList->defer!=0) > 1)
317 PutStr("Only one of ADD, REMOVE, PATH or DEFER is allowed\n");
318 FreeArgs(readarg);
319 CloseLibrary((struct Library *) DOSBase);
320 return RETURN_FAIL;
323 /* Check device name
325 if (MyArgList->name)
327 char *pos;
329 /* Correct assign name construction? The rule is that the device name
330 * should end with a colon at the same time as no other colon may be
331 * in the name.
333 pos = strchr(MyArgList->name, ':');
334 if (!pos || pos[1])
336 Printf("Invalid device name %s\n", (IPTR)MyArgList->name);
337 FreeArgs(readarg);
338 CloseLibrary((struct Library *) DOSBase);
339 return RETURN_FAIL;
343 /* If the EXISTS keyword is specified, we only care about NAME */
344 if (MyArgList->exists)
346 error = checkAssign(ld, MyArgList->name);
347 DEBUG_ASSIGN(Printf("checkassign error %ld\n",error));
349 else if (MyArgList->name)
351 /* If a NAME is specified, our primary task is to add or
352 remove an assign */
354 error = doAssign(ld, MyArgList->name, MyArgList->target, MyArgList->dismount, MyArgList->defer,
355 MyArgList->path, MyArgList->add, MyArgList->remove);
356 DEBUG_ASSIGN(Printf("doassign error %ld\n",error));
357 if (MyArgList->list)
359 /* With the LIST keyword, the current assigns will be
360 displayed also when (after) making an assign */
362 showAssigns(ld, MyArgList->vols, MyArgList->dirs, MyArgList->devices);
365 else
367 /* If no NAME was given, we just show the current assigns
368 as specified by the user (VOLS, DIRS, DEVICES) */
370 showAssigns(ld, MyArgList->vols, MyArgList->dirs, MyArgList->devices);
373 FreeArgs(readarg);
376 CloseLibrary((struct Library *) DOSBase);
379 DEBUG_ASSIGN(Printf("error %ld\n", error));
381 return error;
385 static
386 void showAssigns(struct localdata *ld, BOOL vols, BOOL dirs, BOOL devices)
388 ULONG lockBits = LDF_READ;
389 struct DosList *dl;
391 /* If none of the parameters are specified, everything should be
392 displayed */
393 if (!(vols || dirs || devices))
395 vols = TRUE;
396 dirs = TRUE;
397 devices = TRUE;
400 lockBits |= vols ? LDF_VOLUMES : 0;
401 lockBits |= dirs ? LDF_ASSIGNS : 0;
402 lockBits |= devices ? LDF_DEVICES : 0;
404 dl = LockDosList(lockBits);
406 #warning "FIXME: GetFullPath() breaks LockDosList()'s Forbid()!"
407 #warning "Note: This should be ok as long as we don't have ks 1.x compatibility."
409 if (vols)
411 struct DosList *tdl = dl;
413 DeferPutStr("Volumes:\n");
415 /* Print all mounted volumes */
416 while ((tdl = NextDosEntry(tdl, LDF_VOLUMES)))
418 DeferPrintf("%b [Mounted]\n", tdl->dol_Name);
422 if (dirs)
424 struct DosList *tdl = dl;
425 int count;
427 DeferPutStr("\nDirectories:\n");
429 /* Print all assigned directories */
430 while ((tdl = NextDosEntry(tdl, LDF_ASSIGNS)))
432 DeferPrintf("%b ", tdl->dol_Name);
434 for (count = 14 - AROS_BSTR_strlen(tdl->dol_Name); count > 0; count--)
436 DeferPutStr(" ");
439 switch (tdl->dol_Type)
441 case DLT_LATE:
442 DeferPrintf("<%s>\n", (IPTR)tdl->dol_misc.dol_assign.dol_AssignName);
443 break;
445 case DLT_NONBINDING:
446 DeferPrintf("[%s]\n", (IPTR)tdl->dol_misc.dol_assign.dol_AssignName);
447 break;
449 default:
451 STRPTR dirName; /* For NameFromLock() */
452 struct AssignList *nextAssign; /* For multiassigns */
454 dirName = GetFullPath(ld, tdl->dol_Lock);
456 if (dirName)
458 DeferPutStr(dirName);
459 FreeVec(dirName);
461 DeferPutStr("\n");
463 nextAssign = tdl->dol_misc.dol_assign.dol_List;
465 while (nextAssign)
467 dirName = GetFullPath(ld, nextAssign->al_Lock);
469 if (dirName)
471 DeferPrintf(" + %s\n", (IPTR)dirName);
472 FreeVec(dirName);
475 nextAssign = nextAssign->al_Next;
479 break;
481 } /* while (NextDosEntry()) */
484 if (devices)
486 struct DosList *tdl = dl;
487 int count = 0; /* Used to make sure that as most 5 entries are printed per line */
489 DeferPutStr("\nDevices:\n");
491 /* Print all assigned devices */
492 while ((tdl = NextDosEntry(tdl, LDF_DEVICES)))
494 DeferPrintf("%b%lc", tdl->dol_Name, ++count % 5 ? ' ' : '\n');
497 if (count % 5)
499 DeferPutStr("\n");
503 UnLockDosList(lockBits);
505 DeferFlush(Output());
509 static
510 STRPTR GetFullPath(struct localdata *ld, BPTR lock)
512 STRPTR buf; /* Pointer to the memory allocated for the string */
513 ULONG size; /* Holder of the (growing) size of the string */
515 for (size = 512; ; size += 512)
517 buf = AllocVec(size, MEMF_ANY);
518 if (!buf)
520 break;
523 if (NameFromLock(lock, buf, size))
525 return buf;
528 FreeVec(buf);
530 if (IoErr() != ERROR_LINE_TOO_LONG)
532 break;
536 return NULL;
540 static
541 int doAssign(struct localdata *ld, STRPTR name, STRPTR *target, BOOL dismount, BOOL defer, BOOL path,
542 BOOL add, BOOL remove)
544 STRPTR colon;
545 BPTR lock = NULL;
546 int i;
548 int error = RETURN_OK;
549 LONG ioerr = 0;
550 BOOL cancel = FALSE;
551 BOOL success = TRUE;
553 if (dismount)
555 #ifdef __AROS__
556 /* TODO: AROS currently doesn't support packet handlers directly
557 and we currently don't support shutting down IOFS handlers */
558 success = DOSFALSE;
559 ioerr = ERROR_ACTION_NOT_KNOWN;
560 #else
561 struct MsgPort *dp;
562 struct Process *tp;
564 tp=(struct Process *)FindTask(NULL);
565 tp->pr_WindowPtr = (APTR)-1;
566 dp = DeviceProc(name);
567 DEBUG_ASSIGN(Printf("doassign: dp <%08X>\n",dp));
568 if (dp)
570 success = DoPkt(dp,ACTION_DIE,0,0,0,0,0);
571 ioerr = IoErr();
572 DEBUG_ASSIGN(Printf("doassign: ACTION_DIE returned %ld\n",success));
574 #endif
577 colon = strchr(name, ':');
579 *colon = '\0'; /* Remove trailing colon; name[] is changed! */
581 DEBUG_ASSIGN(Printf("doassign: name <%s>\n", name));
583 /* This is a little bit messy... We first remove the 'name' assign
584 * and later in the loop the target assigns.
587 if (dismount)
589 if ((!success) && (ioerr == ERROR_ACTION_NOT_KNOWN))
591 struct DosList *dl;
592 struct DosList *fdl;
594 DEBUG_ASSIGN(PutStr("Removing device node\n"));
595 dl = LockDosList(LDF_VOLUMES | LDF_DEVICES | LDF_WRITE);
597 fdl = FindDosEntry(dl, name, LDF_VOLUMES | LDF_DEVICES);
599 /* Note the ! for conversion to boolean value */
600 if (fdl)
602 success = RemDosEntry(fdl);
603 if (success)
604 FreeDosEntry(fdl);
605 else
606 ioerr = ERROR_OBJECT_IN_USE;
607 } else
608 ioerr = ERROR_OBJECT_NOT_FOUND;
610 UnLockDosList(LDF_VOLUMES | LDF_DEVICES | LDF_WRITE);
613 else
615 if (target == NULL || *target == NULL)
617 error = removeAssign(ld, name);
618 if (error)
620 ioerr = IoErr();
621 cancel = TRUE;
626 /* AmigaDOS doesn't use RETURN_WARN here... but it should? */
627 error = success ? error : RETURN_WARN;
628 DEBUG_ASSIGN(Printf("error: %d\n", error));
630 // The Loop over multiple targets starts here
632 if (target)
634 for (i = 0; target[i]; i++)
636 cancel = FALSE;
638 DEBUG_ASSIGN(Printf("doassign: target <%s>\n", target[i]));
639 if (!(path || defer || dismount))
641 lock = Lock(target[i], SHARED_LOCK);
643 if (!lock)
645 Printf("Can't find %s\n", (IPTR)target[i]);
646 return RETURN_FAIL;
650 if (remove)
652 if (!RemAssignList(name, lock))
654 Printf("Can't subtract %s from %s\n", (IPTR)target[i], (IPTR)name);
655 error = RETURN_FAIL;
657 UnLock(lock);
659 else if (path)
661 if (!AssignPath(name, target[i]))
663 ioerr = IoErr();
664 error = RETURN_FAIL;
665 DEBUG_ASSIGN(Printf("doassign AssignPath error %ld\n",error));
668 else if (add)
670 if (!AssignAdd(name, lock))
672 struct DosList *dl;
674 error = RETURN_FAIL;
675 ioerr = IoErr();
676 DEBUG_ASSIGN(Printf("doassign AssignAdd error %ld\n",error));
678 /* Check if the assign doesn't exist at all. If so, create it.
679 * This fix bug id 145. - Piru
681 dl = LockDosList(LDF_ASSIGNS | LDF_READ);
682 dl = FindDosEntry(dl, name, LDF_ASSIGNS);
683 UnLockDosList(LDF_ASSIGNS | LDF_READ);
685 if (!dl)
687 if (AssignLock(name, lock))
689 error = RETURN_OK;
690 lock = NULL;
692 else
694 ioerr = IoErr();
695 DEBUG_ASSIGN(Printf("doassign AssignLock error %ld\n", error));
699 if (lock)
700 UnLock(lock);
702 if (error && ioerr != ERROR_OBJECT_EXISTS)
704 Printf("Can't add %s to %s\n", (IPTR)target[i], (IPTR)name);
708 else if (defer)
710 if (!AssignLate(name, target[i]))
712 ioerr = IoErr();
713 UnLock(lock);
714 error = RETURN_FAIL;
715 DEBUG_ASSIGN(Printf("doassign AssignLate error %ld\n",error));
718 else
720 /* If no extra parameters are specified we just do a regular
721 assign (replacing any possible previous assign with that
722 name. The case of target being NULL is taken care of above.
724 if (!AssignLock(name, lock))
726 ioerr = IoErr();
727 cancel = TRUE;
728 UnLock(lock);
729 error = RETURN_FAIL;
730 DEBUG_ASSIGN(Printf("doassign AssignLock error %ld\n",error));
732 /* If there are several targets, the next ones have to be added. */
733 add = TRUE;
736 /* We break as soon as we get a serious error */
737 if (error >= RETURN_FAIL)
739 break;
742 } /* loop through all targets */
745 if (error)
747 if (ioerr == ERROR_OBJECT_EXISTS)
749 Printf("Can't %s %s\n", (IPTR)(cancel ? "cancel" : "assign"), (IPTR)name);
751 else
753 PrintFault(ioerr, NULL);
757 return error;
761 static
762 int removeAssign(struct localdata *ld, STRPTR name)
764 /* In case no target is given, the 'name' assign should be removed.
765 * The AmigaDOS semantics for this is apparently that the error
766 * code is never set even if the assign didn't exist.
769 if (!AssignLock(name, NULL))
771 return RETURN_FAIL;
773 return RETURN_OK;
777 static
778 int checkAssign(struct localdata *ld, STRPTR name)
780 STRPTR colon;
781 struct DosList *dl;
782 int error = RETURN_OK;
784 if (!name)
785 name = "";
787 colon = strchr(name, ':');
788 if (colon)
790 *colon = '\0';
793 dl = LockDosList(LDF_DEVICES | LDF_ASSIGNS | LDF_VOLUMES | LDF_READ);
795 #warning "Note: GetFullPath() breaks LockDosList()'s Forbid()!"
796 #warning "Note: This should be ok as long as we don't have ks 1.x compatibility."
798 dl = FindDosEntry(dl, name, LDF_DEVICES | LDF_ASSIGNS | LDF_VOLUMES);
799 if (dl)
801 struct DosList *tdl = dl;
802 int count;
804 switch (dl->dol_Type)
806 case DLT_DEVICE:
807 DeferPrintf("%b\n", tdl->dol_Name);
808 break;
810 case DLT_VOLUME:
811 DeferPrintf("%b [Mounted]\n", tdl->dol_Name);
812 break;
814 case DLT_DIRECTORY:
815 case DLT_LATE:
816 case DLT_NONBINDING:
818 DeferPrintf("%b ", tdl->dol_Name);
820 for (count = 14 - *((UBYTE*)BADDR(tdl->dol_Name)); count > 0; count--)
822 DeferPutStr(" ");
825 switch (tdl->dol_Type)
827 case DLT_LATE:
828 DeferPrintf("<%s>\n", (IPTR)tdl->dol_misc.dol_assign.dol_AssignName);
829 break;
831 case DLT_NONBINDING:
832 DeferPrintf("[%s]\n", (IPTR)tdl->dol_misc.dol_assign.dol_AssignName);
833 break;
835 default:
837 STRPTR dirName; /* For NameFromLock() */
838 struct AssignList *nextAssign; /* For multiassigns */
840 dirName = GetFullPath(ld, tdl->dol_Lock);
842 if (dirName)
844 DeferPutStr(dirName);
845 FreeVec(dirName);
847 DeferPutStr("\n");
849 nextAssign = tdl->dol_misc.dol_assign.dol_List;
851 while (nextAssign)
853 dirName = GetFullPath(ld, nextAssign->al_Lock);
855 if (dirName)
857 DeferPrintf(" + %s\n", (IPTR)dirName);
858 FreeVec(dirName);
861 nextAssign = nextAssign->al_Next;
866 break;
869 else
871 DeferPrintf("%s: not assigned\n", (IPTR)name);
873 error = RETURN_WARN;
876 UnLockDosList(LDF_DEVICES | LDF_ASSIGNS | LDF_VOLUMES | LDF_READ);
878 DeferFlush(Output());
880 if (colon)
881 *colon = ':';
883 return error;
887 /* Feferred printing routines - Piru
890 #define MAXDEFERBUF 4096
891 #define MAXOUTPUT 128
892 struct deferbufnode
894 struct MinList node;
895 LONG pos;
896 UBYTE buf[MAXDEFERBUF];
899 static void deferputch(UBYTE ch, struct localdata *ld)
901 struct deferbufnode *cur;
903 if (!ch)
904 return;
906 cur = (struct deferbufnode *) GetTail(&DeferList);
908 if (!cur || cur->pos >= MAXDEFERBUF)
910 cur = AllocMem(sizeof(struct deferbufnode), MEMF_ANY);
911 if (!cur)
912 return;
914 cur->pos = 0;
916 ADDTAIL(&DeferList, cur);
919 cur->buf[cur->pos] = ch;
920 cur->pos++;
923 static
924 void _DeferPutStr(struct localdata *ld, CONST_STRPTR str)
926 UBYTE c;
928 DEBUG_ASSIGN(kprintf(str);)
929 while ((c = *str++))
931 deferputch(c, ld);
935 #ifdef __AROS__
936 AROS_UFH2(static void, deferputch_gate,
937 AROS_UFHA(UBYTE, ch, D0),
938 AROS_UFHA(struct localdata *, ld, A3))
940 AROS_USERFUNC_INIT
941 deferputch(ch, ld);
942 AROS_USERFUNC_EXIT
944 #endif
946 #ifdef __MORPHOS__
947 static
948 void deferputch_trampoline(void)
950 UBYTE ch = (UBYTE) REG_D0;
951 struct localdata *ld = (struct localdata *) REG_A3;
953 deferputch(ch, ld);
956 static
957 const struct EmulLibEntry deferputch_gate =
959 TRAP_LIBNR, 0, (void (*)(void)) deferputch_trampoline
961 #endif
963 static
964 void _DeferVPrintf(struct localdata *ld, CONST_STRPTR fmt, IPTR *args)
966 RawDoFmt(fmt, args, (void (*)(void))AROS_ASMSYMNAME(deferputch_gate), ld);
969 static
970 void _DeferFlush(struct localdata *ld, BPTR fh)
972 struct deferbufnode *node;
973 BOOL broken = FALSE;
975 Flush(fh);
977 while ((node = REMHEAD(&DeferList)))
979 LONG offs = 0;
980 LONG left = node->pos;
982 while (!broken && left)
984 LONG len;
986 if (SetSignal(0, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
988 broken = TRUE;
989 break;
992 len = left > MAXOUTPUT ? MAXOUTPUT : left;
994 Write(fh, node->buf + offs, len);
995 offs += len;
996 left -= len;
999 FreeMem(node, sizeof(struct deferbufnode));
1002 Flush(fh);
1004 if (broken)
1006 PrintFault(ERROR_BREAK, NULL);