New bitmap method SetRGBConversionFunction which can be used to
[tangerine.git] / workbench / c / shellcommands / Assign.c
blob662fe825b42badf23c9d58995fc5b479c8550350
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Assign CLI command
6 Lang: English
7 */
9 #define DEBUG 0
10 #include <aros/debug.h>
11 #include <aros/config.h>
13 #include <exec/types.h>
14 #include <exec/memory.h>
15 #include <exec/execbase.h>
16 #include <dos/dos.h>
17 #include <dos/dosextens.h>
18 #include <proto/dos.h>
19 #include <proto/exec.h>
20 #include <utility/tagitem.h>
22 #include <stdio.h>
23 #include <string.h>
25 #include <aros/shcommands.h>
27 /******************************************************************************
30 NAME
32 Assign [(name):] [{(target)}] [LIST] [EXISTS] [DISMOUNT] [DEFER]
33 [PATH] [ADD] [REMOVE] [VOLS] [DIRS] [DEVICES]
35 SYNOPSIS
37 NAME, TARGET/M, LIST/S, EXISTS/S, DISMOUNT/S, DEFER/S, PATH/S, ADD/S,
38 REMOVE/S, VOLS/S, DIRS/S, DEVICES/S
40 LOCATION
42 Workbench:C
44 FUNCTION
46 ASSIGN creates a reference to a file or directory. The reference
47 is a logical device name which makes it very convenient to specify
48 assigned objects using the reference instead of their paths.
50 If the NAME and TARGET arguments are given, ASSIGN assigns the
51 given logical name to the specified target. If the NAME given is
52 already assigned to a file or directory the new target replaces the
53 previous target. A colon must be included after the NAME argument.
55 If only the NAME argument is given, any assigns to that NAME are
56 removed. If no arguments whatsoever are given, all logical
57 assigns are listed.
59 INPUTS
61 NAME -- the name that should be assigned to a file or directory
62 TARGET -- one or more files or directories to assign the NAME to
63 LIST -- list all assigns made
64 EXISTS -- if NAME is already assigned, set the condition flag to
65 WARN
66 DISMOUNT -- remove the volume or device NAME from the dos list
67 DEFER -- make an ASSIGN to a path or directory that not need to
68 exist at the time of assignment. The first time the
69 NAME is referenced the NAME is bound to the object
70 PATH -- path to assign with a non-binding assign. This means
71 that the assign is re-evaluated each time a reference
72 to NAME is done. Like for DEFER, the path doesn't have
73 to exist when the ASSIGN command is executed
74 ADD -- don't replace an assign but add another object for a
75 NAME (multi-assigns)
76 REMOVE -- remove an ASSIGN
77 VOLS -- show assigned volumes if in LIST mode
78 DIRS -- show assigned directories if in LIST mode
79 DEVICES -- show assigned devices if in LIST mode
82 RESULT
84 NOTES
86 EXAMPLE
88 BUGS
90 SEE ALSO
92 INTERNALS
94 The assign command has many switches. This together with the somewhat
95 messy handling of DosList:s by dos.library makes the operation rather
96 complicated.
98 There are some fundamental building blocks that defines the semantics
99 of the Assign command.
101 Only one of the switches ADD, REMOVE, PATH and DEFER may be specified.
103 If EXISTS is specified, only the name parameter is important.
105 The implementation is split up in two fundamental procedures.
107 doAssign() -- make [a number of] assigns
108 showAssigns() -- show the available assigns
109 checkAssign() -- check if a particular assign exists
111 HISTORY
113 ******************************************************************************/
114 /* Prototypes */
116 static int checkAssign(struct ExecBase *SysBase, struct DosLibrary *DOSBase, STRPTR name);
117 static int doAssign(struct DosLibrary *DOSBase, STRPTR name, STRPTR *target,
118 BOOL dismount, BOOL defer, BOOL path,
119 BOOL add, BOOL remove);
120 static void showAssigns(struct ExecBase *SysBase, struct DosLibrary *DOSBase,
121 BOOL vols, BOOL dirs, BOOL devices);
122 static int removeAssign(struct DosLibrary *DOSBase, STRPTR name);
123 static STRPTR GetFullPath(struct ExecBase *SysBase, struct DosLibrary *DOSBase,
124 BPTR lock);
126 AROS_SH12(Assign, 41.5,
127 AROS_SHA(STRPTR, ,NAME, ,NULL),
128 AROS_SHA(STRPTR *, ,TARGET,/M,NULL),
129 AROS_SHA(BOOL, ,LIST,/S,FALSE),
130 AROS_SHA(BOOL, ,EXISTS,/S,FALSE),
131 AROS_SHA(BOOL, ,DISMOUNT,/S,FALSE),
132 AROS_SHA(BOOL, ,DEFER,/S,FALSE),
133 AROS_SHA(BOOL, ,PATH,/S,FALSE),
134 AROS_SHA(BOOL, ,ADD,/S,FALSE),
135 AROS_SHA(BOOL, ,REMOVE,/S,FALSE),
136 AROS_SHA(BOOL, ,VOLS,/S,FALSE),
137 AROS_SHA(BOOL, ,DIRS,/S,FALSE),
138 AROS_SHA(BOOL, ,DEVICES,/S,FALSE))
140 AROS_SHCOMMAND_INIT
141 int error = RETURN_OK;
143 if (SHArg(ADD) + SHArg(REMOVE) + SHArg(PATH) + SHArg(DEFER) > 1)
145 PutStr("Only one of ADD, REMOVE, PATH or DEFER is allowed\n");
147 return RETURN_FAIL;
150 /* Check device name
152 if (SHArg(NAME))
154 char *pos;
156 /* Correct assign name construction? The rule is that the device name
157 * should end with a colon at the same time as no other colon may be
158 * in the name.
160 pos = strchr(SHArg(NAME), ':');
161 if (!pos || pos[1])
163 VPrintf("Invalid device name %s\n", &SHArg(NAME));
164 return RETURN_FAIL;
167 /* If the EXISTS keyword is specified, we only care about NAME */
168 if (SHArg(EXISTS))
170 error = checkAssign(SysBase, DOSBase, SHArg(NAME));
172 else if (SHArg(NAME) != NULL)
174 /* If a NAME is specified, our primary task is to add or
175 remove an assign */
177 error = doAssign(DOSBase, SHArg(NAME), SHArg(TARGET), SHArg(DISMOUNT),
178 SHArg(DEFER), SHArg(PATH), SHArg(ADD), SHArg(REMOVE));
180 if (SHArg(LIST))
182 /* With the LIST keyword, the current assigns will be
183 displayed also when (after) making an assign */
185 showAssigns(SysBase, DOSBase, SHArg(VOLS), SHArg(DIRS),
186 SHArg(DEVICES));
189 else
191 /* If no NAME was given, we just show the current assigns
192 as specified by the user (VOLS, DIRS, DEVICES) */
194 showAssigns(SysBase, DOSBase, SHArg(VOLS), SHArg(DIRS),
195 SHArg(DEVICES));
198 return error;
200 AROS_SHCOMMAND_EXIT
204 static void showAssigns(struct ExecBase *SysBase, struct DosLibrary *DOSBase,
205 BOOL vols, BOOL dirs, BOOL devices)
207 ULONG lockBits = LDF_READ;
208 struct DosList *dl;
210 /* If none of the parameters are specified, everything should be
211 displayed */
212 if (!(vols || dirs || devices))
214 vols = TRUE;
215 dirs = TRUE;
216 devices = TRUE;
219 lockBits |= vols ? LDF_VOLUMES : 0;
220 lockBits |= dirs ? LDF_ASSIGNS : 0;
221 lockBits |= devices ? LDF_DEVICES : 0;
223 dl = LockDosList(lockBits);
225 if (vols)
227 struct DosList *tdl = dl; /* Loop variable */
229 PutStr("Volumes:\n");
231 /* Print all mounted volumes */
232 while ((tdl = NextDosEntry(tdl, LDF_VOLUMES)) != NULL)
234 VPrintf("%s [Mounted]\n", (IPTR *)&tdl->dol_DevName);
238 if (dirs)
240 struct DosList *tdl = dl; /* Loop variable */
241 int count; /* Loop variable */
243 PutStr("Directories:\n");
245 /* Print all assigned directories */
246 while ((tdl = NextDosEntry(tdl, LDF_ASSIGNS)) != NULL)
248 PutStr(tdl->dol_DevName);
250 for(count = 14 - strlen(tdl->dol_DevName); count > 0; count--)
252 PutStr(" ");
255 switch (tdl->dol_Type)
257 case DLT_LATE:
258 VPrintf("<%s>\n",
259 (IPTR *)&tdl->dol_misc.dol_assign.dol_AssignName);
260 break;
262 case DLT_NONBINDING:
263 VPrintf("[%s]\n",
264 (IPTR *)&tdl->dol_misc.dol_assign.dol_AssignName);
265 break;
267 default:
269 STRPTR dirName; /* For NameFromLock() */
270 struct AssignList *nextAssign; /* For multiassigns */
272 dirName = GetFullPath(SysBase, DOSBase, tdl->dol_Lock);
274 if (dirName != NULL)
276 VPrintf("%s\n", (IPTR *)&dirName);
277 FreeVec(dirName);
279 else
281 PutStr("\n");
284 nextAssign = tdl->dol_misc.dol_assign.dol_List;
286 while (nextAssign != NULL)
288 dirName = GetFullPath(SysBase, DOSBase,
289 nextAssign->al_Lock);
291 if (dirName != NULL)
293 VPrintf(" + %s\n", (IPTR *)&dirName);
294 FreeVec(dirName);
297 nextAssign = nextAssign->al_Next;
301 break;
303 } /* while(NextDosEntry() != NULL) */
306 if (devices)
308 struct DosList *tdl = dl; /* Loop variable */
309 int count = 0; /* Used to make sure that as most 5
310 entries are printed per line */
312 PutStr("Devices:\n");
314 /* Print all assigned devices */
315 while ((tdl = NextDosEntry(tdl, LDF_DEVICES)) != NULL)
317 VPrintf("%s ", (IPTR *)&tdl->dol_DevName);
318 count++;
320 if (count == 5)
322 PutStr("\n");
323 count = 0;
327 if (count < 5)
329 PutStr("\n");
333 UnLockDosList(lockBits);
337 static STRPTR GetFullPath(struct ExecBase *SysBase, struct DosLibrary *DOSBase,
338 BPTR lock)
340 UBYTE *buf; /* Pointer to the memory allocated for the string */
341 ULONG size; /* Holder of the (growing) size of the string */
343 for (size = 512; ; size += 512)
345 buf = AllocVec(size, MEMF_ANY);
347 if (buf == NULL)
349 break;
352 if (NameFromLock(lock, buf, size))
354 return (STRPTR)buf;
357 FreeVec(buf);
359 if (IoErr() != ERROR_LINE_TOO_LONG)
361 break;
365 return NULL;
369 static int doAssign(struct DosLibrary *DOSBase, STRPTR name, STRPTR *target,
370 BOOL dismount, BOOL defer, BOOL path, BOOL add,
371 BOOL remove)
373 STRPTR colon;
374 BPTR lock = NULL;
375 int i; /* Loop variable */
377 int error = RETURN_OK;
378 LONG ioerr = 0;
379 BOOL cancel = FALSE;
380 BOOL success = TRUE;
382 colon = strchr(name, ':');
383 *colon = 0; /* Remove trailing colon; name[] is changed! */
385 /* This is a little bit messy... We first remove the 'name' assign
386 and later in the loop the target assigns. */
387 if (dismount)
390 struct DosList *dl;
391 struct DosList *fdl;
393 dl = LockDosList(LDF_VOLUMES | LDF_DEVICES | LDF_WRITE);
395 fdl = FindDosEntry(dl, name, LDF_VOLUMES | LDF_DEVICES);
397 /* Note the ! for conversion to boolean value */
398 if (fdl)
399 success = RemDosEntry(fdl);
401 UnLockDosList(LDF_VOLUMES | LDF_DEVICES | LDF_WRITE);
403 else
405 if(target == NULL || *target == NULL || remove)
407 error = removeAssign(DOSBase, name);
408 if (error)
410 ioerr = IoErr();
411 cancel = TRUE;
415 /* AmigaDOS doesn't use RETURN_WARN here... but it should? */
416 error = success ? error : RETURN_WARN;
418 // The Loop over multiple targets starts here
420 if (target)
422 for (i = 0; target[i] != NULL; i++)
424 cancel = FALSE;
425 if (!(path || defer || dismount))
427 lock = Lock(target[i], SHARED_LOCK);
429 if (lock == NULL)
431 VPrintf("Can't find %s\n", (IPTR *)&target[i]);
433 return RETURN_FAIL;
437 if (remove)
439 AssignLock(target[i], NULL);
440 UnLock(lock);
442 else if (path)
444 if (!AssignPath(name, target[i]))
446 ioerr = IoErr();
447 error = RETURN_FAIL;
450 else if (add)
452 if (AssignAdd(name, lock) == DOSFALSE)
454 struct DosList *dl;
456 error = RETURN_FAIL;
457 ioerr = IoErr();
458 /* Check if the assign doesn't exist at all. If so, create it.
459 * This fix bug id 145. - Piru
461 dl = LockDosList(LDF_ASSIGNS | LDF_READ);
462 dl = FindDosEntry(dl, name, LDF_ASSIGNS);
463 UnLockDosList(LDF_ASSIGNS | LDF_READ);
465 if (!dl)
467 if (AssignLock(name, lock))
469 error = RETURN_OK;
470 lock = NULL;
472 else
474 ioerr = IoErr();
478 if (lock)
479 UnLock(lock);
481 if (error && ioerr != ERROR_OBJECT_EXISTS)
483 STRPTR Args[] = {target[i], name};
484 VPrintf("Can't add %s to %s\n", Args);
488 else if (defer)
490 if (AssignLate(name, target[i]) == DOSFALSE)
492 ioerr = IoErr();
493 UnLock(lock);
494 error = RETURN_FAIL;
497 else
499 /* If no extra parameters are specified we just do a regular
500 assign (replacing any possible previous assign with that
501 name. The case of target being NULL is taken care of above. */
502 if (AssignLock(name, lock) == DOSFALSE)
504 ioerr = IoErr();
505 cancel = TRUE;
506 UnLock(lock);
507 error = RETURN_FAIL;
510 /* If there are several targets, the next ones have to be added. */
511 add = TRUE;
514 /* We break as soon as we get a serious error */
515 if (error >= RETURN_FAIL)
517 return error;
520 } /* loop through all targets */
522 if (error)
524 if (ioerr == ERROR_OBJECT_EXISTS)
526 STRPTR Args[] = {cancel ? "cancel" : "assign", name};
527 VPrintf("Can't %s %s\n", Args);
529 else
531 PrintFault(ioerr, NULL);
534 return error;
537 static int removeAssign(struct DosLibrary *DOSBase, STRPTR name)
539 /* In case no target is given, the 'name' assign should be removed.
540 * The AmigaDOS semantics for this is apparently that the error
541 * code is never set even if the assign didn't exist.
544 if (!AssignLock(name, NULL))
546 return RETURN_FAIL;
548 return RETURN_OK;
551 static int checkAssign(struct ExecBase *SysBase, struct DosLibrary *DOSBase, STRPTR name)
553 STRPTR colon;
554 struct DosList *dl;
555 int error = RETURN_OK;
557 if (!name)
558 name = "";
560 colon = strchr(name, ':');
561 if (colon)
563 *colon = '\0';
566 dl = LockDosList(LDF_DEVICES | LDF_ASSIGNS | LDF_VOLUMES | LDF_READ);
567 dl = FindDosEntry(dl, name, LDF_DEVICES | LDF_ASSIGNS | LDF_VOLUMES);
568 if (dl)
570 struct DosList *tdl = dl;
571 int count;
573 switch (dl->dol_Type)
575 case DLT_DEVICE:
576 VPrintf("%s\n", &tdl->dol_OldName);
577 break;
579 case DLT_VOLUME:
580 VPrintf("%s [Mounted]\n", &tdl->dol_OldName);
581 break;
583 case DLT_DIRECTORY:
584 case DLT_LATE:
585 case DLT_NONBINDING:
587 VPrintf("%s ", &tdl->dol_OldName);
589 for (count = 14 - *((UBYTE*)tdl->dol_OldName); count > 0; count--)
591 PutStr(" ");
594 switch (tdl->dol_Type)
596 case DLT_LATE:
597 VPrintf("<%s>\n", (IPTR) &tdl->dol_misc.dol_assign.dol_AssignName);
598 break;
600 case DLT_NONBINDING:
601 VPrintf("[%s]\n", (IPTR) &tdl->dol_misc.dol_assign.dol_AssignName);
602 break;
604 default:
606 STRPTR dirName; /* For NameFromLock() */
607 struct AssignList *nextAssign; /* For multiassigns */
609 dirName = GetFullPath(SysBase, DOSBase, tdl->dol_Lock);
611 if (dirName)
613 PutStr(dirName);
614 FreeVec(dirName);
616 PutStr("\n");
618 nextAssign = tdl->dol_misc.dol_assign.dol_List;
620 while (nextAssign)
622 dirName = GetFullPath(SysBase, DOSBase, nextAssign->al_Lock);
624 if (dirName)
626 VPrintf(" + %s\n", (IPTR) &dirName);
627 FreeVec(dirName);
630 nextAssign = nextAssign->al_Next;
634 break;
637 else
639 VPrintf("%s: not assigned\n", &name);
641 error = RETURN_WARN;
643 UnLockDosList(LDF_DEVICES | LDF_ASSIGNS | LDF_VOLUMES | LDF_READ);
644 if (colon)
645 *colon = ':';
646 return error;