blob: 99116e757f626ce79844ee1bcbe82d95469847f6 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% U U TTTTT IIIII L IIIII TTTTT Y Y %
7% U U T I L I T Y Y %
8% U U T I L I T Y %
9% U U T I L I T Y %
10% UUU T IIIII LLLLL IIIII T Y %
11% %
12% %
13% MagickCore Utility Methods %
14% %
15% Software Design %
16% John Cristy %
17% January 1993 %
18% %
19% %
cristy16af1cb2009-12-11 21:38:29 +000020% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37*/
38
39/*
40 Include declarations.
41*/
42#include "magick/studio.h"
43#include "magick/property.h"
44#include "magick/blob.h"
45#include "magick/color.h"
46#include "magick/exception.h"
47#include "magick/exception-private.h"
48#include "magick/geometry.h"
49#include "magick/list.h"
50#include "magick/log.h"
51#include "magick/memory_.h"
52#include "magick/option.h"
cristyb32b90a2009-09-07 21:45:48 +000053#include "magick/policy.h"
cristy3ed852e2009-09-05 21:47:34 +000054#include "magick/resource_.h"
55#include "magick/semaphore.h"
56#include "magick/signature-private.h"
57#include "magick/statistic.h"
58#include "magick/string_.h"
59#include "magick/token.h"
60#include "magick/utility.h"
cristy98e91bd2010-01-12 01:11:42 +000061#if defined(MAGICKCORE_HAVE_PROCESS_H)
62#include <process.h>
63#endif
cristy3ed852e2009-09-05 21:47:34 +000064#if defined(MAGICKCORE_HAVE_MACH_O_DYLD_H)
65#include <mach-o/dyld.h>
66#endif
67
68/*
69 Static declarations.
70*/
71static const char
72 Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
73
74/*
75 Forward declaration.
76*/
77static int
78 IsPathDirectory(const char *);
79
80/*
81%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
82% %
83% %
84% %
85% A c q u i r e U n i q u e F i l e n a m e %
86% %
87% %
88% %
89%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
90%
91% AcquireUniqueFilename() replaces the contents of path by a unique path name.
92%
93% The format of the AcquireUniqueFilename method is:
94%
95% MagickBooleanType AcquireUniqueFilename(char *path)
96%
97% A description of each parameter follows.
98%
99% o path: Specifies a pointer to an array of characters. The unique path
100% name is returned in this array.
101%
102*/
103MagickExport MagickBooleanType AcquireUniqueFilename(char *path)
104{
105 int
106 file;
107
108 file=AcquireUniqueFileResource(path);
109 if (file == -1)
110 return(MagickFalse);
111 file=close(file)-1;
112 return(MagickTrue);
113}
114
115/*
116%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
117% %
118% %
119% %
120% A c q u i r e U n i q u e S ym b o l i c L i n k %
121% %
122% %
123% %
124%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
125%
126% AcquireUniqueSymbolicLink() creates a unique symbolic link to the specified
127% source path and returns MagickTrue on success otherwise MagickFalse. If the
128% symlink() method fails or is not available, a unique file name is generated
129% and the source file copied to it. When you are finished with the file, use
130% RelinquishUniqueFilename() to destroy it.
131%
132% The format of the AcquireUniqueSymbolicLink method is:
133%
134% MagickBooleanType AcquireUniqueSymbolicLink(const char *source,
135% char destination)
136%
137% A description of each parameter follows.
138%
139% o source: the source path.
140%
141% o destination: the destination path.
142%
143*/
144
145static inline size_t MagickMin(const size_t x,const size_t y)
146{
147 if (x < y)
148 return(x);
149 return(y);
150}
151
152MagickExport MagickBooleanType AcquireUniqueSymbolicLink(const char *source,
153 char *destination)
154{
155 int
156 destination_file,
157 source_file;
158
159 size_t
160 length,
161 quantum;
162
163 ssize_t
164 count;
165
166 struct stat
167 attributes;
168
169 unsigned char
170 *buffer;
171
172 assert(source != (const char *) NULL);
173 assert(destination != (char *) NULL);
174#if defined(MAGICKCORE_HAVE_SYMLINK)
175 (void) AcquireUniqueFilename(destination);
176 (void) RelinquishUniqueFileResource(destination);
177 if (*source == *DirectorySeparator)
178 {
179 if (symlink(source,destination) == 0)
180 return(MagickTrue);
181 }
182 else
183 {
184 char
185 path[MaxTextExtent];
186
187 *path='\0';
188 if (getcwd(path,MaxTextExtent) == (char *) NULL)
189 return(MagickFalse);
190 (void) ConcatenateMagickString(path,DirectorySeparator,MaxTextExtent);
191 (void) ConcatenateMagickString(path,source,MaxTextExtent);
192 if (symlink(path,destination) == 0)
193 return(MagickTrue);
194 }
195#endif
196 destination_file=AcquireUniqueFileResource(destination);
197 if (destination_file == -1)
198 return(MagickFalse);
199 source_file=open(source,O_RDONLY | O_BINARY);
200 if (source_file == -1)
201 {
202 (void) close(destination_file);
203 (void) RelinquishUniqueFileResource(destination);
204 return(MagickFalse);
205 }
206 quantum=(size_t) MagickMaxBufferExtent;
207 if ((fstat(source_file,&attributes) == 0) && (attributes.st_size != 0))
208 quantum=MagickMin((size_t) attributes.st_size,MagickMaxBufferExtent);
209 buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
210 if (buffer == (unsigned char *) NULL)
211 {
212 (void) close(source_file);
213 (void) close(destination_file);
214 (void) RelinquishUniqueFileResource(destination);
215 return(MagickFalse);
216 }
217 for (length=0; ; )
218 {
219 count=(ssize_t) read(source_file,buffer,quantum);
220 if (count <= 0)
221 break;
222 length=(size_t) count;
223 count=(ssize_t) write(destination_file,buffer,length);
224 if ((size_t) count != length)
225 {
226 (void) close(destination_file);
227 (void) close(source_file);
228 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
229 (void) RelinquishUniqueFileResource(destination);
230 return(MagickFalse);
231 }
232 }
233 (void) close(destination_file);
234 (void) close(source_file);
235 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
236 return(MagickTrue);
237}
238
239/*
240%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
241% %
242% %
243% %
244% A p p e n d I m a g e F o r m a t %
245% %
246% %
247% %
248%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
249%
250% AppendImageFormat() appends the image format type to the filename. If an
251% extension to the file already exists, it is first removed.
252%
253% The format of the AppendImageFormat method is:
254%
255% void AppendImageFormat(const char *format,char *filename)
256%
257% A description of each parameter follows.
258%
259% o format: Specifies a pointer to an array of characters. This the
260% format of the image.
261%
262% o filename: Specifies a pointer to an array of characters. The unique
263% file name is returned in this array.
264%
265*/
266MagickExport void AppendImageFormat(const char *format,char *filename)
267{
268 char
cristy212e2622010-06-12 19:07:47 +0000269 extension[MaxTextExtent],
cristy3ed852e2009-09-05 21:47:34 +0000270 root[MaxTextExtent];
271
272 assert(format != (char *) NULL);
273 assert(filename != (char *) NULL);
274 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
275 if ((*format == '\0') || (*filename == '\0'))
276 return;
277 if (LocaleCompare(filename,"-") == 0)
278 {
279 char
280 message[MaxTextExtent];
281
282 (void) FormatMagickString(message,MaxTextExtent,"%s:%s",format,filename);
283 (void) CopyMagickString(filename,message,MaxTextExtent);
284 return;
285 }
cristy212e2622010-06-12 19:07:47 +0000286 GetPathComponent(filename,ExtensionPath,extension);
287 if ((LocaleCompare(extension,"Z") == 0) ||
288 (LocaleCompare(extension,"bz2") == 0) ||
289 (LocaleCompare(extension,"gz") == 0) ||
290 (LocaleCompare(extension,"wmz") == 0) ||
291 (LocaleCompare(extension,"svgz") == 0))
292 {
293 GetPathComponent(filename,RootPath,root);
294 (void) CopyMagickString(filename,root,MaxTextExtent);
295 GetPathComponent(filename,RootPath,root);
296 (void) FormatMagickString(filename,MaxTextExtent,"%s.%s.%s",root,format,
297 extension);
298 return;
299 }
cristy3ed852e2009-09-05 21:47:34 +0000300 GetPathComponent(filename,RootPath,root);
301 (void) FormatMagickString(filename,MaxTextExtent,"%s.%s",root,format);
302}
303
304/*
305%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
306% %
307% %
308% %
309% B a s e 6 4 D e c o d e %
310% %
311% %
312% %
313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
314%
315% Base64Decode() decodes Base64-encoded text and returns its binary
316% equivalent. NULL is returned if the text is not valid Base64 data, or a
317% memory allocation failure occurs.
318%
319% The format of the Base64Decode method is:
320%
321% unsigned char *Base64Decode(const char *source,length_t *length)
322%
323% A description of each parameter follows:
324%
325% o source: A pointer to a Base64-encoded string.
326%
327% o length: the number of bytes decoded.
328%
329*/
330MagickExport unsigned char *Base64Decode(const char *source,size_t *length)
331{
332 int
333 state;
334
335 register const char
336 *p,
337 *q;
338
339 register size_t
340 i;
341
342 unsigned char
343 *decode;
344
345 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
346 assert(source != (char *) NULL);
347 assert(length != (size_t *) NULL);
348 *length=0;
349 decode=(unsigned char *) AcquireQuantumMemory(strlen(source)/4+4,
350 3*sizeof(*decode));
351 if (decode == (unsigned char *) NULL)
352 return((unsigned char *) NULL);
353 i=0;
354 state=0;
355 for (p=source; *p != '\0'; p++)
356 {
357 if (isspace((int) ((unsigned char) *p)) != 0)
358 continue;
359 if (*p == '=')
360 break;
361 q=strchr(Base64,*p);
362 if (q == (char *) NULL)
363 {
364 decode=(unsigned char *) RelinquishMagickMemory(decode);
365 return((unsigned char *) NULL); /* non-Base64 character */
366 }
367 switch (state)
368 {
369 case 0:
370 {
371 decode[i]=(q-Base64) << 2;
372 state++;
373 break;
374 }
375 case 1:
376 {
377 decode[i++]|=(q-Base64) >> 4;
378 decode[i]=((q-Base64) & 0x0f) << 4;
379 state++;
380 break;
381 }
382 case 2:
383 {
384 decode[i++]|=(q-Base64) >> 2;
385 decode[i]=((q-Base64) & 0x03) << 6;
386 state++;
387 break;
388 }
389 case 3:
390 {
391 decode[i++]|=(q-Base64);
392 state=0;
393 break;
394 }
395 }
396 }
397 /*
398 Verify Base-64 string has proper terminal characters.
399 */
400 if (*p != '=')
401 {
402 if (state != 0)
403 {
404 decode=(unsigned char *) RelinquishMagickMemory(decode);
405 return((unsigned char *) NULL);
406 }
407 }
408 else
409 {
410 p++;
411 switch (state)
412 {
413 case 0:
414 case 1:
415 {
416 /*
417 Unrecognized '=' character.
418 */
419 decode=(unsigned char *) RelinquishMagickMemory(decode);
420 return((unsigned char *) NULL);
421 }
422 case 2:
423 {
424 for ( ; *p != '\0'; p++)
425 if (isspace((int) ((unsigned char) *p)) == 0)
426 break;
427 if (*p != '=')
428 {
429 decode=(unsigned char *) RelinquishMagickMemory(decode);
430 return((unsigned char *) NULL);
431 }
432 p++;
433 }
434 case 3:
435 {
436 for ( ; *p != '\0'; p++)
437 if (isspace((int) ((unsigned char) *p)) == 0)
438 {
439 decode=(unsigned char *) RelinquishMagickMemory(decode);
440 return((unsigned char *) NULL);
441 }
442 if ((int) decode[i] != 0)
443 {
444 decode=(unsigned char *) RelinquishMagickMemory(decode);
445 return((unsigned char *) NULL);
446 }
447 }
448 }
449 }
450 *length=i;
451 return(decode);
452}
453
454/*
455%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
456% %
457% %
458% %
459% B a s e 6 4 E n c o d e %
460% %
461% %
462% %
463%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
464%
465% Base64Encode() encodes arbitrary binary data to Base64 encoded format as
466% described by the "Base64 Content-Transfer-Encoding" section of RFC 2045 and
467% returns the result as a null-terminated ASCII string. NULL is returned if
468% a memory allocation failure occurs.
469%
470% The format of the Base64Encode method is:
471%
472% char *Base64Encode(const unsigned char *blob,const size_t blob_length,
473% size_t *encode_length)
474%
475% A description of each parameter follows:
476%
477% o blob: A pointer to binary data to encode.
478%
479% o blob_length: the number of bytes to encode.
480%
481% o encode_length: The number of bytes encoded.
482%
483*/
484MagickExport char *Base64Encode(const unsigned char *blob,
485 const size_t blob_length,size_t *encode_length)
486{
487 char
488 *encode;
489
490 register const unsigned char
491 *p;
492
493 register size_t
494 i;
495
496 size_t
497 remainder;
498
499 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
500 assert(blob != (const unsigned char *) NULL);
501 assert(blob_length != 0);
502 assert(encode_length != (size_t *) NULL);
503 *encode_length=0;
504 encode=(char *) AcquireQuantumMemory(blob_length/3+4,4*sizeof(*encode));
505 if (encode == (char *) NULL)
506 return((char *) NULL);
507 i=0;
508 for (p=blob; p < (blob+blob_length-2); p+=3)
509 {
510 encode[i++]=Base64[(int) (*p >> 2)];
511 encode[i++]=Base64[(int) (((*p & 0x03) << 4)+(*(p+1) >> 4))];
512 encode[i++]=Base64[(int) (((*(p+1) & 0x0f) << 2)+(*(p+2) >> 6))];
513 encode[i++]=Base64[(int) (*(p+2) & 0x3f)];
514 }
515 remainder=blob_length % 3;
516 if (remainder != 0)
517 {
cristybb503372010-05-27 20:51:26 +0000518 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000519 j;
520
521 unsigned char
522 code[3];
523
524 code[0]='\0';
525 code[1]='\0';
526 code[2]='\0';
cristybb503372010-05-27 20:51:26 +0000527 for (j=0; j < (ssize_t) remainder; j++)
cristy3ed852e2009-09-05 21:47:34 +0000528 code[j]=(*p++);
529 encode[i++]=Base64[(int) (code[0] >> 2)];
530 encode[i++]=Base64[(int) (((code[0] & 0x03) << 4)+(code[1] >> 4))];
531 if (remainder == 1)
532 encode[i++]='=';
533 else
534 encode[i++]=Base64[(int) (((code[1] & 0x0f) << 2)+(code[2] >> 6))];
535 encode[i++]='=';
536 }
537 *encode_length=i;
538 encode[i++]='\0';
539 return(encode);
540}
541
542/*
543%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
544% %
545% %
546% %
547% C h o p P a t h C o m p o n e n t s %
548% %
549% %
550% %
551%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
552%
553% ChopPathComponents() removes the number of specified file components from a
554% path.
555%
556% The format of the ChopPathComponents method is:
557%
cristybb503372010-05-27 20:51:26 +0000558% ChopPathComponents(char *path,size_t components)
cristy3ed852e2009-09-05 21:47:34 +0000559%
560% A description of each parameter follows:
561%
562% o path: The path.
563%
564% o components: The number of components to chop.
565%
566*/
cristybb503372010-05-27 20:51:26 +0000567MagickExport void ChopPathComponents(char *path,const size_t components)
cristy3ed852e2009-09-05 21:47:34 +0000568{
cristybb503372010-05-27 20:51:26 +0000569 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000570 i;
571
cristybb503372010-05-27 20:51:26 +0000572 for (i=0; i < (ssize_t) components; i++)
cristy3ed852e2009-09-05 21:47:34 +0000573 GetPathComponent(path,HeadPath,path);
574}
575
576/*
577%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
578% %
579% %
580% %
581% E x p a n d F i l e n a m e %
582% %
583% %
584% %
585%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
586%
587% ExpandFilename() expands '~' in a path.
588%
589% The format of the ExpandFilename function is:
590%
591% ExpandFilename(char *path)
592%
593% A description of each parameter follows:
594%
595% o path: Specifies a pointer to a character array that contains the
596% path.
597%
598*/
599MagickExport void ExpandFilename(char *path)
600{
601 char
602 expand_path[MaxTextExtent];
603
604 if (path == (char *) NULL)
605 return;
606 if (*path != '~')
607 return;
608 (void) CopyMagickString(expand_path,path,MaxTextExtent);
609 if ((*(path+1) == *DirectorySeparator) || (*(path+1) == '\0'))
610 {
611 char
612 *home;
613
614 /*
615 Substitute ~ with $HOME.
616 */
617 (void) CopyMagickString(expand_path,".",MaxTextExtent);
618 (void) ConcatenateMagickString(expand_path,path+1,MaxTextExtent);
619 home=GetEnvironmentValue("HOME");
620 if (home == (char *) NULL)
621 home=GetEnvironmentValue("USERPROFILE");
622 if (home != (char *) NULL)
623 {
624 (void) CopyMagickString(expand_path,home,MaxTextExtent);
625 (void) ConcatenateMagickString(expand_path,path+1,MaxTextExtent);
626 home=DestroyString(home);
627 }
628 }
629 else
630 {
631#if defined(MAGICKCORE_POSIX_SUPPORT) && !defined(__OS2__)
632 char
633 username[MaxTextExtent];
634
635 register char
636 *p;
637
638 struct passwd
639 *entry;
640
641 /*
642 Substitute ~ with home directory from password file.
643 */
644 (void) CopyMagickString(username,path+1,MaxTextExtent);
645 p=strchr(username,'/');
646 if (p != (char *) NULL)
647 *p='\0';
648 entry=getpwnam(username);
649 if (entry == (struct passwd *) NULL)
650 return;
651 (void) CopyMagickString(expand_path,entry->pw_dir,MaxTextExtent);
652 if (p != (char *) NULL)
653 {
654 (void) ConcatenateMagickString(expand_path,"/",MaxTextExtent);
655 (void) ConcatenateMagickString(expand_path,p+1,MaxTextExtent);
656 }
657#endif
658 }
659 (void) CopyMagickString(path,expand_path,MaxTextExtent);
660}
661
662/*
663%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
664% %
665% %
666% %
667% E x p a n d F i l e n a m e s %
668% %
669% %
670% %
671%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
672%
673% ExpandFilenames() checks each argument of the command line vector and
674% expands it if they have a wildcard character. For example, *.jpg might
675% expand to: bird.jpg rose.jpg tiki.jpg.
676%
677% The format of the ExpandFilenames function is:
678%
679% status=ExpandFilenames(int *number_arguments,char ***arguments)
680%
681% A description of each parameter follows:
682%
683% o number_arguments: Specifies a pointer to an integer describing the
684% number of elements in the argument vector.
685%
686% o arguments: Specifies a pointer to a text array containing the command
687% line arguments.
688%
689*/
690MagickExport MagickBooleanType ExpandFilenames(int *number_arguments,
691 char ***arguments)
692{
693 char
694 *cwd,
695 home_directory[MaxTextExtent],
696 **vector;
697
cristybb503372010-05-27 20:51:26 +0000698 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000699 count,
700 parameters;
701
cristybb503372010-05-27 20:51:26 +0000702 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000703 i,
704 j;
705
cristybb503372010-05-27 20:51:26 +0000706 size_t
cristy3ed852e2009-09-05 21:47:34 +0000707 number_files;
708
709 /*
710 Allocate argument vector.
711 */
712 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
713 assert(number_arguments != (int *) NULL);
714 assert(arguments != (char ***) NULL);
715 vector=(char **) AcquireQuantumMemory((size_t) (*number_arguments+1),
716 sizeof(*vector));
717 if (vector == (char **) NULL)
718 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
719 /*
720 Expand any wildcard filenames.
721 */
722 *home_directory='\0';
cristy3ed852e2009-09-05 21:47:34 +0000723 count=0;
cristybb503372010-05-27 20:51:26 +0000724 for (i=0; i < (ssize_t) *number_arguments; i++)
cristy3ed852e2009-09-05 21:47:34 +0000725 {
726 char
727 **filelist,
728 filename[MaxTextExtent],
729 magick[MaxTextExtent],
730 *option,
731 path[MaxTextExtent],
732 subimage[MaxTextExtent];
733
734 MagickBooleanType
735 destroy;
736
737 option=(*arguments)[i];
738 *magick='\0';
739 *path='\0';
740 *filename='\0';
741 *subimage='\0';
742 vector[count++]=ConstantString(option);
743 destroy=MagickTrue;
744 parameters=ParseMagickOption(MagickCommandOptions,MagickFalse,option);
745 if (parameters > 0)
746 {
747 /*
748 Do not expand command option parameters.
749 */
750 for (j=0; j < parameters; j++)
751 {
752 i++;
cristybb503372010-05-27 20:51:26 +0000753 if (i == (ssize_t) *number_arguments)
cristy3ed852e2009-09-05 21:47:34 +0000754 break;
755 option=(*arguments)[i];
756 vector[count++]=ConstantString(option);
757 }
758 continue;
759 }
760 if ((*option == '"') || (*option == '\''))
761 continue;
762 GetPathComponent(option,TailPath,filename);
763 GetPathComponent(option,MagickPath,magick);
764 if ((LocaleCompare(magick,"CAPTION") == 0) ||
765 (LocaleCompare(magick,"LABEL") == 0) ||
766 (LocaleCompare(magick,"VID") == 0))
767 continue;
768 if ((IsGlob(filename) == MagickFalse) && (*filename != '@'))
769 continue;
770 if (*filename != '@')
771 {
772 /*
773 Generate file list from wildcard filename (e.g. *.jpg).
774 */
775 GetPathComponent(option,HeadPath,path);
776 GetPathComponent(option,SubimagePath,subimage);
777 ExpandFilename(path);
cristyf5ee5be2009-11-06 02:22:56 +0000778 if (*home_directory == '\0')
779 cwd=getcwd(home_directory,MaxTextExtent-1);
cristy3ed852e2009-09-05 21:47:34 +0000780 filelist=ListFiles(*path == '\0' ? home_directory : path,filename,
781 &number_files);
782 }
783 else
784 {
785 char
786 *files;
787
788 ExceptionInfo
789 *exception;
790
791 int
cristyf9218a72010-07-03 17:29:40 +0000792 length;
cristy3ed852e2009-09-05 21:47:34 +0000793
794 /*
795 Generate file list from file list (e.g. @filelist.txt).
796 */
797 exception=AcquireExceptionInfo();
798 files=FileToString(filename+1,~0,exception);
799 exception=DestroyExceptionInfo(exception);
800 if (files == (char *) NULL)
801 continue;
802 StripString(files);
cristyf9218a72010-07-03 17:29:40 +0000803 filelist=StringToArgv(files,&length);
804 if (filelist == (char **) NULL)
805 continue;
cristy3ed852e2009-09-05 21:47:34 +0000806 files=DestroyString(files);
cristyf9218a72010-07-03 17:29:40 +0000807 filelist[0]=DestroyString(filelist[0]);
808 for (j=0; j < (ssize_t) (length-1); j++)
809 filelist[j]=filelist[j+1];
810 number_files=(size_t) length-1;
cristy3ed852e2009-09-05 21:47:34 +0000811 }
812 if (filelist == (char **) NULL)
813 continue;
cristybb503372010-05-27 20:51:26 +0000814 for (j=0; j < (ssize_t) number_files; j++)
cristy3ed852e2009-09-05 21:47:34 +0000815 if (IsPathDirectory(filelist[j]) <= 0)
816 break;
cristybb503372010-05-27 20:51:26 +0000817 if (j == (ssize_t) number_files)
cristy3ed852e2009-09-05 21:47:34 +0000818 {
cristybb503372010-05-27 20:51:26 +0000819 for (j=0; j < (ssize_t) number_files; j++)
cristy3ed852e2009-09-05 21:47:34 +0000820 filelist[j]=DestroyString(filelist[j]);
821 filelist=(char **) RelinquishMagickMemory(filelist);
822 continue;
823 }
824 /*
825 Transfer file list to argument vector.
826 */
827 vector=(char **) ResizeQuantumMemory(vector,(size_t) *number_arguments+
828 count+number_files+1,sizeof(*vector));
829 if (vector == (char **) NULL)
830 return(MagickFalse);
cristybb503372010-05-27 20:51:26 +0000831 for (j=0; j < (ssize_t) number_files; j++)
cristy3ed852e2009-09-05 21:47:34 +0000832 {
cristy0e526222010-05-06 14:07:32 +0000833 option=filelist[j];
834 parameters=ParseMagickOption(MagickCommandOptions,MagickFalse,option);
835 if (parameters > 0)
836 {
cristybb503372010-05-27 20:51:26 +0000837 ssize_t
cristy0e526222010-05-06 14:07:32 +0000838 k;
839
840 /*
841 Do not expand command option parameters.
842 */
843 vector[count++]=ConstantString(option);
844 for (k=0; k < parameters; k++)
845 {
846 j++;
cristybb503372010-05-27 20:51:26 +0000847 if (j == (ssize_t) number_files)
cristy0e526222010-05-06 14:07:32 +0000848 break;
849 option=filelist[j];
850 vector[count++]=ConstantString(option);
851 }
852 continue;
853 }
cristy3ed852e2009-09-05 21:47:34 +0000854 (void) CopyMagickString(filename,path,MaxTextExtent);
855 if (*path != '\0')
856 (void) ConcatenateMagickString(filename,DirectorySeparator,
857 MaxTextExtent);
858 (void) ConcatenateMagickString(filename,filelist[j],MaxTextExtent);
859 filelist[j]=DestroyString(filelist[j]);
cristycfef62c2010-05-05 01:21:43 +0000860 if (strlen(filename) >= (MaxTextExtent-1))
cristy3ed852e2009-09-05 21:47:34 +0000861 ThrowFatalException(OptionFatalError,"FilenameTruncated");
cristy47dc34d2010-04-22 16:12:43 +0000862 if (IsPathDirectory(filename) <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000863 {
864 char
865 path[MaxTextExtent];
866
867 *path='\0';
868 if (*magick != '\0')
869 {
870 (void) ConcatenateMagickString(path,magick,MaxTextExtent);
871 (void) ConcatenateMagickString(path,":",MaxTextExtent);
872 }
873 (void) ConcatenateMagickString(path,filename,MaxTextExtent);
874 if (*subimage != '\0')
875 {
876 (void) ConcatenateMagickString(path,"[",MaxTextExtent);
877 (void) ConcatenateMagickString(path,subimage,MaxTextExtent);
878 (void) ConcatenateMagickString(path,"]",MaxTextExtent);
879 }
880 if (strlen(path) >= MaxTextExtent)
881 ThrowFatalException(OptionFatalError,"FilenameTruncated");
882 if (destroy != MagickFalse)
883 {
884 count--;
885 vector[count]=DestroyString(vector[count]);
886 destroy=MagickFalse;
887 }
888 vector[count++]=ConstantString(path);
889 }
890 }
891 filelist=(char **) RelinquishMagickMemory(filelist);
892 }
893 vector[count]=(char *) NULL;
894 if (IsEventLogging() != MagickFalse)
895 {
896 char
897 *command_line;
898
899 command_line=AcquireString(vector[0]);
900 for (i=1; i < count; i++)
901 {
902 (void) ConcatenateString(&command_line," {");
903 (void) ConcatenateString(&command_line,vector[i]);
904 (void) ConcatenateString(&command_line,"}");
905 }
906 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
907 "Command line: %s",command_line);
908 command_line=DestroyString(command_line);
909 }
910 *number_arguments=(int) count;
911 *arguments=vector;
912 return(MagickTrue);
913}
914
915/*
916%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
917% %
918% %
919% %
920% G e t E x e c u t i o n P a t h %
921% %
922% %
923% %
924%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
925%
926% GetExecutionPath() returns the pathname of the executable that started
927% the process. On success MagickTrue is returned, otherwise MagickFalse.
928%
929% The format of the GetExecutionPath method is:
930%
931% MagickBooleanType GetExecutionPath(char *path,const size_t extent)
932%
933% A description of each parameter follows:
934%
935% o path: the pathname of the executable that started the process.
936%
937% o extent: the maximum extent of the path.
938%
939*/
940MagickExport MagickBooleanType GetExecutionPath(char *path,const size_t extent)
941{
942 char
943 *cwd;
944
945 *path='\0';
cristyeaedf062010-05-29 22:36:02 +0000946 cwd=getcwd(path,(unsigned long) extent);
cristyfa09d142009-10-15 01:02:25 +0000947#if defined(MAGICKCORE_HAVE_GETPID) && defined(MAGICKCORE_HAVE_READLINK) && defined(PATH_MAX)
cristy3ed852e2009-09-05 21:47:34 +0000948 {
949 char
950 link_path[MaxTextExtent],
cristyfa09d142009-10-15 01:02:25 +0000951 execution_path[PATH_MAX+1];
cristy3ed852e2009-09-05 21:47:34 +0000952
953 ssize_t
954 count;
955
cristye8c25f92010-06-03 00:53:06 +0000956 (void) FormatMagickString(link_path,MaxTextExtent,"/proc/%.20g/exe",
957 (double) getpid());
cristyfa09d142009-10-15 01:02:25 +0000958 count=readlink(link_path,execution_path,PATH_MAX);
cristy3ed852e2009-09-05 21:47:34 +0000959 if (count == -1)
960 {
cristye8c25f92010-06-03 00:53:06 +0000961 (void) FormatMagickString(link_path,MaxTextExtent,"/proc/%.20g/file",
962 (double) getpid());
cristyfa09d142009-10-15 01:02:25 +0000963 count=readlink(link_path,execution_path,PATH_MAX);
cristy3ed852e2009-09-05 21:47:34 +0000964 }
965 if ((count > 0) && (count <= (ssize_t) PATH_MAX))
966 {
cristyfa09d142009-10-15 01:02:25 +0000967 execution_path[count]='\0';
968 (void) CopyMagickString(path,execution_path,extent);
cristy3ed852e2009-09-05 21:47:34 +0000969 }
970 }
971#endif
972#if defined(MAGICKCORE_HAVE__NSGETEXECUTABLEPATH)
973 {
974 char
975 executable_path[PATH_MAX << 1],
cristyfa09d142009-10-15 01:02:25 +0000976 execution_path[PATH_MAX+1];
cristy3ed852e2009-09-05 21:47:34 +0000977
978 uint32_t
979 length;
980
981 length=sizeof(executable_path);
982 if ((_NSGetExecutablePath(executable_path,&length) == 0) &&
cristyfa09d142009-10-15 01:02:25 +0000983 (realpath(executable_path,execution_path) != (char *) NULL))
984 (void) CopyMagickString(path,execution_path,extent);
cristy3ed852e2009-09-05 21:47:34 +0000985 }
986#endif
987#if defined(MAGICKCORE_HAVE_GETEXECNAME)
988 {
989 const char
990 *execution_path;
991
992 execution_path=(const char *) getexecname();
993 if (execution_path != (const char *) NULL)
994 {
995 if (*execution_path != *DirectorySeparator)
996 (void) ConcatenateMagickString(path,DirectorySeparator,extent);
997 (void) ConcatenateMagickString(path,execution_path,extent);
998 }
999 }
1000#endif
cristy0157aea2010-04-24 21:12:18 +00001001#if defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +00001002 NTGetExecutionPath(path,extent);
1003#endif
cristyfa09d142009-10-15 01:02:25 +00001004#if defined(__GNU__)
1005 {
1006 char
1007 *program_name,
1008 *execution_path;
1009
cristybb503372010-05-27 20:51:26 +00001010 ssize_t
cristyfa09d142009-10-15 01:02:25 +00001011 count;
1012
1013 count=0;
1014 execution_path=(char *) NULL;
1015 program_name=program_invocation_name;
1016 if (*program_invocation_name != '/')
1017 {
1018 size_t
1019 extent;
1020
1021 extent=strlen(cwd)+strlen(program_name)+1;
1022 program_name=AcquireQuantumMemory(extent,sizeof(*program_name));
1023 if (program_name == (char *) NULL)
1024 program_name=program_invocation_name;
1025 else
1026 count=FormatMagickString(program_name,extent,"%s/%s",cwd,
1027 program_invocation_name);
1028 }
1029 if (count != -1)
1030 {
1031 execution_path=realpath(program_name,NULL);
1032 if (execution_path != (char *) NULL)
1033 (void) CopyMagickString(path,execution_path,extent);
1034 }
1035 if (program_name != program_invocation_name)
1036 program_name=(char *) RelinquishMagickMemory(program_name);
1037 execution_path=(char *) RelinquishMagickMemory(execution_path);
1038 }
1039#endif
cristy3ed852e2009-09-05 21:47:34 +00001040 return(IsPathAccessible(path));
1041}
1042
1043/*
1044%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1045% %
1046% %
1047% %
cristy688f07b2009-09-27 15:19:13 +00001048% G e t M a g i c k P a g e S i z e %
1049% %
1050% %
1051% %
1052%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1053%
1054% GetMagickPageSize() returns the memory page size.
1055%
1056% The format of the GetMagickPageSize method is:
1057%
cristybb503372010-05-27 20:51:26 +00001058% ssize_t GetMagickPageSize()
cristy688f07b2009-09-27 15:19:13 +00001059%
1060*/
cristybb503372010-05-27 20:51:26 +00001061MagickExport ssize_t GetMagickPageSize(void)
cristy688f07b2009-09-27 15:19:13 +00001062{
cristybb503372010-05-27 20:51:26 +00001063 static ssize_t
cristy688f07b2009-09-27 15:19:13 +00001064 page_size = -1;
1065
1066 if (page_size > 0)
1067 return(page_size);
1068#if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
cristyecd0ab52010-05-30 14:59:20 +00001069 page_size=(ssize_t) sysconf(_SC_PAGE_SIZE);
cristy09449f72010-01-23 03:08:36 +00001070#else
cristy688f07b2009-09-27 15:19:13 +00001071#if defined(MAGICKCORE_HAVE_GETPAGESIZE)
cristyecd0ab52010-05-30 14:59:20 +00001072 page_size=(ssize_t) getpagesize();
cristy09449f72010-01-23 03:08:36 +00001073#endif
cristy688f07b2009-09-27 15:19:13 +00001074#endif
1075 if (page_size <= 0)
1076 page_size=16384;
1077 return(page_size);
1078}
1079
1080/*
1081%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1082% %
1083% %
1084% %
cristy3ed852e2009-09-05 21:47:34 +00001085% G e t P a t h A t t r i b u t e s %
1086% %
1087% %
1088% %
1089%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1090%
1091% GetPathAttributes() returns attributes (e.g. size of file) about a path.
1092%
1093% The path of the GetPathAttributes method is:
1094%
1095% MagickBooleanType GetPathAttributes(const char *path,void *attributes)
1096%
1097% A description of each parameter follows.
1098%
1099% o path: the file path.
1100%
1101% o attributes: the path attributes are returned here.
1102%
1103*/
1104
1105#if defined(MAGICKCORE_HAVE__WFOPEN)
1106static size_t UTF8ToUTF16(const unsigned char *utf8,wchar_t *utf16)
1107{
1108 register const unsigned char
1109 *p;
1110
1111 if (utf16 != (wchar_t *) NULL)
1112 {
1113 register wchar_t
1114 *q;
1115
1116 wchar_t
1117 c;
1118
1119 /*
1120 Convert UTF-8 to UTF-16.
1121 */
1122 q=utf16;
1123 for (p=utf8; *p != '\0'; p++)
1124 {
1125 if ((*p & 0x80) == 0)
1126 *q=(*p);
1127 else
1128 if ((*p & 0xE0) == 0xC0)
1129 {
1130 c=(*p);
1131 *q=(c & 0x1F) << 6;
1132 p++;
1133 if ((*p & 0xC0) != 0x80)
1134 return(0);
1135 *q|=(*p & 0x3F);
1136 }
1137 else
1138 if ((*p & 0xF0) == 0xE0)
1139 {
1140 c=(*p);
1141 *q=c << 12;
1142 p++;
1143 if ((*p & 0xC0) != 0x80)
1144 return(0);
1145 c=(*p);
1146 *q|=(c & 0x3F) << 6;
1147 p++;
1148 if ((*p & 0xC0) != 0x80)
1149 return(0);
1150 *q|=(*p & 0x3F);
1151 }
1152 else
1153 return(0);
1154 q++;
1155 }
1156 *q++='\0';
1157 return(q-utf16);
1158 }
1159 /*
1160 Compute UTF-16 string length.
1161 */
1162 for (p=utf8; *p != '\0'; p++)
1163 {
1164 if ((*p & 0x80) == 0)
1165 ;
1166 else
1167 if ((*p & 0xE0) == 0xC0)
1168 {
1169 p++;
1170 if ((*p & 0xC0) != 0x80)
1171 return(0);
1172 }
1173 else
1174 if ((*p & 0xF0) == 0xE0)
1175 {
1176 p++;
1177 if ((*p & 0xC0) != 0x80)
1178 return(0);
1179 p++;
1180 if ((*p & 0xC0) != 0x80)
1181 return(0);
1182 }
1183 else
1184 return(0);
1185 }
1186 return(p-utf8);
1187}
1188
1189static wchar_t *ConvertUTF8ToUTF16(const unsigned char *source)
1190{
1191 size_t
1192 length;
1193
1194 wchar_t
1195 *utf16;
1196
1197 length=UTF8ToUTF16(source,(wchar_t *) NULL);
1198 if (length == 0)
1199 {
cristybb503372010-05-27 20:51:26 +00001200 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001201 i;
1202
1203 /*
1204 Not UTF-8, just copy.
1205 */
cristy0157aea2010-04-24 21:12:18 +00001206 length=strlen((const char *) source);
cristy3ed852e2009-09-05 21:47:34 +00001207 utf16=(wchar_t *) AcquireQuantumMemory(length+1,sizeof(*utf16));
1208 if (utf16 == (wchar_t *) NULL)
1209 return((wchar_t *) NULL);
cristybb503372010-05-27 20:51:26 +00001210 for (i=0; i <= (ssize_t) length; i++)
cristy3ed852e2009-09-05 21:47:34 +00001211 utf16[i]=source[i];
1212 return(utf16);
1213 }
1214 utf16=(wchar_t *) AcquireQuantumMemory(length+1,sizeof(*utf16));
1215 if (utf16 == (wchar_t *) NULL)
1216 return((wchar_t *) NULL);
1217 length=UTF8ToUTF16(source,utf16);
1218 return(utf16);
1219}
1220#endif
1221
1222MagickExport MagickBooleanType GetPathAttributes(const char *path,
1223 void *attributes)
1224{
1225 MagickBooleanType
1226 status;
1227
1228 if (path == (const char *) NULL)
1229 {
1230 errno=EINVAL;
1231 return(MagickFalse);
1232 }
1233#if !defined(MAGICKCORE_HAVE__WSTAT)
1234 status=stat(path,(struct stat *) attributes) == 0 ? MagickTrue : MagickFalse;
1235#else
1236 {
1237 wchar_t
1238 *unicode_path;
1239
cristye7e40552010-04-24 21:34:22 +00001240 unicode_path=ConvertUTF8ToUTF16((const unsigned char *) path);
cristy3ed852e2009-09-05 21:47:34 +00001241 if (unicode_path == (wchar_t *) NULL)
1242 return(MagickFalse);
1243 status=wstat(unicode_path,(struct stat *) attributes) == 0 ? MagickTrue :
1244 MagickFalse;
1245 unicode_path=(wchar_t *) RelinquishMagickMemory(unicode_path);
1246 }
1247#endif
1248 return(status);
1249}
1250
1251/*
1252%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1253% %
1254% %
1255% %
1256% G e t P a t h C o m p o n e n t %
1257% %
1258% %
1259% %
1260%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1261%
1262% GetPathComponent() returns the parent directory name, filename, basename, or
1263% extension of a file path.
1264%
1265% The format of the GetPathComponent function is:
1266%
1267% GetPathComponent(const char *path,PathType type,char *component)
1268%
1269% A description of each parameter follows:
1270%
1271% o path: Specifies a pointer to a character array that contains the
1272% file path.
1273%
1274% o type: Specififies which file path component to return.
1275%
1276% o component: the selected file path component is returned here.
1277%
1278*/
1279MagickExport void GetPathComponent(const char *path,PathType type,
1280 char *component)
1281{
1282 char
1283 magick[MaxTextExtent],
1284 *q,
1285 subimage[MaxTextExtent];
1286
1287 register char
1288 *p;
1289
1290 assert(path != (const char *) NULL);
1291 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",path);
1292 assert(component != (char *) NULL);
1293 if (*path == '\0')
1294 {
1295 *component='\0';
1296 return;
1297 }
1298 (void) CopyMagickString(component,path,MaxTextExtent);
1299 *magick='\0';
1300#if defined(__OS2__)
1301 if (path[1] != ":")
1302#endif
1303 for (p=component; *p != '\0'; p++)
cristy2261ef52010-05-25 13:11:55 +00001304 {
1305 if ((*p == '%') && (*(p+1) == '['))
1306 {
cristy20843ea2010-05-25 13:18:56 +00001307 /*
1308 Skip over %[...].
1309 */
cristy2261ef52010-05-25 13:11:55 +00001310 for (p++; (*p != ']') && (*p != '\0'); p++) ;
1311 if (*p == '\0')
1312 break;
1313 }
cristy3ed852e2009-09-05 21:47:34 +00001314 if ((*p == ':') && (IsPathDirectory(path) < 0) &&
1315 (IsPathAccessible(path) == MagickFalse))
1316 {
1317 /*
1318 Look for image format specification (e.g. ps3:image).
1319 */
1320 (void) CopyMagickString(magick,component,(size_t) (p-component+1));
1321 if (IsMagickConflict(magick) != MagickFalse)
1322 *magick='\0';
1323 else
1324 for (q=component; *q != '\0'; q++)
1325 *q=(*++p);
1326 break;
1327 }
cristy2261ef52010-05-25 13:11:55 +00001328 }
cristy3ed852e2009-09-05 21:47:34 +00001329 *subimage='\0';
1330 p=component;
1331 if (*p != '\0')
1332 p=component+strlen(component)-1;
1333 if ((*p == ']') && (strchr(component,'[') != (char *) NULL) &&
1334 (IsPathAccessible(path) == MagickFalse))
1335 {
1336 /*
1337 Look for scene specification (e.g. img0001.pcd[4]).
1338 */
1339 for (q=p-1; q > component; q--)
1340 if (*q == '[')
1341 break;
1342 if (*q == '[')
1343 {
1344 (void) CopyMagickString(subimage,q+1,MaxTextExtent);
1345 subimage[p-q-1]='\0';
1346 if ((IsSceneGeometry(subimage,MagickFalse) == MagickFalse) &&
1347 (IsGeometry(subimage) == MagickFalse))
1348 *subimage='\0';
1349 else
1350 *q='\0';
1351 }
1352 }
1353 p=component;
1354 if (*p != '\0')
1355 for (p=component+strlen(component)-1; p > component; p--)
1356 if (IsBasenameSeparator(*p) != MagickFalse)
1357 break;
1358 switch (type)
1359 {
1360 case MagickPath:
1361 {
1362 (void) CopyMagickString(component,magick,MaxTextExtent);
1363 break;
1364 }
1365 case RootPath:
1366 {
1367 for (p=component+(strlen(component)-1); p > component; p--)
1368 {
1369 if (IsBasenameSeparator(*p) != MagickFalse)
1370 break;
1371 if (*p == '.')
1372 break;
1373 }
1374 if (*p == '.')
1375 *p='\0';
1376 break;
1377 }
1378 case HeadPath:
1379 {
1380 *p='\0';
1381 break;
1382 }
1383 case TailPath:
1384 {
1385 if (IsBasenameSeparator(*p) != MagickFalse)
1386 (void) CopyMagickMemory((unsigned char *) component,
1387 (const unsigned char *) (p+1),strlen(p+1)+1);
1388 break;
1389 }
1390 case BasePath:
1391 {
1392 if (IsBasenameSeparator(*p) != MagickFalse)
1393 (void) CopyMagickString(component,p+1,MaxTextExtent);
1394 for (p=component+(strlen(component)-1); p > component; p--)
1395 if (*p == '.')
1396 {
1397 *p='\0';
1398 break;
1399 }
1400 break;
1401 }
1402 case ExtensionPath:
1403 {
1404 if (IsBasenameSeparator(*p) != MagickFalse)
1405 (void) CopyMagickString(component,p+1,MaxTextExtent);
1406 p=component;
1407 if (*p != '\0')
1408 for (p=component+strlen(component)-1; p > component; p--)
1409 if (*p == '.')
1410 break;
1411 *component='\0';
1412 if (*p == '.')
1413 (void) CopyMagickString(component,p+1,MaxTextExtent);
1414 break;
1415 }
1416 case SubimagePath:
1417 {
1418 (void) CopyMagickString(component,subimage,MaxTextExtent);
1419 break;
1420 }
1421 case CanonicalPath:
1422 case UndefinedPath:
1423 break;
1424 }
1425}
1426
1427/*
1428%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1429% %
1430% %
1431% %
1432% G e t P a t h C o m p o n e n t s %
1433% %
1434% %
1435% %
1436%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1437%
1438% GetPathComponents() returns a list of path components.
1439%
1440% The format of the GetPathComponents method is:
1441%
1442% char **GetPathComponents(const char *path,
cristybb503372010-05-27 20:51:26 +00001443% size_t *number_componenets)
cristy3ed852e2009-09-05 21:47:34 +00001444%
1445% A description of each parameter follows:
1446%
1447% o path: Specifies the string to segment into a list.
1448%
1449% o number_components: return the number of components in the list
1450%
1451*/
1452MagickExport char **GetPathComponents(const char *path,
cristybb503372010-05-27 20:51:26 +00001453 size_t *number_components)
cristy3ed852e2009-09-05 21:47:34 +00001454{
1455 char
1456 **components;
1457
1458 register const char
1459 *p,
1460 *q;
1461
cristybb503372010-05-27 20:51:26 +00001462 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001463 i;
1464
1465 if (path == (char *) NULL)
1466 return((char **) NULL);
1467 *number_components=1;
1468 for (p=path; *p != '\0'; p++)
1469 if (IsBasenameSeparator(*p))
1470 (*number_components)++;
1471 components=(char **) AcquireQuantumMemory((size_t) *number_components+1UL,
1472 sizeof(*components));
1473 if (components == (char **) NULL)
1474 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1475 p=path;
cristybb503372010-05-27 20:51:26 +00001476 for (i=0; i < (ssize_t) *number_components; i++)
cristy3ed852e2009-09-05 21:47:34 +00001477 {
1478 for (q=p; *q != '\0'; q++)
1479 if (IsBasenameSeparator(*q))
1480 break;
1481 components[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
1482 sizeof(*components));
1483 if (components[i] == (char *) NULL)
1484 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1485 (void) CopyMagickString(components[i],p,(size_t) (q-p+1));
1486 p=q+1;
1487 }
1488 components[i]=(char *) NULL;
1489 return(components);
1490}
1491
1492/*
1493%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1494% %
1495% %
1496% %
1497% I s P a t h A c c e s s i b l e %
1498% %
1499% %
1500% %
1501%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1502%
1503% IsPathAccessible() returns MagickTrue if the file as defined by the path is
1504% accessible.
1505%
1506% The format of the IsPathAccessible method is:
1507%
1508% MagickBooleanType IsPathAccessible(const char *filename)
1509%
1510% A description of each parameter follows.
1511%
1512% o path: Specifies a path to a file.
1513%
1514*/
1515MagickExport MagickBooleanType IsPathAccessible(const char *path)
1516{
1517 MagickBooleanType
1518 status;
1519
1520 struct stat
1521 attributes;
1522
1523 if ((path == (const char *) NULL) || (*path == '\0'))
1524 return(MagickFalse);
1525 status=GetPathAttributes(path,&attributes);
1526 if (status == MagickFalse)
1527 return(status);
1528 if (S_ISREG(attributes.st_mode) == 0)
1529 return(MagickFalse);
1530 if (access(path,F_OK) != 0)
1531 return(MagickFalse);
1532 return(MagickTrue);
1533}
1534
1535/*
1536%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1537% %
1538% %
1539% %
1540+ I s P a t h D i r e c t o r y %
1541% %
1542% %
1543% %
1544%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1545%
1546% IsPathDirectory() returns -1 if the directory does not exist, 1 is returned
1547% if the path represents a directory otherwise 0.
1548%
1549% The format of the IsPathDirectory method is:
1550%
1551% int IsPathDirectory(const char *path)
1552%
1553% A description of each parameter follows.
1554%
1555% o path: The directory path.
1556%
1557*/
1558static int IsPathDirectory(const char *path)
1559{
1560 MagickBooleanType
1561 status;
1562
1563 struct stat
1564 attributes;
1565
1566 if ((path == (const char *) NULL) || (*path == '\0'))
1567 return(MagickFalse);
1568 status=GetPathAttributes(path,&attributes);
1569 if (status == MagickFalse)
1570 return(-1);
1571 if (S_ISDIR(attributes.st_mode) == 0)
1572 return(0);
1573 return(1);
1574}
1575
1576/*
1577%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1578% %
1579% %
1580% %
1581% I s M a g i c k T r u e %
1582% %
1583% %
1584% %
1585%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1586%
1587% IsMagickTrue() returns MagickTrue if the value is "true", "on", "yes" or
1588% "1".
1589%
1590% The format of the IsMagickTrue method is:
1591%
1592% MagickBooleanType IsMagickTrue(const char *value)
1593%
1594% A description of each parameter follows:
1595%
1596% o option: either MagickTrue or MagickFalse depending on the value
1597% parameter.
1598%
1599% o value: Specifies a pointer to a character array.
1600%
1601*/
1602MagickExport MagickBooleanType IsMagickTrue(const char *value)
1603{
1604 if (value == (const char *) NULL)
1605 return(MagickFalse);
1606 if (LocaleCompare(value,"true") == 0)
1607 return(MagickTrue);
1608 if (LocaleCompare(value,"on") == 0)
1609 return(MagickTrue);
1610 if (LocaleCompare(value,"yes") == 0)
1611 return(MagickTrue);
1612 if (LocaleCompare(value,"1") == 0)
1613 return(MagickTrue);
1614 return(MagickFalse);
1615}
1616
1617/*
1618%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1619% %
1620% %
1621% %
1622% L i s t F i l e s %
1623% %
1624% %
1625% %
1626%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1627%
1628% ListFiles() reads the directory specified and returns a list of filenames
1629% contained in the directory sorted in ascending alphabetic order.
1630%
1631% The format of the ListFiles function is:
1632%
1633% char **ListFiles(const char *directory,const char *pattern,
cristybb503372010-05-27 20:51:26 +00001634% ssize_t *number_entries)
cristy3ed852e2009-09-05 21:47:34 +00001635%
1636% A description of each parameter follows:
1637%
1638% o filelist: Method ListFiles returns a list of filenames contained
1639% in the directory. If the directory specified cannot be read or it is
1640% a file a NULL list is returned.
1641%
1642% o directory: Specifies a pointer to a text string containing a directory
1643% name.
1644%
1645% o pattern: Specifies a pointer to a text string containing a pattern.
1646%
1647% o number_entries: This integer returns the number of filenames in the
1648% list.
1649%
1650*/
1651
1652#if defined(__cplusplus) || defined(c_plusplus)
1653extern "C" {
1654#endif
1655
1656static int FileCompare(const void *x,const void *y)
1657{
1658 register const char
1659 **p,
1660 **q;
1661
1662 p=(const char **) x;
1663 q=(const char **) y;
1664 return(LocaleCompare(*p,*q));
1665}
1666
1667#if defined(__cplusplus) || defined(c_plusplus)
1668}
1669#endif
1670
1671static inline int MagickReadDirectory(DIR *directory,struct dirent *entry,
1672 struct dirent **result)
1673{
1674#if defined(MAGICKCORE_HAVE_READDIR_R)
1675 return(readdir_r(directory,entry,result));
1676#else
1677 (void) entry;
1678 errno=0;
1679 *result=readdir(directory);
1680 return(errno);
1681#endif
1682}
1683
1684MagickExport char **ListFiles(const char *directory,const char *pattern,
cristybb503372010-05-27 20:51:26 +00001685 size_t *number_entries)
cristy3ed852e2009-09-05 21:47:34 +00001686{
1687 char
1688 **filelist;
1689
1690 DIR
1691 *current_directory;
1692
1693 struct dirent
1694 *buffer,
1695 *entry;
1696
cristybb503372010-05-27 20:51:26 +00001697 size_t
cristy3ed852e2009-09-05 21:47:34 +00001698 max_entries;
1699
1700 /*
1701 Open directory.
1702 */
1703 assert(directory != (const char *) NULL);
1704 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",directory);
1705 assert(pattern != (const char *) NULL);
cristybb503372010-05-27 20:51:26 +00001706 assert(number_entries != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001707 *number_entries=0;
1708 current_directory=opendir(directory);
1709 if (current_directory == (DIR *) NULL)
1710 return((char **) NULL);
1711 /*
1712 Allocate filelist.
1713 */
1714 max_entries=2048;
1715 filelist=(char **) AcquireQuantumMemory((size_t) max_entries,
1716 sizeof(*filelist));
1717 if (filelist == (char **) NULL)
1718 {
1719 (void) closedir(current_directory);
1720 return((char **) NULL);
1721 }
1722 /*
1723 Save the current and change to the new directory.
1724 */
cristy73bd4a52010-10-05 11:24:23 +00001725 buffer=(struct dirent *) AcquireMagickMemory(sizeof(*buffer)+
cristy0be53ea2010-06-23 19:12:05 +00001726 FILENAME_MAX+1);
cristy3ed852e2009-09-05 21:47:34 +00001727 if (buffer == (struct dirent *) NULL)
1728 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1729 while ((MagickReadDirectory(current_directory,buffer,&entry) == 0) &&
1730 (entry != (struct dirent *) NULL))
1731 {
1732 if (*entry->d_name == '.')
1733 continue;
1734 if ((IsPathDirectory(entry->d_name) > 0) ||
cristy0157aea2010-04-24 21:12:18 +00001735#if defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +00001736 (GlobExpression(entry->d_name,pattern,MagickTrue) != MagickFalse))
1737#else
1738 (GlobExpression(entry->d_name,pattern,MagickFalse) != MagickFalse))
1739#endif
1740 {
1741 if (*number_entries >= max_entries)
1742 {
1743 /*
1744 Extend the file list.
1745 */
1746 max_entries<<=1;
1747 filelist=(char **) ResizeQuantumMemory(filelist,(size_t)
1748 max_entries,sizeof(*filelist));
1749 if (filelist == (char **) NULL)
1750 break;
1751 }
1752#if defined(vms)
1753 {
1754 register char
1755 *p;
1756
1757 p=strchr(entry->d_name,';');
1758 if (p)
1759 *p='\0';
1760 if (*number_entries > 0)
1761 if (LocaleCompare(entry->d_name,filelist[*number_entries-1]) == 0)
1762 continue;
1763 }
1764#endif
1765 filelist[*number_entries]=(char *) AcquireString(entry->d_name);
cristy3ed852e2009-09-05 21:47:34 +00001766 (*number_entries)++;
1767 }
1768 }
1769 buffer=(struct dirent *) RelinquishMagickMemory(buffer);
1770 (void) closedir(current_directory);
1771 if (filelist == (char **) NULL)
1772 return((char **) NULL);
1773 /*
1774 Sort filelist in ascending order.
1775 */
1776 qsort((void *) filelist,(size_t) *number_entries,sizeof(*filelist),
1777 FileCompare);
1778 return(filelist);
1779}
1780
1781/*
1782%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1783% %
1784% %
1785% %
cristya21afde2010-07-02 00:45:40 +00001786% M a g i c k D e l a y %
1787% %
1788% %
1789% %
1790%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1791%
1792% MagickDelay() suspends program execution for the number of milliseconds
1793% specified.
1794%
1795% The format of the Delay method is:
1796%
1797% void MagickDelay(const MagickSizeType milliseconds)
1798%
1799% A description of each parameter follows:
1800%
1801% o milliseconds: Specifies the number of milliseconds to delay before
1802% returning.
1803%
1804*/
1805MagickExport void MagickDelay(const MagickSizeType milliseconds)
1806{
1807 if (milliseconds == 0)
1808 return;
1809#if defined(MAGICKCORE_HAVE_NANOSLEEP)
1810 {
1811 struct timespec
1812 timer;
1813
1814 timer.tv_sec=(time_t) (milliseconds/1000);
1815 timer.tv_nsec=(milliseconds % 1000)*1000*1000;
1816 (void) nanosleep(&timer,(struct timespec *) NULL);
1817 }
1818#elif defined(MAGICKCORE_HAVE_USLEEP)
1819 usleep(1000*milliseconds);
1820#elif defined(MAGICKCORE_HAVE_SELECT)
1821 {
1822 struct timeval
1823 timer;
1824
1825 timer.tv_sec=(long) milliseconds/1000;
1826 timer.tv_usec=(long) (milliseconds % 1000)*1000;
1827 (void) select(0,(XFD_SET *) NULL,(XFD_SET *) NULL,(XFD_SET *) NULL,&timer);
1828 }
1829#elif defined(MAGICKCORE_HAVE_POLL)
1830 (void) poll((struct pollfd *) NULL,0,(int) milliseconds);
1831#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
1832 Sleep((long) milliseconds);
1833#elif defined(vms)
1834 {
1835 float
1836 timer;
1837
1838 timer=milliseconds/1000.0;
1839 lib$wait(&timer);
1840 }
1841#elif defined(__BEOS__)
1842 snooze(1000*milliseconds);
1843#else
1844# error "Time delay method not defined."
1845#endif
1846}
1847
1848/*
1849%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1850% %
1851% %
1852% %
cristy3ed852e2009-09-05 21:47:34 +00001853% M u l t i l i n e C e n s u s %
1854% %
1855% %
1856% %
1857%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1858%
1859% MultilineCensus() returns the number of lines within a label. A line is
1860% represented by a \n character.
1861%
1862% The format of the MultilineCenus method is:
1863%
cristybb503372010-05-27 20:51:26 +00001864% size_t MultilineCensus(const char *label)
cristy3ed852e2009-09-05 21:47:34 +00001865%
1866% A description of each parameter follows.
1867%
1868% o label: This character string is the label.
1869%
1870%
1871*/
cristybb503372010-05-27 20:51:26 +00001872MagickExport size_t MultilineCensus(const char *label)
cristy3ed852e2009-09-05 21:47:34 +00001873{
cristybb503372010-05-27 20:51:26 +00001874 size_t
cristy3ed852e2009-09-05 21:47:34 +00001875 number_lines;
1876
1877 /*
1878 Determine the number of lines within this label.
1879 */
1880 if (label == (char *) NULL)
1881 return(0);
1882 for (number_lines=1; *label != '\0'; label++)
1883 if (*label == '\n')
1884 number_lines++;
1885 return(number_lines);
1886}
1887
1888/*
1889%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1890% %
1891% %
1892% %
1893% O p e n M a g i c k S t r e a m %
1894% %
1895% %
1896% %
1897%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1898%
1899% OpenMagickStream() opens the file at the specified path and return the
1900% associated stream.
1901%
1902% The path of the OpenMagickStream method is:
1903%
1904% FILE *OpenMagickStream(const char *path,const char *mode)
1905%
1906% A description of each parameter follows.
1907%
1908% o path: the file path.
1909%
1910% o mode: the file mode.
1911%
1912*/
1913MagickExport FILE *OpenMagickStream(const char *path,const char *mode)
1914{
1915 FILE
1916 *file;
1917
1918 if ((path == (const char *) NULL) || (mode == (const char *) NULL))
1919 {
1920 errno=EINVAL;
1921 return((FILE *) NULL);
1922 }
1923 file=(FILE *) NULL;
1924#if defined(MAGICKCORE_HAVE__WFOPEN)
1925 {
1926 wchar_t
1927 *unicode_mode,
1928 *unicode_path;
1929
cristye7e40552010-04-24 21:34:22 +00001930 unicode_path=ConvertUTF8ToUTF16((const unsigned char *) path);
cristy3ed852e2009-09-05 21:47:34 +00001931 if (unicode_path == (wchar_t *) NULL)
1932 return((FILE *) NULL);
cristye20ffe52010-04-24 23:51:41 +00001933 unicode_mode=ConvertUTF8ToUTF16((const unsigned char *) mode);
cristy3ed852e2009-09-05 21:47:34 +00001934 if (unicode_mode == (wchar_t *) NULL)
1935 {
1936 unicode_path=(wchar_t *) RelinquishMagickMemory(unicode_path);
1937 return((FILE *) NULL);
1938 }
1939 file=_wfopen(unicode_path,unicode_mode);
1940 unicode_mode=(wchar_t *) RelinquishMagickMemory(unicode_mode);
1941 unicode_path=(wchar_t *) RelinquishMagickMemory(unicode_path);
1942 }
1943#endif
1944 if (file == (FILE *) NULL)
1945 file=fopen(path,mode);
1946 return(file);
1947}
1948
1949/*
1950%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1951% %
1952% %
1953% %
1954% S y s t e m C o m m a n d %
1955% %
1956% %
1957% %
1958%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1959%
1960% SystemCommand() executes the specified command and waits until it
1961% terminates. The returned value is the exit status of the command.
1962%
1963% The format of the SystemCommand method is:
1964%
cristy6de4bc22010-01-12 17:10:35 +00001965% int SystemCommand(const MagickBooleanType asynchronous,
1966% const MagickBooleanType verbose,const char *command,
cristyb32b90a2009-09-07 21:45:48 +00001967% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001968%
1969% A description of each parameter follows:
1970%
cristy6de4bc22010-01-12 17:10:35 +00001971% o asynchronous: a value other than 0 executes the parent program
1972% concurrently with the new child process.
1973%
cristyb32b90a2009-09-07 21:45:48 +00001974% o verbose: a value other than 0 prints the executed command before it is
cristy3ed852e2009-09-05 21:47:34 +00001975% invoked.
1976%
cristyb32b90a2009-09-07 21:45:48 +00001977% o command: this string is the command to execute.
1978%
1979% o exception: return any errors here.
cristy3ed852e2009-09-05 21:47:34 +00001980%
1981*/
cristy6de4bc22010-01-12 17:10:35 +00001982MagickExport int SystemCommand(const MagickBooleanType asynchronous,
1983 const MagickBooleanType verbose,const char *command,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001984{
cristyb32b90a2009-09-07 21:45:48 +00001985 char
cristy6de4bc22010-01-12 17:10:35 +00001986 **arguments,
1987 *shell_command;
cristyb32b90a2009-09-07 21:45:48 +00001988
cristy3ed852e2009-09-05 21:47:34 +00001989 int
cristyb32b90a2009-09-07 21:45:48 +00001990 number_arguments,
cristy3ed852e2009-09-05 21:47:34 +00001991 status;
1992
cristyb32b90a2009-09-07 21:45:48 +00001993 PolicyDomain
1994 domain;
1995
1996 PolicyRights
1997 rights;
1998
cristybb503372010-05-27 20:51:26 +00001999 register ssize_t
cristyb32b90a2009-09-07 21:45:48 +00002000 i;
2001
2002 status=(-1);
2003 arguments=StringToArgv(command,&number_arguments);
2004 if (arguments == (char **) NULL)
2005 return(status);
cristyb32b90a2009-09-07 21:45:48 +00002006 rights=ExecutePolicyRights;
cristy6de4bc22010-01-12 17:10:35 +00002007 domain=DelegatePolicyDomain;
cristyb32b90a2009-09-07 21:45:48 +00002008 if (IsRightsAuthorized(domain,rights,arguments[1]) == MagickFalse)
2009 {
cristya9197f62010-01-12 02:23:34 +00002010 errno=EPERM;
cristyb32b90a2009-09-07 21:45:48 +00002011 (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
2012 "NotAuthorized","`%s'",arguments[1]);
cristycee97112010-05-28 00:44:52 +00002013 for (i=0; i < (ssize_t) number_arguments; i++)
cristyb32b90a2009-09-07 21:45:48 +00002014 arguments[i]=DestroyString(arguments[i]);
2015 arguments=(char **) RelinquishMagickMemory(arguments);
2016 return(-1);
2017 }
cristy3ed852e2009-09-05 21:47:34 +00002018 if (verbose != MagickFalse)
2019 {
2020 (void) fprintf(stderr,"%s\n",command);
2021 (void) fflush(stderr);
2022 }
cristy6de4bc22010-01-12 17:10:35 +00002023 shell_command=(char *) command;
2024 if (asynchronous != MagickFalse)
2025 {
2026 shell_command=AcquireString(command);
2027 (void) ConcatenateMagickString(shell_command,"&",MaxTextExtent);
2028 }
cristy3ed852e2009-09-05 21:47:34 +00002029#if defined(MAGICKCORE_POSIX_SUPPORT)
cristya9197f62010-01-12 02:23:34 +00002030#if !defined(MAGICKCORE_HAVE_EXECVP)
cristy6de4bc22010-01-12 17:10:35 +00002031 status=system(shell_command);
cristy3ed852e2009-09-05 21:47:34 +00002032#else
cristy6de4bc22010-01-12 17:10:35 +00002033 if ((asynchronous != MagickFalse) || (strspn(shell_command,"&;<>|") == 0))
2034 status=system(shell_command);
cristy3ed852e2009-09-05 21:47:34 +00002035 else
2036 {
cristyb32b90a2009-09-07 21:45:48 +00002037 pid_t
2038 child_pid;
cristy3ed852e2009-09-05 21:47:34 +00002039
cristyb32b90a2009-09-07 21:45:48 +00002040 /*
2041 Call application directly rather than from a shell.
2042 */
2043 child_pid=fork();
2044 if (child_pid == (pid_t) -1)
cristy3ed852e2009-09-05 21:47:34 +00002045 status=system(command);
2046 else
cristyb32b90a2009-09-07 21:45:48 +00002047 if (child_pid == 0)
2048 {
2049 status=execvp(arguments[1],arguments+1);
2050 _exit(1);
2051 }
2052 else
2053 {
2054 int
2055 child_status;
cristy3ed852e2009-09-05 21:47:34 +00002056
cristyb32b90a2009-09-07 21:45:48 +00002057 pid_t
2058 pid;
cristy3ed852e2009-09-05 21:47:34 +00002059
cristyb32b90a2009-09-07 21:45:48 +00002060 child_status=0;
2061 pid=waitpid(child_pid,&child_status,0);
2062 if (pid == -1)
2063 status=(-1);
cristy3ed852e2009-09-05 21:47:34 +00002064 else
2065 {
cristyb32b90a2009-09-07 21:45:48 +00002066 if (WIFEXITED(child_status) != 0)
2067 status=WEXITSTATUS(child_status);
cristy3ed852e2009-09-05 21:47:34 +00002068 else
cristyb32b90a2009-09-07 21:45:48 +00002069 if (WIFSIGNALED(child_status))
2070 status=(-1);
cristy3ed852e2009-09-05 21:47:34 +00002071 }
cristyb32b90a2009-09-07 21:45:48 +00002072 }
cristy3ed852e2009-09-05 21:47:34 +00002073 }
2074#endif
cristy0157aea2010-04-24 21:12:18 +00002075#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
cristyceaf0142010-01-12 02:39:34 +00002076 {
2077 int
2078 mode;
2079
2080 mode=_P_WAIT;
cristy6de4bc22010-01-12 17:10:35 +00002081 if (asynchronous != MagickFalse)
2082 mode=_P_NOWAIT;
cristye7e40552010-04-24 21:34:22 +00002083 status=spawnvp(mode,arguments[1],(const char **) (arguments+1));
cristyceaf0142010-01-12 02:39:34 +00002084 }
cristy3ed852e2009-09-05 21:47:34 +00002085#elif defined(macintosh)
cristy6de4bc22010-01-12 17:10:35 +00002086 status=MACSystemCommand(shell_command);
cristy3ed852e2009-09-05 21:47:34 +00002087#elif defined(vms)
cristy6de4bc22010-01-12 17:10:35 +00002088 status=system(shell_command);
cristy3ed852e2009-09-05 21:47:34 +00002089#else
2090# error No suitable system() method.
2091#endif
2092 if (status < 0)
cristy6de4bc22010-01-12 17:10:35 +00002093 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
2094 "`%s' (%d)",command,status);
2095 if (shell_command != command)
2096 shell_command=DestroyString(shell_command);
cristycee97112010-05-28 00:44:52 +00002097 for (i=0; i < (ssize_t) number_arguments; i++)
cristyb32b90a2009-09-07 21:45:48 +00002098 arguments[i]=DestroyString(arguments[i]);
2099 arguments=(char **) RelinquishMagickMemory(arguments);
cristy3ed852e2009-09-05 21:47:34 +00002100 return(status);
2101}