blob: 7183bd7030106862d99c233bfae37544bbb13436 [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% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 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*/
cristy4c08aed2011-07-01 19:47:50 +000042#include "MagickCore/studio.h"
43#include "MagickCore/property.h"
44#include "MagickCore/blob.h"
45#include "MagickCore/color.h"
46#include "MagickCore/exception.h"
47#include "MagickCore/exception-private.h"
48#include "MagickCore/geometry.h"
49#include "MagickCore/list.h"
50#include "MagickCore/log.h"
cristy7832dc22011-09-05 01:21:53 +000051#include "MagickCore/magick-private.h"
cristy4c08aed2011-07-01 19:47:50 +000052#include "MagickCore/memory_.h"
53#include "MagickCore/option.h"
54#include "MagickCore/policy.h"
55#include "MagickCore/resource_.h"
56#include "MagickCore/semaphore.h"
57#include "MagickCore/signature-private.h"
58#include "MagickCore/statistic.h"
59#include "MagickCore/string_.h"
cristy7832dc22011-09-05 01:21:53 +000060#include "MagickCore/string-private.h"
cristy4c08aed2011-07-01 19:47:50 +000061#include "MagickCore/token.h"
cristy7832dc22011-09-05 01:21:53 +000062#include "MagickCore/token-private.h"
cristy4c08aed2011-07-01 19:47:50 +000063#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000064#include "MagickCore/utility-private.h"
cristy98e91bd2010-01-12 01:11:42 +000065#if defined(MAGICKCORE_HAVE_PROCESS_H)
66#include <process.h>
67#endif
cristy3ed852e2009-09-05 21:47:34 +000068#if defined(MAGICKCORE_HAVE_MACH_O_DYLD_H)
69#include <mach-o/dyld.h>
70#endif
71
72/*
73 Static declarations.
74*/
75static const char
76 Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
77
78/*
79 Forward declaration.
80*/
81static int
82 IsPathDirectory(const char *);
83
84/*
85%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
86% %
87% %
88% %
89% A c q u i r e U n i q u e F i l e n a m e %
90% %
91% %
92% %
93%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
94%
95% AcquireUniqueFilename() replaces the contents of path by a unique path name.
96%
97% The format of the AcquireUniqueFilename method is:
98%
99% MagickBooleanType AcquireUniqueFilename(char *path)
100%
101% A description of each parameter follows.
102%
103% o path: Specifies a pointer to an array of characters. The unique path
104% name is returned in this array.
105%
106*/
107MagickExport MagickBooleanType AcquireUniqueFilename(char *path)
108{
109 int
110 file;
111
112 file=AcquireUniqueFileResource(path);
113 if (file == -1)
114 return(MagickFalse);
115 file=close(file)-1;
116 return(MagickTrue);
117}
118
119/*
120%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
121% %
122% %
123% %
124% A c q u i r e U n i q u e S ym b o l i c L i n k %
125% %
126% %
127% %
128%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
129%
130% AcquireUniqueSymbolicLink() creates a unique symbolic link to the specified
131% source path and returns MagickTrue on success otherwise MagickFalse. If the
132% symlink() method fails or is not available, a unique file name is generated
133% and the source file copied to it. When you are finished with the file, use
134% RelinquishUniqueFilename() to destroy it.
135%
136% The format of the AcquireUniqueSymbolicLink method is:
137%
138% MagickBooleanType AcquireUniqueSymbolicLink(const char *source,
139% char destination)
140%
141% A description of each parameter follows.
142%
143% o source: the source path.
144%
145% o destination: the destination path.
146%
147*/
148
149static inline size_t MagickMin(const size_t x,const size_t y)
150{
151 if (x < y)
152 return(x);
153 return(y);
154}
155
156MagickExport MagickBooleanType AcquireUniqueSymbolicLink(const char *source,
157 char *destination)
158{
159 int
160 destination_file,
161 source_file;
162
163 size_t
164 length,
165 quantum;
166
167 ssize_t
168 count;
169
170 struct stat
171 attributes;
172
173 unsigned char
174 *buffer;
175
176 assert(source != (const char *) NULL);
177 assert(destination != (char *) NULL);
178#if defined(MAGICKCORE_HAVE_SYMLINK)
179 (void) AcquireUniqueFilename(destination);
180 (void) RelinquishUniqueFileResource(destination);
181 if (*source == *DirectorySeparator)
182 {
183 if (symlink(source,destination) == 0)
184 return(MagickTrue);
185 }
186 else
187 {
188 char
189 path[MaxTextExtent];
190
191 *path='\0';
192 if (getcwd(path,MaxTextExtent) == (char *) NULL)
193 return(MagickFalse);
194 (void) ConcatenateMagickString(path,DirectorySeparator,MaxTextExtent);
195 (void) ConcatenateMagickString(path,source,MaxTextExtent);
196 if (symlink(path,destination) == 0)
197 return(MagickTrue);
198 }
199#endif
200 destination_file=AcquireUniqueFileResource(destination);
201 if (destination_file == -1)
202 return(MagickFalse);
cristy18c6c272011-09-23 14:40:37 +0000203 source_file=open_utf8(source,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000204 if (source_file == -1)
205 {
206 (void) close(destination_file);
207 (void) RelinquishUniqueFileResource(destination);
208 return(MagickFalse);
209 }
210 quantum=(size_t) MagickMaxBufferExtent;
211 if ((fstat(source_file,&attributes) == 0) && (attributes.st_size != 0))
212 quantum=MagickMin((size_t) attributes.st_size,MagickMaxBufferExtent);
213 buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
214 if (buffer == (unsigned char *) NULL)
215 {
216 (void) close(source_file);
217 (void) close(destination_file);
218 (void) RelinquishUniqueFileResource(destination);
219 return(MagickFalse);
220 }
221 for (length=0; ; )
222 {
223 count=(ssize_t) read(source_file,buffer,quantum);
224 if (count <= 0)
225 break;
226 length=(size_t) count;
227 count=(ssize_t) write(destination_file,buffer,length);
228 if ((size_t) count != length)
229 {
230 (void) close(destination_file);
231 (void) close(source_file);
232 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
233 (void) RelinquishUniqueFileResource(destination);
234 return(MagickFalse);
235 }
236 }
237 (void) close(destination_file);
238 (void) close(source_file);
239 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
240 return(MagickTrue);
241}
242
243/*
244%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
245% %
246% %
247% %
248% A p p e n d I m a g e F o r m a t %
249% %
250% %
251% %
252%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
253%
254% AppendImageFormat() appends the image format type to the filename. If an
255% extension to the file already exists, it is first removed.
256%
257% The format of the AppendImageFormat method is:
258%
259% void AppendImageFormat(const char *format,char *filename)
260%
261% A description of each parameter follows.
262%
263% o format: Specifies a pointer to an array of characters. This the
264% format of the image.
265%
266% o filename: Specifies a pointer to an array of characters. The unique
267% file name is returned in this array.
268%
269*/
270MagickExport void AppendImageFormat(const char *format,char *filename)
271{
272 char
cristy212e2622010-06-12 19:07:47 +0000273 extension[MaxTextExtent],
cristy3ed852e2009-09-05 21:47:34 +0000274 root[MaxTextExtent];
275
276 assert(format != (char *) NULL);
277 assert(filename != (char *) NULL);
278 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
279 if ((*format == '\0') || (*filename == '\0'))
280 return;
281 if (LocaleCompare(filename,"-") == 0)
282 {
283 char
284 message[MaxTextExtent];
285
cristyb51dff52011-05-19 16:55:47 +0000286 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s",format,filename);
cristy3ed852e2009-09-05 21:47:34 +0000287 (void) CopyMagickString(filename,message,MaxTextExtent);
288 return;
289 }
cristy212e2622010-06-12 19:07:47 +0000290 GetPathComponent(filename,ExtensionPath,extension);
291 if ((LocaleCompare(extension,"Z") == 0) ||
292 (LocaleCompare(extension,"bz2") == 0) ||
293 (LocaleCompare(extension,"gz") == 0) ||
294 (LocaleCompare(extension,"wmz") == 0) ||
295 (LocaleCompare(extension,"svgz") == 0))
296 {
297 GetPathComponent(filename,RootPath,root);
298 (void) CopyMagickString(filename,root,MaxTextExtent);
299 GetPathComponent(filename,RootPath,root);
cristyb51dff52011-05-19 16:55:47 +0000300 (void) FormatLocaleString(filename,MaxTextExtent,"%s.%s.%s",root,format,
cristy212e2622010-06-12 19:07:47 +0000301 extension);
302 return;
303 }
cristy3ed852e2009-09-05 21:47:34 +0000304 GetPathComponent(filename,RootPath,root);
cristyb51dff52011-05-19 16:55:47 +0000305 (void) FormatLocaleString(filename,MaxTextExtent,"%s.%s",root,format);
cristy3ed852e2009-09-05 21:47:34 +0000306}
307
308/*
309%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
310% %
311% %
312% %
313% B a s e 6 4 D e c o d e %
314% %
315% %
316% %
317%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
318%
319% Base64Decode() decodes Base64-encoded text and returns its binary
320% equivalent. NULL is returned if the text is not valid Base64 data, or a
321% memory allocation failure occurs.
322%
323% The format of the Base64Decode method is:
324%
325% unsigned char *Base64Decode(const char *source,length_t *length)
326%
327% A description of each parameter follows:
328%
329% o source: A pointer to a Base64-encoded string.
330%
331% o length: the number of bytes decoded.
332%
333*/
334MagickExport unsigned char *Base64Decode(const char *source,size_t *length)
335{
336 int
337 state;
338
339 register const char
340 *p,
341 *q;
342
343 register size_t
344 i;
345
346 unsigned char
347 *decode;
348
349 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
350 assert(source != (char *) NULL);
351 assert(length != (size_t *) NULL);
352 *length=0;
353 decode=(unsigned char *) AcquireQuantumMemory(strlen(source)/4+4,
354 3*sizeof(*decode));
355 if (decode == (unsigned char *) NULL)
356 return((unsigned char *) NULL);
357 i=0;
358 state=0;
359 for (p=source; *p != '\0'; p++)
360 {
361 if (isspace((int) ((unsigned char) *p)) != 0)
362 continue;
363 if (*p == '=')
364 break;
365 q=strchr(Base64,*p);
366 if (q == (char *) NULL)
367 {
368 decode=(unsigned char *) RelinquishMagickMemory(decode);
369 return((unsigned char *) NULL); /* non-Base64 character */
370 }
371 switch (state)
372 {
373 case 0:
374 {
375 decode[i]=(q-Base64) << 2;
376 state++;
377 break;
378 }
379 case 1:
380 {
381 decode[i++]|=(q-Base64) >> 4;
382 decode[i]=((q-Base64) & 0x0f) << 4;
383 state++;
384 break;
385 }
386 case 2:
387 {
388 decode[i++]|=(q-Base64) >> 2;
389 decode[i]=((q-Base64) & 0x03) << 6;
390 state++;
391 break;
392 }
393 case 3:
394 {
395 decode[i++]|=(q-Base64);
396 state=0;
397 break;
398 }
399 }
400 }
401 /*
402 Verify Base-64 string has proper terminal characters.
403 */
404 if (*p != '=')
405 {
406 if (state != 0)
407 {
408 decode=(unsigned char *) RelinquishMagickMemory(decode);
409 return((unsigned char *) NULL);
410 }
411 }
412 else
413 {
414 p++;
415 switch (state)
416 {
417 case 0:
418 case 1:
419 {
420 /*
421 Unrecognized '=' character.
422 */
423 decode=(unsigned char *) RelinquishMagickMemory(decode);
424 return((unsigned char *) NULL);
425 }
426 case 2:
427 {
428 for ( ; *p != '\0'; p++)
429 if (isspace((int) ((unsigned char) *p)) == 0)
430 break;
431 if (*p != '=')
432 {
433 decode=(unsigned char *) RelinquishMagickMemory(decode);
434 return((unsigned char *) NULL);
435 }
436 p++;
437 }
438 case 3:
439 {
440 for ( ; *p != '\0'; p++)
441 if (isspace((int) ((unsigned char) *p)) == 0)
442 {
443 decode=(unsigned char *) RelinquishMagickMemory(decode);
444 return((unsigned char *) NULL);
445 }
446 if ((int) decode[i] != 0)
447 {
448 decode=(unsigned char *) RelinquishMagickMemory(decode);
449 return((unsigned char *) NULL);
450 }
451 }
452 }
453 }
454 *length=i;
455 return(decode);
456}
457
458/*
459%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
460% %
461% %
462% %
463% B a s e 6 4 E n c o d e %
464% %
465% %
466% %
467%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
468%
469% Base64Encode() encodes arbitrary binary data to Base64 encoded format as
470% described by the "Base64 Content-Transfer-Encoding" section of RFC 2045 and
471% returns the result as a null-terminated ASCII string. NULL is returned if
472% a memory allocation failure occurs.
473%
474% The format of the Base64Encode method is:
475%
476% char *Base64Encode(const unsigned char *blob,const size_t blob_length,
477% size_t *encode_length)
478%
479% A description of each parameter follows:
480%
481% o blob: A pointer to binary data to encode.
482%
483% o blob_length: the number of bytes to encode.
484%
485% o encode_length: The number of bytes encoded.
486%
487*/
488MagickExport char *Base64Encode(const unsigned char *blob,
489 const size_t blob_length,size_t *encode_length)
490{
491 char
492 *encode;
493
494 register const unsigned char
495 *p;
496
497 register size_t
498 i;
499
500 size_t
501 remainder;
502
503 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
504 assert(blob != (const unsigned char *) NULL);
505 assert(blob_length != 0);
506 assert(encode_length != (size_t *) NULL);
507 *encode_length=0;
508 encode=(char *) AcquireQuantumMemory(blob_length/3+4,4*sizeof(*encode));
509 if (encode == (char *) NULL)
510 return((char *) NULL);
511 i=0;
512 for (p=blob; p < (blob+blob_length-2); p+=3)
513 {
514 encode[i++]=Base64[(int) (*p >> 2)];
515 encode[i++]=Base64[(int) (((*p & 0x03) << 4)+(*(p+1) >> 4))];
516 encode[i++]=Base64[(int) (((*(p+1) & 0x0f) << 2)+(*(p+2) >> 6))];
517 encode[i++]=Base64[(int) (*(p+2) & 0x3f)];
518 }
519 remainder=blob_length % 3;
520 if (remainder != 0)
521 {
cristybb503372010-05-27 20:51:26 +0000522 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000523 j;
524
525 unsigned char
526 code[3];
527
528 code[0]='\0';
529 code[1]='\0';
530 code[2]='\0';
cristybb503372010-05-27 20:51:26 +0000531 for (j=0; j < (ssize_t) remainder; j++)
cristy3ed852e2009-09-05 21:47:34 +0000532 code[j]=(*p++);
533 encode[i++]=Base64[(int) (code[0] >> 2)];
534 encode[i++]=Base64[(int) (((code[0] & 0x03) << 4)+(code[1] >> 4))];
535 if (remainder == 1)
536 encode[i++]='=';
537 else
538 encode[i++]=Base64[(int) (((code[1] & 0x0f) << 2)+(code[2] >> 6))];
539 encode[i++]='=';
540 }
541 *encode_length=i;
542 encode[i++]='\0';
543 return(encode);
544}
545
546/*
547%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
548% %
549% %
550% %
551% C h o p P a t h C o m p o n e n t s %
552% %
553% %
554% %
555%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
556%
557% ChopPathComponents() removes the number of specified file components from a
558% path.
559%
560% The format of the ChopPathComponents method is:
561%
cristybb503372010-05-27 20:51:26 +0000562% ChopPathComponents(char *path,size_t components)
cristy3ed852e2009-09-05 21:47:34 +0000563%
564% A description of each parameter follows:
565%
566% o path: The path.
567%
568% o components: The number of components to chop.
569%
570*/
cristyd1dd6e42011-09-04 01:46:08 +0000571MagickPrivate void ChopPathComponents(char *path,const size_t components)
cristy3ed852e2009-09-05 21:47:34 +0000572{
cristybb503372010-05-27 20:51:26 +0000573 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000574 i;
575
cristybb503372010-05-27 20:51:26 +0000576 for (i=0; i < (ssize_t) components; i++)
cristy3ed852e2009-09-05 21:47:34 +0000577 GetPathComponent(path,HeadPath,path);
578}
579
580/*
581%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
582% %
583% %
584% %
585% E x p a n d F i l e n a m e %
586% %
587% %
588% %
589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
590%
591% ExpandFilename() expands '~' in a path.
592%
593% The format of the ExpandFilename function is:
594%
595% ExpandFilename(char *path)
596%
597% A description of each parameter follows:
598%
599% o path: Specifies a pointer to a character array that contains the
600% path.
601%
602*/
cristyd1dd6e42011-09-04 01:46:08 +0000603MagickPrivate void ExpandFilename(char *path)
cristy3ed852e2009-09-05 21:47:34 +0000604{
605 char
606 expand_path[MaxTextExtent];
607
608 if (path == (char *) NULL)
609 return;
610 if (*path != '~')
611 return;
612 (void) CopyMagickString(expand_path,path,MaxTextExtent);
613 if ((*(path+1) == *DirectorySeparator) || (*(path+1) == '\0'))
614 {
615 char
616 *home;
617
618 /*
619 Substitute ~ with $HOME.
620 */
621 (void) CopyMagickString(expand_path,".",MaxTextExtent);
622 (void) ConcatenateMagickString(expand_path,path+1,MaxTextExtent);
623 home=GetEnvironmentValue("HOME");
624 if (home == (char *) NULL)
625 home=GetEnvironmentValue("USERPROFILE");
626 if (home != (char *) NULL)
627 {
628 (void) CopyMagickString(expand_path,home,MaxTextExtent);
629 (void) ConcatenateMagickString(expand_path,path+1,MaxTextExtent);
630 home=DestroyString(home);
631 }
632 }
633 else
634 {
635#if defined(MAGICKCORE_POSIX_SUPPORT) && !defined(__OS2__)
636 char
637 username[MaxTextExtent];
638
639 register char
640 *p;
641
642 struct passwd
643 *entry;
644
645 /*
646 Substitute ~ with home directory from password file.
647 */
648 (void) CopyMagickString(username,path+1,MaxTextExtent);
649 p=strchr(username,'/');
650 if (p != (char *) NULL)
651 *p='\0';
652 entry=getpwnam(username);
653 if (entry == (struct passwd *) NULL)
654 return;
655 (void) CopyMagickString(expand_path,entry->pw_dir,MaxTextExtent);
656 if (p != (char *) NULL)
657 {
658 (void) ConcatenateMagickString(expand_path,"/",MaxTextExtent);
659 (void) ConcatenateMagickString(expand_path,p+1,MaxTextExtent);
660 }
661#endif
662 }
663 (void) CopyMagickString(path,expand_path,MaxTextExtent);
664}
665
666/*
667%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
668% %
669% %
670% %
671% E x p a n d F i l e n a m e s %
672% %
673% %
674% %
675%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
676%
677% ExpandFilenames() checks each argument of the command line vector and
678% expands it if they have a wildcard character. For example, *.jpg might
679% expand to: bird.jpg rose.jpg tiki.jpg.
680%
681% The format of the ExpandFilenames function is:
682%
683% status=ExpandFilenames(int *number_arguments,char ***arguments)
684%
685% A description of each parameter follows:
686%
687% o number_arguments: Specifies a pointer to an integer describing the
688% number of elements in the argument vector.
689%
690% o arguments: Specifies a pointer to a text array containing the command
691% line arguments.
692%
693*/
694MagickExport MagickBooleanType ExpandFilenames(int *number_arguments,
695 char ***arguments)
696{
697 char
cristy00976d82011-02-20 20:31:28 +0000698 *directory,
cristy3ed852e2009-09-05 21:47:34 +0000699 home_directory[MaxTextExtent],
700 **vector;
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
cristy00976d82011-02-20 20:31:28 +0000709 ssize_t
710 count,
711 parameters;
712
cristy3ed852e2009-09-05 21:47:34 +0000713 /*
714 Allocate argument vector.
715 */
716 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
717 assert(number_arguments != (int *) NULL);
718 assert(arguments != (char ***) NULL);
719 vector=(char **) AcquireQuantumMemory((size_t) (*number_arguments+1),
720 sizeof(*vector));
721 if (vector == (char **) NULL)
722 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
723 /*
724 Expand any wildcard filenames.
725 */
726 *home_directory='\0';
cristy3ed852e2009-09-05 21:47:34 +0000727 count=0;
cristybb503372010-05-27 20:51:26 +0000728 for (i=0; i < (ssize_t) *number_arguments; i++)
cristy3ed852e2009-09-05 21:47:34 +0000729 {
730 char
731 **filelist,
732 filename[MaxTextExtent],
733 magick[MaxTextExtent],
734 *option,
735 path[MaxTextExtent],
736 subimage[MaxTextExtent];
737
738 MagickBooleanType
739 destroy;
740
741 option=(*arguments)[i];
742 *magick='\0';
743 *path='\0';
744 *filename='\0';
745 *subimage='\0';
746 vector[count++]=ConstantString(option);
747 destroy=MagickTrue;
cristy042ee782011-04-22 18:48:30 +0000748 parameters=ParseCommandOption(MagickCommandOptions,MagickFalse,option);
cristy3ed852e2009-09-05 21:47:34 +0000749 if (parameters > 0)
750 {
751 /*
752 Do not expand command option parameters.
753 */
754 for (j=0; j < parameters; j++)
755 {
756 i++;
cristybb503372010-05-27 20:51:26 +0000757 if (i == (ssize_t) *number_arguments)
cristy3ed852e2009-09-05 21:47:34 +0000758 break;
759 option=(*arguments)[i];
760 vector[count++]=ConstantString(option);
761 }
762 continue;
763 }
764 if ((*option == '"') || (*option == '\''))
765 continue;
766 GetPathComponent(option,TailPath,filename);
767 GetPathComponent(option,MagickPath,magick);
768 if ((LocaleCompare(magick,"CAPTION") == 0) ||
769 (LocaleCompare(magick,"LABEL") == 0) ||
770 (LocaleCompare(magick,"VID") == 0))
771 continue;
772 if ((IsGlob(filename) == MagickFalse) && (*filename != '@'))
773 continue;
774 if (*filename != '@')
775 {
776 /*
777 Generate file list from wildcard filename (e.g. *.jpg).
778 */
779 GetPathComponent(option,HeadPath,path);
780 GetPathComponent(option,SubimagePath,subimage);
781 ExpandFilename(path);
cristyf5ee5be2009-11-06 02:22:56 +0000782 if (*home_directory == '\0')
cristy00976d82011-02-20 20:31:28 +0000783 directory=getcwd(home_directory,MaxTextExtent-1);
784 (void) directory;
cristy3ed852e2009-09-05 21:47:34 +0000785 filelist=ListFiles(*path == '\0' ? home_directory : path,filename,
786 &number_files);
787 }
788 else
789 {
790 char
791 *files;
792
793 ExceptionInfo
794 *exception;
795
796 int
cristyf9218a72010-07-03 17:29:40 +0000797 length;
cristy3ed852e2009-09-05 21:47:34 +0000798
799 /*
800 Generate file list from file list (e.g. @filelist.txt).
801 */
802 exception=AcquireExceptionInfo();
803 files=FileToString(filename+1,~0,exception);
804 exception=DestroyExceptionInfo(exception);
805 if (files == (char *) NULL)
806 continue;
cristyf9218a72010-07-03 17:29:40 +0000807 filelist=StringToArgv(files,&length);
808 if (filelist == (char **) NULL)
809 continue;
cristy3ed852e2009-09-05 21:47:34 +0000810 files=DestroyString(files);
cristyf9218a72010-07-03 17:29:40 +0000811 filelist[0]=DestroyString(filelist[0]);
812 for (j=0; j < (ssize_t) (length-1); j++)
813 filelist[j]=filelist[j+1];
814 number_files=(size_t) length-1;
cristy3ed852e2009-09-05 21:47:34 +0000815 }
816 if (filelist == (char **) NULL)
817 continue;
cristybb503372010-05-27 20:51:26 +0000818 for (j=0; j < (ssize_t) number_files; j++)
cristy3ed852e2009-09-05 21:47:34 +0000819 if (IsPathDirectory(filelist[j]) <= 0)
820 break;
cristybb503372010-05-27 20:51:26 +0000821 if (j == (ssize_t) number_files)
cristy3ed852e2009-09-05 21:47:34 +0000822 {
cristybb503372010-05-27 20:51:26 +0000823 for (j=0; j < (ssize_t) number_files; j++)
cristy3ed852e2009-09-05 21:47:34 +0000824 filelist[j]=DestroyString(filelist[j]);
825 filelist=(char **) RelinquishMagickMemory(filelist);
826 continue;
827 }
828 /*
829 Transfer file list to argument vector.
830 */
831 vector=(char **) ResizeQuantumMemory(vector,(size_t) *number_arguments+
832 count+number_files+1,sizeof(*vector));
833 if (vector == (char **) NULL)
834 return(MagickFalse);
cristybb503372010-05-27 20:51:26 +0000835 for (j=0; j < (ssize_t) number_files; j++)
cristy3ed852e2009-09-05 21:47:34 +0000836 {
cristy0e526222010-05-06 14:07:32 +0000837 option=filelist[j];
cristy042ee782011-04-22 18:48:30 +0000838 parameters=ParseCommandOption(MagickCommandOptions,MagickFalse,option);
cristy0e526222010-05-06 14:07:32 +0000839 if (parameters > 0)
840 {
cristybb503372010-05-27 20:51:26 +0000841 ssize_t
cristy0e526222010-05-06 14:07:32 +0000842 k;
843
844 /*
845 Do not expand command option parameters.
846 */
847 vector[count++]=ConstantString(option);
848 for (k=0; k < parameters; k++)
849 {
850 j++;
cristybb503372010-05-27 20:51:26 +0000851 if (j == (ssize_t) number_files)
cristy0e526222010-05-06 14:07:32 +0000852 break;
853 option=filelist[j];
854 vector[count++]=ConstantString(option);
855 }
856 continue;
857 }
cristy3ed852e2009-09-05 21:47:34 +0000858 (void) CopyMagickString(filename,path,MaxTextExtent);
859 if (*path != '\0')
860 (void) ConcatenateMagickString(filename,DirectorySeparator,
861 MaxTextExtent);
862 (void) ConcatenateMagickString(filename,filelist[j],MaxTextExtent);
863 filelist[j]=DestroyString(filelist[j]);
cristycfef62c2010-05-05 01:21:43 +0000864 if (strlen(filename) >= (MaxTextExtent-1))
cristy3ed852e2009-09-05 21:47:34 +0000865 ThrowFatalException(OptionFatalError,"FilenameTruncated");
cristy47dc34d2010-04-22 16:12:43 +0000866 if (IsPathDirectory(filename) <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000867 {
868 char
869 path[MaxTextExtent];
870
871 *path='\0';
872 if (*magick != '\0')
873 {
874 (void) ConcatenateMagickString(path,magick,MaxTextExtent);
875 (void) ConcatenateMagickString(path,":",MaxTextExtent);
876 }
877 (void) ConcatenateMagickString(path,filename,MaxTextExtent);
878 if (*subimage != '\0')
879 {
880 (void) ConcatenateMagickString(path,"[",MaxTextExtent);
881 (void) ConcatenateMagickString(path,subimage,MaxTextExtent);
882 (void) ConcatenateMagickString(path,"]",MaxTextExtent);
883 }
cristy37e0b382011-06-07 13:31:21 +0000884 if (strlen(path) >= (MaxTextExtent-1))
cristy3ed852e2009-09-05 21:47:34 +0000885 ThrowFatalException(OptionFatalError,"FilenameTruncated");
886 if (destroy != MagickFalse)
887 {
888 count--;
889 vector[count]=DestroyString(vector[count]);
890 destroy=MagickFalse;
891 }
892 vector[count++]=ConstantString(path);
893 }
894 }
895 filelist=(char **) RelinquishMagickMemory(filelist);
896 }
897 vector[count]=(char *) NULL;
898 if (IsEventLogging() != MagickFalse)
899 {
900 char
901 *command_line;
902
903 command_line=AcquireString(vector[0]);
904 for (i=1; i < count; i++)
905 {
906 (void) ConcatenateString(&command_line," {");
907 (void) ConcatenateString(&command_line,vector[i]);
908 (void) ConcatenateString(&command_line,"}");
909 }
910 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
911 "Command line: %s",command_line);
912 command_line=DestroyString(command_line);
913 }
914 *number_arguments=(int) count;
915 *arguments=vector;
916 return(MagickTrue);
917}
918
919/*
920%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
921% %
922% %
923% %
924% G e t E x e c u t i o n P a t h %
925% %
926% %
927% %
928%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
929%
930% GetExecutionPath() returns the pathname of the executable that started
931% the process. On success MagickTrue is returned, otherwise MagickFalse.
932%
933% The format of the GetExecutionPath method is:
934%
935% MagickBooleanType GetExecutionPath(char *path,const size_t extent)
936%
937% A description of each parameter follows:
938%
939% o path: the pathname of the executable that started the process.
940%
941% o extent: the maximum extent of the path.
942%
943*/
cristyd1dd6e42011-09-04 01:46:08 +0000944MagickPrivate MagickBooleanType GetExecutionPath(char *path,const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +0000945{
cristyfbe485a2011-02-22 13:54:48 +0000946 char
947 *directory;
948
cristy3ed852e2009-09-05 21:47:34 +0000949 *path='\0';
cristyfbe485a2011-02-22 13:54:48 +0000950 directory=getcwd(path,(unsigned long) extent);
951 (void) directory;
cristyfa09d142009-10-15 01:02:25 +0000952#if defined(MAGICKCORE_HAVE_GETPID) && defined(MAGICKCORE_HAVE_READLINK) && defined(PATH_MAX)
cristy3ed852e2009-09-05 21:47:34 +0000953 {
954 char
955 link_path[MaxTextExtent],
cristyfa09d142009-10-15 01:02:25 +0000956 execution_path[PATH_MAX+1];
cristy3ed852e2009-09-05 21:47:34 +0000957
958 ssize_t
959 count;
960
cristyb51dff52011-05-19 16:55:47 +0000961 (void) FormatLocaleString(link_path,MaxTextExtent,"/proc/%.20g/exe",
cristye8c25f92010-06-03 00:53:06 +0000962 (double) getpid());
cristyfa09d142009-10-15 01:02:25 +0000963 count=readlink(link_path,execution_path,PATH_MAX);
cristy3ed852e2009-09-05 21:47:34 +0000964 if (count == -1)
965 {
cristyb51dff52011-05-19 16:55:47 +0000966 (void) FormatLocaleString(link_path,MaxTextExtent,"/proc/%.20g/file",
cristye8c25f92010-06-03 00:53:06 +0000967 (double) getpid());
cristyfa09d142009-10-15 01:02:25 +0000968 count=readlink(link_path,execution_path,PATH_MAX);
cristy3ed852e2009-09-05 21:47:34 +0000969 }
970 if ((count > 0) && (count <= (ssize_t) PATH_MAX))
971 {
cristyfa09d142009-10-15 01:02:25 +0000972 execution_path[count]='\0';
973 (void) CopyMagickString(path,execution_path,extent);
cristy3ed852e2009-09-05 21:47:34 +0000974 }
975 }
976#endif
977#if defined(MAGICKCORE_HAVE__NSGETEXECUTABLEPATH)
978 {
979 char
980 executable_path[PATH_MAX << 1],
cristyfa09d142009-10-15 01:02:25 +0000981 execution_path[PATH_MAX+1];
cristy3ed852e2009-09-05 21:47:34 +0000982
983 uint32_t
984 length;
985
986 length=sizeof(executable_path);
987 if ((_NSGetExecutablePath(executable_path,&length) == 0) &&
cristyfa09d142009-10-15 01:02:25 +0000988 (realpath(executable_path,execution_path) != (char *) NULL))
989 (void) CopyMagickString(path,execution_path,extent);
cristy3ed852e2009-09-05 21:47:34 +0000990 }
991#endif
992#if defined(MAGICKCORE_HAVE_GETEXECNAME)
993 {
994 const char
995 *execution_path;
996
997 execution_path=(const char *) getexecname();
998 if (execution_path != (const char *) NULL)
999 {
1000 if (*execution_path != *DirectorySeparator)
1001 (void) ConcatenateMagickString(path,DirectorySeparator,extent);
1002 (void) ConcatenateMagickString(path,execution_path,extent);
1003 }
1004 }
1005#endif
cristy0157aea2010-04-24 21:12:18 +00001006#if defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +00001007 NTGetExecutionPath(path,extent);
1008#endif
cristyfa09d142009-10-15 01:02:25 +00001009#if defined(__GNU__)
1010 {
1011 char
1012 *program_name,
1013 *execution_path;
1014
cristybb503372010-05-27 20:51:26 +00001015 ssize_t
cristyfa09d142009-10-15 01:02:25 +00001016 count;
1017
1018 count=0;
1019 execution_path=(char *) NULL;
1020 program_name=program_invocation_name;
1021 if (*program_invocation_name != '/')
1022 {
1023 size_t
1024 extent;
1025
cristyb29bea52011-05-26 17:54:31 +00001026 extent=strlen(directory)+strlen(program_name)+2;
cristyfa09d142009-10-15 01:02:25 +00001027 program_name=AcquireQuantumMemory(extent,sizeof(*program_name));
1028 if (program_name == (char *) NULL)
1029 program_name=program_invocation_name;
1030 else
cristyb29bea52011-05-26 17:54:31 +00001031 count=FormatLocaleString(program_name,extent,"%s/%s",directory,
cristyfa09d142009-10-15 01:02:25 +00001032 program_invocation_name);
1033 }
1034 if (count != -1)
1035 {
1036 execution_path=realpath(program_name,NULL);
1037 if (execution_path != (char *) NULL)
1038 (void) CopyMagickString(path,execution_path,extent);
1039 }
1040 if (program_name != program_invocation_name)
1041 program_name=(char *) RelinquishMagickMemory(program_name);
1042 execution_path=(char *) RelinquishMagickMemory(execution_path);
1043 }
1044#endif
cristy3ed852e2009-09-05 21:47:34 +00001045 return(IsPathAccessible(path));
1046}
1047
1048/*
1049%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1050% %
1051% %
1052% %
cristy688f07b2009-09-27 15:19:13 +00001053% G e t M a g i c k P a g e S i z e %
1054% %
1055% %
1056% %
1057%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1058%
1059% GetMagickPageSize() returns the memory page size.
1060%
1061% The format of the GetMagickPageSize method is:
1062%
cristybb503372010-05-27 20:51:26 +00001063% ssize_t GetMagickPageSize()
cristy688f07b2009-09-27 15:19:13 +00001064%
1065*/
cristyd1dd6e42011-09-04 01:46:08 +00001066MagickPrivate ssize_t GetMagickPageSize(void)
cristy688f07b2009-09-27 15:19:13 +00001067{
cristybb503372010-05-27 20:51:26 +00001068 static ssize_t
cristy688f07b2009-09-27 15:19:13 +00001069 page_size = -1;
1070
1071 if (page_size > 0)
1072 return(page_size);
1073#if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
cristyecd0ab52010-05-30 14:59:20 +00001074 page_size=(ssize_t) sysconf(_SC_PAGE_SIZE);
cristy09449f72010-01-23 03:08:36 +00001075#else
cristy688f07b2009-09-27 15:19:13 +00001076#if defined(MAGICKCORE_HAVE_GETPAGESIZE)
cristyecd0ab52010-05-30 14:59:20 +00001077 page_size=(ssize_t) getpagesize();
cristy09449f72010-01-23 03:08:36 +00001078#endif
cristy688f07b2009-09-27 15:19:13 +00001079#endif
1080 if (page_size <= 0)
1081 page_size=16384;
1082 return(page_size);
1083}
1084
1085/*
1086%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1087% %
1088% %
1089% %
cristy3ed852e2009-09-05 21:47:34 +00001090% G e t P a t h A t t r i b u t e s %
1091% %
1092% %
1093% %
1094%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1095%
1096% GetPathAttributes() returns attributes (e.g. size of file) about a path.
1097%
1098% The path of the GetPathAttributes method is:
1099%
1100% MagickBooleanType GetPathAttributes(const char *path,void *attributes)
1101%
1102% A description of each parameter follows.
1103%
1104% o path: the file path.
1105%
1106% o attributes: the path attributes are returned here.
1107%
1108*/
cristy3ed852e2009-09-05 21:47:34 +00001109MagickExport MagickBooleanType GetPathAttributes(const char *path,
1110 void *attributes)
1111{
1112 MagickBooleanType
1113 status;
1114
1115 if (path == (const char *) NULL)
1116 {
1117 errno=EINVAL;
1118 return(MagickFalse);
1119 }
cristy18c6c272011-09-23 14:40:37 +00001120 status=stat_utf8(path,(struct stat *) attributes) == 0 ? MagickTrue :
1121 MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00001122 return(status);
1123}
1124
1125/*
1126%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1127% %
1128% %
1129% %
1130% G e t P a t h C o m p o n e n t %
1131% %
1132% %
1133% %
1134%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1135%
1136% GetPathComponent() returns the parent directory name, filename, basename, or
1137% extension of a file path.
1138%
1139% The format of the GetPathComponent function is:
1140%
1141% GetPathComponent(const char *path,PathType type,char *component)
1142%
1143% A description of each parameter follows:
1144%
1145% o path: Specifies a pointer to a character array that contains the
1146% file path.
1147%
1148% o type: Specififies which file path component to return.
1149%
1150% o component: the selected file path component is returned here.
1151%
1152*/
1153MagickExport void GetPathComponent(const char *path,PathType type,
1154 char *component)
1155{
1156 char
1157 magick[MaxTextExtent],
1158 *q,
1159 subimage[MaxTextExtent];
1160
1161 register char
1162 *p;
1163
1164 assert(path != (const char *) NULL);
1165 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",path);
1166 assert(component != (char *) NULL);
1167 if (*path == '\0')
1168 {
1169 *component='\0';
1170 return;
1171 }
1172 (void) CopyMagickString(component,path,MaxTextExtent);
1173 *magick='\0';
cristy1224a992011-10-12 19:23:41 +00001174#if defined(__OS2__)
1175 if (path[1] != ":")
1176#endif
1177 for (p=component; *p != '\0'; p++)
1178 {
1179 if ((*p == '%') && (*(p+1) == '['))
1180 {
1181 /*
1182 Skip over %[...].
1183 */
1184 for (p++; (*p != ']') && (*p != '\0'); p++) ;
1185 if (*p == '\0')
1186 break;
1187 }
1188 if ((*p == ':') && (IsPathDirectory(path) < 0) &&
1189 (IsPathAccessible(path) == MagickFalse))
1190 {
1191 /*
1192 Look for image format specification (e.g. ps3:image).
1193 */
1194 (void) CopyMagickString(magick,component,(size_t) (p-component+1));
1195 if (IsMagickConflict(magick) != MagickFalse)
1196 *magick='\0';
1197 else
1198 for (q=component; *q != '\0'; q++)
1199 *q=(*++p);
1200 break;
1201 }
1202 }
cristy86057c42011-08-03 18:12:58 +00001203 *subimage='\0';
1204 p=component;
1205 if (*p != '\0')
1206 p=component+strlen(component)-1;
1207 if ((*p == ']') && (strchr(component,'[') != (char *) NULL) &&
1208 (IsPathAccessible(path) == MagickFalse))
1209 {
1210 /*
1211 Look for scene specification (e.g. img0001.pcd[4]).
1212 */
1213 for (q=p-1; q > component; q--)
1214 if (*q == '[')
1215 break;
1216 if (*q == '[')
1217 {
1218 (void) CopyMagickString(subimage,q+1,MaxTextExtent);
1219 subimage[p-q-1]='\0';
1220 if ((IsSceneGeometry(subimage,MagickFalse) == MagickFalse) &&
1221 (IsGeometry(subimage) == MagickFalse))
1222 *subimage='\0';
cristy1224a992011-10-12 19:23:41 +00001223 else
1224 *q='\0';
cristy86057c42011-08-03 18:12:58 +00001225 }
1226 }
cristy3ed852e2009-09-05 21:47:34 +00001227 p=component;
1228 if (*p != '\0')
1229 for (p=component+strlen(component)-1; p > component; p--)
1230 if (IsBasenameSeparator(*p) != MagickFalse)
1231 break;
1232 switch (type)
1233 {
1234 case MagickPath:
1235 {
1236 (void) CopyMagickString(component,magick,MaxTextExtent);
1237 break;
1238 }
1239 case RootPath:
1240 {
1241 for (p=component+(strlen(component)-1); p > component; p--)
1242 {
1243 if (IsBasenameSeparator(*p) != MagickFalse)
1244 break;
1245 if (*p == '.')
1246 break;
1247 }
1248 if (*p == '.')
1249 *p='\0';
1250 break;
1251 }
1252 case HeadPath:
1253 {
1254 *p='\0';
1255 break;
1256 }
1257 case TailPath:
1258 {
1259 if (IsBasenameSeparator(*p) != MagickFalse)
1260 (void) CopyMagickMemory((unsigned char *) component,
1261 (const unsigned char *) (p+1),strlen(p+1)+1);
1262 break;
1263 }
1264 case BasePath:
1265 {
1266 if (IsBasenameSeparator(*p) != MagickFalse)
1267 (void) CopyMagickString(component,p+1,MaxTextExtent);
1268 for (p=component+(strlen(component)-1); p > component; p--)
1269 if (*p == '.')
1270 {
1271 *p='\0';
1272 break;
1273 }
1274 break;
1275 }
1276 case ExtensionPath:
1277 {
1278 if (IsBasenameSeparator(*p) != MagickFalse)
1279 (void) CopyMagickString(component,p+1,MaxTextExtent);
1280 p=component;
1281 if (*p != '\0')
1282 for (p=component+strlen(component)-1; p > component; p--)
1283 if (*p == '.')
1284 break;
1285 *component='\0';
1286 if (*p == '.')
1287 (void) CopyMagickString(component,p+1,MaxTextExtent);
1288 break;
1289 }
1290 case SubimagePath:
1291 {
1292 (void) CopyMagickString(component,subimage,MaxTextExtent);
1293 break;
1294 }
1295 case CanonicalPath:
1296 case UndefinedPath:
1297 break;
1298 }
1299}
1300
1301/*
1302%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1303% %
1304% %
1305% %
1306% G e t P a t h C o m p o n e n t s %
1307% %
1308% %
1309% %
1310%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1311%
1312% GetPathComponents() returns a list of path components.
1313%
1314% The format of the GetPathComponents method is:
1315%
1316% char **GetPathComponents(const char *path,
cristybb503372010-05-27 20:51:26 +00001317% size_t *number_componenets)
cristy3ed852e2009-09-05 21:47:34 +00001318%
1319% A description of each parameter follows:
1320%
1321% o path: Specifies the string to segment into a list.
1322%
1323% o number_components: return the number of components in the list
1324%
1325*/
cristyd1dd6e42011-09-04 01:46:08 +00001326MagickPrivate char **GetPathComponents(const char *path,
cristybb503372010-05-27 20:51:26 +00001327 size_t *number_components)
cristy3ed852e2009-09-05 21:47:34 +00001328{
1329 char
1330 **components;
1331
1332 register const char
1333 *p,
1334 *q;
1335
cristybb503372010-05-27 20:51:26 +00001336 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001337 i;
1338
1339 if (path == (char *) NULL)
1340 return((char **) NULL);
1341 *number_components=1;
1342 for (p=path; *p != '\0'; p++)
1343 if (IsBasenameSeparator(*p))
1344 (*number_components)++;
1345 components=(char **) AcquireQuantumMemory((size_t) *number_components+1UL,
1346 sizeof(*components));
1347 if (components == (char **) NULL)
1348 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1349 p=path;
cristybb503372010-05-27 20:51:26 +00001350 for (i=0; i < (ssize_t) *number_components; i++)
cristy3ed852e2009-09-05 21:47:34 +00001351 {
1352 for (q=p; *q != '\0'; q++)
1353 if (IsBasenameSeparator(*q))
1354 break;
1355 components[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
cristyc92c1e12011-03-25 15:47:59 +00001356 sizeof(**components));
cristy3ed852e2009-09-05 21:47:34 +00001357 if (components[i] == (char *) NULL)
1358 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1359 (void) CopyMagickString(components[i],p,(size_t) (q-p+1));
1360 p=q+1;
1361 }
1362 components[i]=(char *) NULL;
1363 return(components);
1364}
1365
1366/*
1367%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1368% %
1369% %
1370% %
1371% I s P a t h A c c e s s i b l e %
1372% %
1373% %
1374% %
1375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1376%
1377% IsPathAccessible() returns MagickTrue if the file as defined by the path is
1378% accessible.
1379%
1380% The format of the IsPathAccessible method is:
1381%
1382% MagickBooleanType IsPathAccessible(const char *filename)
1383%
1384% A description of each parameter follows.
1385%
1386% o path: Specifies a path to a file.
1387%
1388*/
1389MagickExport MagickBooleanType IsPathAccessible(const char *path)
1390{
1391 MagickBooleanType
1392 status;
1393
1394 struct stat
1395 attributes;
1396
1397 if ((path == (const char *) NULL) || (*path == '\0'))
1398 return(MagickFalse);
1399 status=GetPathAttributes(path,&attributes);
1400 if (status == MagickFalse)
1401 return(status);
1402 if (S_ISREG(attributes.st_mode) == 0)
1403 return(MagickFalse);
cristy18c6c272011-09-23 14:40:37 +00001404 if (access_utf8(path,F_OK) != 0)
cristy3ed852e2009-09-05 21:47:34 +00001405 return(MagickFalse);
1406 return(MagickTrue);
1407}
1408
1409/*
1410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1411% %
1412% %
1413% %
1414+ I s P a t h D i r e c t o r y %
1415% %
1416% %
1417% %
1418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1419%
1420% IsPathDirectory() returns -1 if the directory does not exist, 1 is returned
1421% if the path represents a directory otherwise 0.
1422%
1423% The format of the IsPathDirectory method is:
1424%
1425% int IsPathDirectory(const char *path)
1426%
1427% A description of each parameter follows.
1428%
1429% o path: The directory path.
1430%
1431*/
1432static int IsPathDirectory(const char *path)
1433{
1434 MagickBooleanType
1435 status;
1436
1437 struct stat
1438 attributes;
1439
1440 if ((path == (const char *) NULL) || (*path == '\0'))
1441 return(MagickFalse);
1442 status=GetPathAttributes(path,&attributes);
1443 if (status == MagickFalse)
1444 return(-1);
1445 if (S_ISDIR(attributes.st_mode) == 0)
1446 return(0);
1447 return(1);
1448}
1449
1450/*
1451%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1452% %
1453% %
1454% %
1455% I s M a g i c k T r u e %
1456% %
1457% %
1458% %
1459%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1460%
1461% IsMagickTrue() returns MagickTrue if the value is "true", "on", "yes" or
1462% "1".
1463%
1464% The format of the IsMagickTrue method is:
1465%
1466% MagickBooleanType IsMagickTrue(const char *value)
1467%
1468% A description of each parameter follows:
1469%
1470% o option: either MagickTrue or MagickFalse depending on the value
1471% parameter.
1472%
1473% o value: Specifies a pointer to a character array.
1474%
1475*/
1476MagickExport MagickBooleanType IsMagickTrue(const char *value)
1477{
1478 if (value == (const char *) NULL)
1479 return(MagickFalse);
1480 if (LocaleCompare(value,"true") == 0)
1481 return(MagickTrue);
1482 if (LocaleCompare(value,"on") == 0)
1483 return(MagickTrue);
1484 if (LocaleCompare(value,"yes") == 0)
1485 return(MagickTrue);
1486 if (LocaleCompare(value,"1") == 0)
1487 return(MagickTrue);
1488 return(MagickFalse);
1489}
1490
1491/*
1492%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1493% %
1494% %
1495% %
1496% L i s t F i l e s %
1497% %
1498% %
1499% %
1500%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1501%
1502% ListFiles() reads the directory specified and returns a list of filenames
1503% contained in the directory sorted in ascending alphabetic order.
1504%
1505% The format of the ListFiles function is:
1506%
1507% char **ListFiles(const char *directory,const char *pattern,
cristybb503372010-05-27 20:51:26 +00001508% ssize_t *number_entries)
cristy3ed852e2009-09-05 21:47:34 +00001509%
1510% A description of each parameter follows:
1511%
1512% o filelist: Method ListFiles returns a list of filenames contained
1513% in the directory. If the directory specified cannot be read or it is
1514% a file a NULL list is returned.
1515%
1516% o directory: Specifies a pointer to a text string containing a directory
1517% name.
1518%
1519% o pattern: Specifies a pointer to a text string containing a pattern.
1520%
1521% o number_entries: This integer returns the number of filenames in the
1522% list.
1523%
1524*/
1525
1526#if defined(__cplusplus) || defined(c_plusplus)
1527extern "C" {
1528#endif
1529
1530static int FileCompare(const void *x,const void *y)
1531{
1532 register const char
1533 **p,
1534 **q;
1535
1536 p=(const char **) x;
1537 q=(const char **) y;
1538 return(LocaleCompare(*p,*q));
1539}
1540
1541#if defined(__cplusplus) || defined(c_plusplus)
1542}
1543#endif
1544
1545static inline int MagickReadDirectory(DIR *directory,struct dirent *entry,
1546 struct dirent **result)
1547{
1548#if defined(MAGICKCORE_HAVE_READDIR_R)
1549 return(readdir_r(directory,entry,result));
1550#else
1551 (void) entry;
1552 errno=0;
1553 *result=readdir(directory);
1554 return(errno);
1555#endif
1556}
1557
cristyd1dd6e42011-09-04 01:46:08 +00001558MagickPrivate char **ListFiles(const char *directory,const char *pattern,
cristybb503372010-05-27 20:51:26 +00001559 size_t *number_entries)
cristy3ed852e2009-09-05 21:47:34 +00001560{
1561 char
1562 **filelist;
1563
1564 DIR
1565 *current_directory;
1566
1567 struct dirent
1568 *buffer,
1569 *entry;
1570
cristybb503372010-05-27 20:51:26 +00001571 size_t
cristy3ed852e2009-09-05 21:47:34 +00001572 max_entries;
1573
1574 /*
1575 Open directory.
1576 */
1577 assert(directory != (const char *) NULL);
1578 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",directory);
1579 assert(pattern != (const char *) NULL);
cristybb503372010-05-27 20:51:26 +00001580 assert(number_entries != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001581 *number_entries=0;
1582 current_directory=opendir(directory);
1583 if (current_directory == (DIR *) NULL)
1584 return((char **) NULL);
1585 /*
1586 Allocate filelist.
1587 */
1588 max_entries=2048;
1589 filelist=(char **) AcquireQuantumMemory((size_t) max_entries,
1590 sizeof(*filelist));
1591 if (filelist == (char **) NULL)
1592 {
1593 (void) closedir(current_directory);
1594 return((char **) NULL);
1595 }
1596 /*
1597 Save the current and change to the new directory.
1598 */
cristy73bd4a52010-10-05 11:24:23 +00001599 buffer=(struct dirent *) AcquireMagickMemory(sizeof(*buffer)+
cristy0be53ea2010-06-23 19:12:05 +00001600 FILENAME_MAX+1);
cristy3ed852e2009-09-05 21:47:34 +00001601 if (buffer == (struct dirent *) NULL)
1602 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1603 while ((MagickReadDirectory(current_directory,buffer,&entry) == 0) &&
1604 (entry != (struct dirent *) NULL))
1605 {
1606 if (*entry->d_name == '.')
1607 continue;
1608 if ((IsPathDirectory(entry->d_name) > 0) ||
cristy0157aea2010-04-24 21:12:18 +00001609#if defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +00001610 (GlobExpression(entry->d_name,pattern,MagickTrue) != MagickFalse))
1611#else
1612 (GlobExpression(entry->d_name,pattern,MagickFalse) != MagickFalse))
1613#endif
1614 {
1615 if (*number_entries >= max_entries)
1616 {
1617 /*
1618 Extend the file list.
1619 */
1620 max_entries<<=1;
1621 filelist=(char **) ResizeQuantumMemory(filelist,(size_t)
1622 max_entries,sizeof(*filelist));
1623 if (filelist == (char **) NULL)
1624 break;
1625 }
1626#if defined(vms)
1627 {
1628 register char
1629 *p;
1630
1631 p=strchr(entry->d_name,';');
1632 if (p)
1633 *p='\0';
1634 if (*number_entries > 0)
1635 if (LocaleCompare(entry->d_name,filelist[*number_entries-1]) == 0)
1636 continue;
1637 }
1638#endif
1639 filelist[*number_entries]=(char *) AcquireString(entry->d_name);
cristy3ed852e2009-09-05 21:47:34 +00001640 (*number_entries)++;
1641 }
1642 }
1643 buffer=(struct dirent *) RelinquishMagickMemory(buffer);
1644 (void) closedir(current_directory);
1645 if (filelist == (char **) NULL)
1646 return((char **) NULL);
1647 /*
1648 Sort filelist in ascending order.
1649 */
1650 qsort((void *) filelist,(size_t) *number_entries,sizeof(*filelist),
1651 FileCompare);
1652 return(filelist);
1653}
1654
1655/*
1656%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1657% %
1658% %
1659% %
cristya21afde2010-07-02 00:45:40 +00001660% M a g i c k D e l a y %
1661% %
1662% %
1663% %
1664%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1665%
1666% MagickDelay() suspends program execution for the number of milliseconds
1667% specified.
1668%
1669% The format of the Delay method is:
1670%
1671% void MagickDelay(const MagickSizeType milliseconds)
1672%
1673% A description of each parameter follows:
1674%
1675% o milliseconds: Specifies the number of milliseconds to delay before
1676% returning.
1677%
1678*/
cristyd1dd6e42011-09-04 01:46:08 +00001679MagickPrivate void MagickDelay(const MagickSizeType milliseconds)
cristya21afde2010-07-02 00:45:40 +00001680{
1681 if (milliseconds == 0)
1682 return;
1683#if defined(MAGICKCORE_HAVE_NANOSLEEP)
1684 {
1685 struct timespec
1686 timer;
1687
1688 timer.tv_sec=(time_t) (milliseconds/1000);
1689 timer.tv_nsec=(milliseconds % 1000)*1000*1000;
1690 (void) nanosleep(&timer,(struct timespec *) NULL);
1691 }
1692#elif defined(MAGICKCORE_HAVE_USLEEP)
1693 usleep(1000*milliseconds);
1694#elif defined(MAGICKCORE_HAVE_SELECT)
1695 {
1696 struct timeval
1697 timer;
1698
1699 timer.tv_sec=(long) milliseconds/1000;
1700 timer.tv_usec=(long) (milliseconds % 1000)*1000;
1701 (void) select(0,(XFD_SET *) NULL,(XFD_SET *) NULL,(XFD_SET *) NULL,&timer);
1702 }
1703#elif defined(MAGICKCORE_HAVE_POLL)
1704 (void) poll((struct pollfd *) NULL,0,(int) milliseconds);
1705#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
1706 Sleep((long) milliseconds);
1707#elif defined(vms)
1708 {
1709 float
1710 timer;
1711
1712 timer=milliseconds/1000.0;
1713 lib$wait(&timer);
1714 }
1715#elif defined(__BEOS__)
1716 snooze(1000*milliseconds);
1717#else
1718# error "Time delay method not defined."
1719#endif
1720}
1721
1722/*
1723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1724% %
1725% %
1726% %
cristy3ed852e2009-09-05 21:47:34 +00001727% M u l t i l i n e C e n s u s %
1728% %
1729% %
1730% %
1731%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1732%
1733% MultilineCensus() returns the number of lines within a label. A line is
1734% represented by a \n character.
1735%
1736% The format of the MultilineCenus method is:
1737%
cristybb503372010-05-27 20:51:26 +00001738% size_t MultilineCensus(const char *label)
cristy3ed852e2009-09-05 21:47:34 +00001739%
1740% A description of each parameter follows.
1741%
1742% o label: This character string is the label.
1743%
cristy3ed852e2009-09-05 21:47:34 +00001744*/
cristybb503372010-05-27 20:51:26 +00001745MagickExport size_t MultilineCensus(const char *label)
cristy3ed852e2009-09-05 21:47:34 +00001746{
cristybb503372010-05-27 20:51:26 +00001747 size_t
cristy3ed852e2009-09-05 21:47:34 +00001748 number_lines;
1749
1750 /*
1751 Determine the number of lines within this label.
1752 */
1753 if (label == (char *) NULL)
1754 return(0);
1755 for (number_lines=1; *label != '\0'; label++)
1756 if (*label == '\n')
1757 number_lines++;
1758 return(number_lines);
1759}
1760
1761/*
1762%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1763% %
1764% %
1765% %
cristy3ed852e2009-09-05 21:47:34 +00001766% S y s t e m C o m m a n d %
1767% %
1768% %
1769% %
1770%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1771%
1772% SystemCommand() executes the specified command and waits until it
1773% terminates. The returned value is the exit status of the command.
1774%
1775% The format of the SystemCommand method is:
1776%
cristy6de4bc22010-01-12 17:10:35 +00001777% int SystemCommand(const MagickBooleanType asynchronous,
1778% const MagickBooleanType verbose,const char *command,
cristyb32b90a2009-09-07 21:45:48 +00001779% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001780%
1781% A description of each parameter follows:
1782%
cristy6de4bc22010-01-12 17:10:35 +00001783% o asynchronous: a value other than 0 executes the parent program
1784% concurrently with the new child process.
1785%
cristyb32b90a2009-09-07 21:45:48 +00001786% o verbose: a value other than 0 prints the executed command before it is
cristy3ed852e2009-09-05 21:47:34 +00001787% invoked.
1788%
cristyb32b90a2009-09-07 21:45:48 +00001789% o command: this string is the command to execute.
1790%
1791% o exception: return any errors here.
cristy3ed852e2009-09-05 21:47:34 +00001792%
1793*/
cristy6de4bc22010-01-12 17:10:35 +00001794MagickExport int SystemCommand(const MagickBooleanType asynchronous,
1795 const MagickBooleanType verbose,const char *command,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001796{
cristyb32b90a2009-09-07 21:45:48 +00001797 char
cristy6de4bc22010-01-12 17:10:35 +00001798 **arguments,
1799 *shell_command;
cristyb32b90a2009-09-07 21:45:48 +00001800
cristy3ed852e2009-09-05 21:47:34 +00001801 int
cristyb32b90a2009-09-07 21:45:48 +00001802 number_arguments,
cristy3ed852e2009-09-05 21:47:34 +00001803 status;
1804
cristyb32b90a2009-09-07 21:45:48 +00001805 PolicyDomain
1806 domain;
1807
1808 PolicyRights
1809 rights;
1810
cristybb503372010-05-27 20:51:26 +00001811 register ssize_t
cristyb32b90a2009-09-07 21:45:48 +00001812 i;
1813
1814 status=(-1);
1815 arguments=StringToArgv(command,&number_arguments);
1816 if (arguments == (char **) NULL)
1817 return(status);
cristyb32b90a2009-09-07 21:45:48 +00001818 rights=ExecutePolicyRights;
cristy6de4bc22010-01-12 17:10:35 +00001819 domain=DelegatePolicyDomain;
cristyb32b90a2009-09-07 21:45:48 +00001820 if (IsRightsAuthorized(domain,rights,arguments[1]) == MagickFalse)
1821 {
cristya9197f62010-01-12 02:23:34 +00001822 errno=EPERM;
cristyb32b90a2009-09-07 21:45:48 +00001823 (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
1824 "NotAuthorized","`%s'",arguments[1]);
cristycee97112010-05-28 00:44:52 +00001825 for (i=0; i < (ssize_t) number_arguments; i++)
cristyb32b90a2009-09-07 21:45:48 +00001826 arguments[i]=DestroyString(arguments[i]);
1827 arguments=(char **) RelinquishMagickMemory(arguments);
1828 return(-1);
1829 }
cristy3ed852e2009-09-05 21:47:34 +00001830 if (verbose != MagickFalse)
1831 {
cristyb51dff52011-05-19 16:55:47 +00001832 (void) FormatLocaleFile(stderr,"%s\n",command);
cristy3ed852e2009-09-05 21:47:34 +00001833 (void) fflush(stderr);
1834 }
cristy6de4bc22010-01-12 17:10:35 +00001835 shell_command=(char *) command;
1836 if (asynchronous != MagickFalse)
1837 {
1838 shell_command=AcquireString(command);
1839 (void) ConcatenateMagickString(shell_command,"&",MaxTextExtent);
1840 }
cristy3ed852e2009-09-05 21:47:34 +00001841#if defined(MAGICKCORE_POSIX_SUPPORT)
cristya9197f62010-01-12 02:23:34 +00001842#if !defined(MAGICKCORE_HAVE_EXECVP)
cristy6de4bc22010-01-12 17:10:35 +00001843 status=system(shell_command);
cristy3ed852e2009-09-05 21:47:34 +00001844#else
cristy6de4bc22010-01-12 17:10:35 +00001845 if ((asynchronous != MagickFalse) || (strspn(shell_command,"&;<>|") == 0))
1846 status=system(shell_command);
cristy3ed852e2009-09-05 21:47:34 +00001847 else
1848 {
cristyb32b90a2009-09-07 21:45:48 +00001849 pid_t
1850 child_pid;
cristy3ed852e2009-09-05 21:47:34 +00001851
cristyb32b90a2009-09-07 21:45:48 +00001852 /*
1853 Call application directly rather than from a shell.
1854 */
1855 child_pid=fork();
1856 if (child_pid == (pid_t) -1)
cristy3ed852e2009-09-05 21:47:34 +00001857 status=system(command);
1858 else
cristyb32b90a2009-09-07 21:45:48 +00001859 if (child_pid == 0)
1860 {
1861 status=execvp(arguments[1],arguments+1);
1862 _exit(1);
1863 }
1864 else
1865 {
1866 int
1867 child_status;
cristy3ed852e2009-09-05 21:47:34 +00001868
cristyb32b90a2009-09-07 21:45:48 +00001869 pid_t
1870 pid;
cristy3ed852e2009-09-05 21:47:34 +00001871
cristyb32b90a2009-09-07 21:45:48 +00001872 child_status=0;
1873 pid=waitpid(child_pid,&child_status,0);
1874 if (pid == -1)
1875 status=(-1);
cristy3ed852e2009-09-05 21:47:34 +00001876 else
1877 {
cristyb32b90a2009-09-07 21:45:48 +00001878 if (WIFEXITED(child_status) != 0)
1879 status=WEXITSTATUS(child_status);
cristy3ed852e2009-09-05 21:47:34 +00001880 else
cristyb32b90a2009-09-07 21:45:48 +00001881 if (WIFSIGNALED(child_status))
1882 status=(-1);
cristy3ed852e2009-09-05 21:47:34 +00001883 }
cristyb32b90a2009-09-07 21:45:48 +00001884 }
cristy3ed852e2009-09-05 21:47:34 +00001885 }
1886#endif
cristy0157aea2010-04-24 21:12:18 +00001887#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
cristyceaf0142010-01-12 02:39:34 +00001888 {
1889 int
1890 mode;
1891
1892 mode=_P_WAIT;
cristy6de4bc22010-01-12 17:10:35 +00001893 if (asynchronous != MagickFalse)
1894 mode=_P_NOWAIT;
cristye7e40552010-04-24 21:34:22 +00001895 status=spawnvp(mode,arguments[1],(const char **) (arguments+1));
cristyceaf0142010-01-12 02:39:34 +00001896 }
cristy3ed852e2009-09-05 21:47:34 +00001897#elif defined(macintosh)
cristy6de4bc22010-01-12 17:10:35 +00001898 status=MACSystemCommand(shell_command);
cristy3ed852e2009-09-05 21:47:34 +00001899#elif defined(vms)
cristy6de4bc22010-01-12 17:10:35 +00001900 status=system(shell_command);
cristy3ed852e2009-09-05 21:47:34 +00001901#else
1902# error No suitable system() method.
1903#endif
1904 if (status < 0)
cristy6de4bc22010-01-12 17:10:35 +00001905 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
1906 "`%s' (%d)",command,status);
1907 if (shell_command != command)
1908 shell_command=DestroyString(shell_command);
cristycee97112010-05-28 00:44:52 +00001909 for (i=0; i < (ssize_t) number_arguments; i++)
cristyb32b90a2009-09-07 21:45:48 +00001910 arguments[i]=DestroyString(arguments[i]);
1911 arguments=(char **) RelinquishMagickMemory(arguments);
cristy3ed852e2009-09-05 21:47:34 +00001912 return(status);
1913}