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