blob: 00d7d6d50aab64bcaf71d9fe642ae475d2a08ea1 [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% %
cristy1454be72011-12-19 01:52:48 +000020% Copyright 1999-2012 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"
cristy2c5fc272012-02-22 01:27:46 +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) ||
cristyc0732c42012-03-20 19:28:35 +0000771 (LocaleCompare(magick,"PANGO") == 0) ||
cristy3ed852e2009-09-05 21:47:34 +0000772 (LocaleCompare(magick,"VID") == 0))
773 continue;
cristy47b20292012-04-26 18:18:48 +0000774 if ((IsGlob(option) == MagickFalse) && (*option != '@'))
cristy3ed852e2009-09-05 21:47:34 +0000775 continue;
cristy47b20292012-04-26 18:18:48 +0000776 if (*option != '@')
cristy3ed852e2009-09-05 21:47:34 +0000777 {
778 /*
779 Generate file list from wildcard filename (e.g. *.jpg).
780 */
781 GetPathComponent(option,HeadPath,path);
782 GetPathComponent(option,SubimagePath,subimage);
783 ExpandFilename(path);
cristyf5ee5be2009-11-06 02:22:56 +0000784 if (*home_directory == '\0')
cristy00976d82011-02-20 20:31:28 +0000785 directory=getcwd(home_directory,MaxTextExtent-1);
786 (void) directory;
cristy47b20292012-04-26 18:18:48 +0000787 filelist=ListFiles(*path == '\0' ? home_directory : path,option,
cristy3ed852e2009-09-05 21:47:34 +0000788 &number_files);
789 }
790 else
791 {
792 char
793 *files;
794
795 ExceptionInfo
796 *exception;
797
798 int
cristyf9218a72010-07-03 17:29:40 +0000799 length;
cristy3ed852e2009-09-05 21:47:34 +0000800
801 /*
802 Generate file list from file list (e.g. @filelist.txt).
803 */
804 exception=AcquireExceptionInfo();
cristy47b20292012-04-26 18:18:48 +0000805 files=FileToString(option+1,~0,exception);
cristy3ed852e2009-09-05 21:47:34 +0000806 exception=DestroyExceptionInfo(exception);
807 if (files == (char *) NULL)
808 continue;
cristyf9218a72010-07-03 17:29:40 +0000809 filelist=StringToArgv(files,&length);
810 if (filelist == (char **) NULL)
811 continue;
cristy3ed852e2009-09-05 21:47:34 +0000812 files=DestroyString(files);
cristyf9218a72010-07-03 17:29:40 +0000813 filelist[0]=DestroyString(filelist[0]);
814 for (j=0; j < (ssize_t) (length-1); j++)
815 filelist[j]=filelist[j+1];
816 number_files=(size_t) length-1;
cristy3ed852e2009-09-05 21:47:34 +0000817 }
818 if (filelist == (char **) NULL)
819 continue;
cristybb503372010-05-27 20:51:26 +0000820 for (j=0; j < (ssize_t) number_files; j++)
cristy3ed852e2009-09-05 21:47:34 +0000821 if (IsPathDirectory(filelist[j]) <= 0)
822 break;
cristybb503372010-05-27 20:51:26 +0000823 if (j == (ssize_t) number_files)
cristy3ed852e2009-09-05 21:47:34 +0000824 {
cristybb503372010-05-27 20:51:26 +0000825 for (j=0; j < (ssize_t) number_files; j++)
cristy3ed852e2009-09-05 21:47:34 +0000826 filelist[j]=DestroyString(filelist[j]);
827 filelist=(char **) RelinquishMagickMemory(filelist);
828 continue;
829 }
830 /*
831 Transfer file list to argument vector.
832 */
833 vector=(char **) ResizeQuantumMemory(vector,(size_t) *number_arguments+
834 count+number_files+1,sizeof(*vector));
835 if (vector == (char **) NULL)
836 return(MagickFalse);
cristybb503372010-05-27 20:51:26 +0000837 for (j=0; j < (ssize_t) number_files; j++)
cristy3ed852e2009-09-05 21:47:34 +0000838 {
cristy0e526222010-05-06 14:07:32 +0000839 option=filelist[j];
cristy042ee782011-04-22 18:48:30 +0000840 parameters=ParseCommandOption(MagickCommandOptions,MagickFalse,option);
cristy0e526222010-05-06 14:07:32 +0000841 if (parameters > 0)
842 {
cristybb503372010-05-27 20:51:26 +0000843 ssize_t
cristy0e526222010-05-06 14:07:32 +0000844 k;
845
846 /*
847 Do not expand command option parameters.
848 */
849 vector[count++]=ConstantString(option);
850 for (k=0; k < parameters; k++)
851 {
852 j++;
cristybb503372010-05-27 20:51:26 +0000853 if (j == (ssize_t) number_files)
cristy0e526222010-05-06 14:07:32 +0000854 break;
855 option=filelist[j];
856 vector[count++]=ConstantString(option);
857 }
858 continue;
859 }
cristy3ed852e2009-09-05 21:47:34 +0000860 (void) CopyMagickString(filename,path,MaxTextExtent);
861 if (*path != '\0')
862 (void) ConcatenateMagickString(filename,DirectorySeparator,
863 MaxTextExtent);
864 (void) ConcatenateMagickString(filename,filelist[j],MaxTextExtent);
865 filelist[j]=DestroyString(filelist[j]);
cristycfef62c2010-05-05 01:21:43 +0000866 if (strlen(filename) >= (MaxTextExtent-1))
cristy3ed852e2009-09-05 21:47:34 +0000867 ThrowFatalException(OptionFatalError,"FilenameTruncated");
cristy47dc34d2010-04-22 16:12:43 +0000868 if (IsPathDirectory(filename) <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000869 {
870 char
871 path[MaxTextExtent];
872
873 *path='\0';
874 if (*magick != '\0')
875 {
876 (void) ConcatenateMagickString(path,magick,MaxTextExtent);
877 (void) ConcatenateMagickString(path,":",MaxTextExtent);
878 }
879 (void) ConcatenateMagickString(path,filename,MaxTextExtent);
880 if (*subimage != '\0')
881 {
882 (void) ConcatenateMagickString(path,"[",MaxTextExtent);
883 (void) ConcatenateMagickString(path,subimage,MaxTextExtent);
884 (void) ConcatenateMagickString(path,"]",MaxTextExtent);
885 }
cristy37e0b382011-06-07 13:31:21 +0000886 if (strlen(path) >= (MaxTextExtent-1))
cristy3ed852e2009-09-05 21:47:34 +0000887 ThrowFatalException(OptionFatalError,"FilenameTruncated");
888 if (destroy != MagickFalse)
889 {
890 count--;
891 vector[count]=DestroyString(vector[count]);
892 destroy=MagickFalse;
893 }
894 vector[count++]=ConstantString(path);
895 }
896 }
897 filelist=(char **) RelinquishMagickMemory(filelist);
898 }
899 vector[count]=(char *) NULL;
900 if (IsEventLogging() != MagickFalse)
901 {
902 char
903 *command_line;
904
905 command_line=AcquireString(vector[0]);
906 for (i=1; i < count; i++)
907 {
908 (void) ConcatenateString(&command_line," {");
909 (void) ConcatenateString(&command_line,vector[i]);
910 (void) ConcatenateString(&command_line,"}");
911 }
912 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
913 "Command line: %s",command_line);
914 command_line=DestroyString(command_line);
915 }
916 *number_arguments=(int) count;
917 *arguments=vector;
918 return(MagickTrue);
919}
920
921/*
922%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
923% %
924% %
925% %
926% G e t E x e c u t i o n P a t h %
927% %
928% %
929% %
930%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
931%
932% GetExecutionPath() returns the pathname of the executable that started
933% the process. On success MagickTrue is returned, otherwise MagickFalse.
934%
935% The format of the GetExecutionPath method is:
936%
937% MagickBooleanType GetExecutionPath(char *path,const size_t extent)
938%
939% A description of each parameter follows:
940%
941% o path: the pathname of the executable that started the process.
942%
943% o extent: the maximum extent of the path.
944%
945*/
cristyd1dd6e42011-09-04 01:46:08 +0000946MagickPrivate MagickBooleanType GetExecutionPath(char *path,const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +0000947{
cristyfbe485a2011-02-22 13:54:48 +0000948 char
949 *directory;
950
cristy3ed852e2009-09-05 21:47:34 +0000951 *path='\0';
cristyfbe485a2011-02-22 13:54:48 +0000952 directory=getcwd(path,(unsigned long) extent);
953 (void) directory;
cristyfa09d142009-10-15 01:02:25 +0000954#if defined(MAGICKCORE_HAVE_GETPID) && defined(MAGICKCORE_HAVE_READLINK) && defined(PATH_MAX)
cristy3ed852e2009-09-05 21:47:34 +0000955 {
956 char
957 link_path[MaxTextExtent],
cristyfa09d142009-10-15 01:02:25 +0000958 execution_path[PATH_MAX+1];
cristy3ed852e2009-09-05 21:47:34 +0000959
960 ssize_t
961 count;
962
cristyb51dff52011-05-19 16:55:47 +0000963 (void) FormatLocaleString(link_path,MaxTextExtent,"/proc/%.20g/exe",
cristye8c25f92010-06-03 00:53:06 +0000964 (double) getpid());
cristyfa09d142009-10-15 01:02:25 +0000965 count=readlink(link_path,execution_path,PATH_MAX);
cristy3ed852e2009-09-05 21:47:34 +0000966 if (count == -1)
967 {
cristyb51dff52011-05-19 16:55:47 +0000968 (void) FormatLocaleString(link_path,MaxTextExtent,"/proc/%.20g/file",
cristye8c25f92010-06-03 00:53:06 +0000969 (double) getpid());
cristyfa09d142009-10-15 01:02:25 +0000970 count=readlink(link_path,execution_path,PATH_MAX);
cristy3ed852e2009-09-05 21:47:34 +0000971 }
972 if ((count > 0) && (count <= (ssize_t) PATH_MAX))
973 {
cristyfa09d142009-10-15 01:02:25 +0000974 execution_path[count]='\0';
975 (void) CopyMagickString(path,execution_path,extent);
cristy3ed852e2009-09-05 21:47:34 +0000976 }
977 }
978#endif
979#if defined(MAGICKCORE_HAVE__NSGETEXECUTABLEPATH)
980 {
981 char
982 executable_path[PATH_MAX << 1],
cristyfa09d142009-10-15 01:02:25 +0000983 execution_path[PATH_MAX+1];
cristy3ed852e2009-09-05 21:47:34 +0000984
985 uint32_t
986 length;
987
988 length=sizeof(executable_path);
989 if ((_NSGetExecutablePath(executable_path,&length) == 0) &&
cristyfa09d142009-10-15 01:02:25 +0000990 (realpath(executable_path,execution_path) != (char *) NULL))
991 (void) CopyMagickString(path,execution_path,extent);
cristy3ed852e2009-09-05 21:47:34 +0000992 }
993#endif
994#if defined(MAGICKCORE_HAVE_GETEXECNAME)
995 {
996 const char
997 *execution_path;
998
999 execution_path=(const char *) getexecname();
1000 if (execution_path != (const char *) NULL)
1001 {
1002 if (*execution_path != *DirectorySeparator)
1003 (void) ConcatenateMagickString(path,DirectorySeparator,extent);
1004 (void) ConcatenateMagickString(path,execution_path,extent);
1005 }
1006 }
1007#endif
cristy0157aea2010-04-24 21:12:18 +00001008#if defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +00001009 NTGetExecutionPath(path,extent);
1010#endif
cristyfa09d142009-10-15 01:02:25 +00001011#if defined(__GNU__)
1012 {
1013 char
1014 *program_name,
1015 *execution_path;
1016
cristybb503372010-05-27 20:51:26 +00001017 ssize_t
cristyfa09d142009-10-15 01:02:25 +00001018 count;
1019
1020 count=0;
1021 execution_path=(char *) NULL;
1022 program_name=program_invocation_name;
1023 if (*program_invocation_name != '/')
1024 {
1025 size_t
1026 extent;
1027
cristyb29bea52011-05-26 17:54:31 +00001028 extent=strlen(directory)+strlen(program_name)+2;
cristyfa09d142009-10-15 01:02:25 +00001029 program_name=AcquireQuantumMemory(extent,sizeof(*program_name));
1030 if (program_name == (char *) NULL)
1031 program_name=program_invocation_name;
1032 else
cristyb29bea52011-05-26 17:54:31 +00001033 count=FormatLocaleString(program_name,extent,"%s/%s",directory,
cristyfa09d142009-10-15 01:02:25 +00001034 program_invocation_name);
1035 }
1036 if (count != -1)
1037 {
1038 execution_path=realpath(program_name,NULL);
1039 if (execution_path != (char *) NULL)
1040 (void) CopyMagickString(path,execution_path,extent);
1041 }
1042 if (program_name != program_invocation_name)
1043 program_name=(char *) RelinquishMagickMemory(program_name);
1044 execution_path=(char *) RelinquishMagickMemory(execution_path);
1045 }
1046#endif
cristy3ed852e2009-09-05 21:47:34 +00001047 return(IsPathAccessible(path));
1048}
1049
1050/*
1051%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1052% %
1053% %
1054% %
cristy688f07b2009-09-27 15:19:13 +00001055% G e t M a g i c k P a g e S i z e %
1056% %
1057% %
1058% %
1059%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1060%
1061% GetMagickPageSize() returns the memory page size.
1062%
1063% The format of the GetMagickPageSize method is:
1064%
cristybb503372010-05-27 20:51:26 +00001065% ssize_t GetMagickPageSize()
cristy688f07b2009-09-27 15:19:13 +00001066%
1067*/
cristyd1dd6e42011-09-04 01:46:08 +00001068MagickPrivate ssize_t GetMagickPageSize(void)
cristy688f07b2009-09-27 15:19:13 +00001069{
cristybb503372010-05-27 20:51:26 +00001070 static ssize_t
cristy688f07b2009-09-27 15:19:13 +00001071 page_size = -1;
1072
1073 if (page_size > 0)
1074 return(page_size);
1075#if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
cristyecd0ab52010-05-30 14:59:20 +00001076 page_size=(ssize_t) sysconf(_SC_PAGE_SIZE);
cristy09449f72010-01-23 03:08:36 +00001077#else
cristy688f07b2009-09-27 15:19:13 +00001078#if defined(MAGICKCORE_HAVE_GETPAGESIZE)
cristyecd0ab52010-05-30 14:59:20 +00001079 page_size=(ssize_t) getpagesize();
cristy09449f72010-01-23 03:08:36 +00001080#endif
cristy688f07b2009-09-27 15:19:13 +00001081#endif
1082 if (page_size <= 0)
1083 page_size=16384;
1084 return(page_size);
1085}
1086
1087/*
1088%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1089% %
1090% %
1091% %
cristy3ed852e2009-09-05 21:47:34 +00001092% G e t P a t h A t t r i b u t e s %
1093% %
1094% %
1095% %
1096%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1097%
1098% GetPathAttributes() returns attributes (e.g. size of file) about a path.
1099%
1100% The path of the GetPathAttributes method is:
1101%
1102% MagickBooleanType GetPathAttributes(const char *path,void *attributes)
1103%
1104% A description of each parameter follows.
1105%
1106% o path: the file path.
1107%
1108% o attributes: the path attributes are returned here.
1109%
1110*/
cristy3ed852e2009-09-05 21:47:34 +00001111MagickExport MagickBooleanType GetPathAttributes(const char *path,
1112 void *attributes)
1113{
1114 MagickBooleanType
1115 status;
1116
1117 if (path == (const char *) NULL)
1118 {
1119 errno=EINVAL;
1120 return(MagickFalse);
1121 }
cristy18c6c272011-09-23 14:40:37 +00001122 status=stat_utf8(path,(struct stat *) attributes) == 0 ? MagickTrue :
1123 MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00001124 return(status);
1125}
1126
1127/*
1128%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1129% %
1130% %
1131% %
1132% G e t P a t h C o m p o n e n t %
1133% %
1134% %
1135% %
1136%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1137%
1138% GetPathComponent() returns the parent directory name, filename, basename, or
1139% extension of a file path.
1140%
1141% The format of the GetPathComponent function is:
1142%
1143% GetPathComponent(const char *path,PathType type,char *component)
1144%
1145% A description of each parameter follows:
1146%
1147% o path: Specifies a pointer to a character array that contains the
1148% file path.
1149%
1150% o type: Specififies which file path component to return.
1151%
1152% o component: the selected file path component is returned here.
1153%
1154*/
1155MagickExport void GetPathComponent(const char *path,PathType type,
1156 char *component)
1157{
1158 char
1159 magick[MaxTextExtent],
1160 *q,
1161 subimage[MaxTextExtent];
1162
1163 register char
1164 *p;
1165
1166 assert(path != (const char *) NULL);
1167 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",path);
1168 assert(component != (char *) NULL);
1169 if (*path == '\0')
1170 {
1171 *component='\0';
1172 return;
1173 }
1174 (void) CopyMagickString(component,path,MaxTextExtent);
1175 *magick='\0';
cristy1224a992011-10-12 19:23:41 +00001176#if defined(__OS2__)
1177 if (path[1] != ":")
1178#endif
1179 for (p=component; *p != '\0'; p++)
1180 {
1181 if ((*p == '%') && (*(p+1) == '['))
1182 {
1183 /*
1184 Skip over %[...].
1185 */
1186 for (p++; (*p != ']') && (*p != '\0'); p++) ;
1187 if (*p == '\0')
1188 break;
1189 }
1190 if ((*p == ':') && (IsPathDirectory(path) < 0) &&
1191 (IsPathAccessible(path) == MagickFalse))
1192 {
1193 /*
1194 Look for image format specification (e.g. ps3:image).
1195 */
1196 (void) CopyMagickString(magick,component,(size_t) (p-component+1));
1197 if (IsMagickConflict(magick) != MagickFalse)
1198 *magick='\0';
1199 else
1200 for (q=component; *q != '\0'; q++)
1201 *q=(*++p);
1202 break;
1203 }
1204 }
cristy86057c42011-08-03 18:12:58 +00001205 *subimage='\0';
1206 p=component;
1207 if (*p != '\0')
1208 p=component+strlen(component)-1;
1209 if ((*p == ']') && (strchr(component,'[') != (char *) NULL) &&
1210 (IsPathAccessible(path) == MagickFalse))
1211 {
1212 /*
1213 Look for scene specification (e.g. img0001.pcd[4]).
1214 */
1215 for (q=p-1; q > component; q--)
1216 if (*q == '[')
1217 break;
1218 if (*q == '[')
1219 {
1220 (void) CopyMagickString(subimage,q+1,MaxTextExtent);
1221 subimage[p-q-1]='\0';
1222 if ((IsSceneGeometry(subimage,MagickFalse) == MagickFalse) &&
1223 (IsGeometry(subimage) == MagickFalse))
1224 *subimage='\0';
cristy1224a992011-10-12 19:23:41 +00001225 else
1226 *q='\0';
cristy86057c42011-08-03 18:12:58 +00001227 }
1228 }
cristy3ed852e2009-09-05 21:47:34 +00001229 p=component;
1230 if (*p != '\0')
1231 for (p=component+strlen(component)-1; p > component; p--)
1232 if (IsBasenameSeparator(*p) != MagickFalse)
1233 break;
1234 switch (type)
1235 {
1236 case MagickPath:
1237 {
1238 (void) CopyMagickString(component,magick,MaxTextExtent);
1239 break;
1240 }
1241 case RootPath:
1242 {
1243 for (p=component+(strlen(component)-1); p > component; p--)
1244 {
1245 if (IsBasenameSeparator(*p) != MagickFalse)
1246 break;
1247 if (*p == '.')
1248 break;
1249 }
1250 if (*p == '.')
1251 *p='\0';
1252 break;
1253 }
1254 case HeadPath:
1255 {
1256 *p='\0';
1257 break;
1258 }
1259 case TailPath:
1260 {
1261 if (IsBasenameSeparator(*p) != MagickFalse)
1262 (void) CopyMagickMemory((unsigned char *) component,
1263 (const unsigned char *) (p+1),strlen(p+1)+1);
1264 break;
1265 }
1266 case BasePath:
1267 {
1268 if (IsBasenameSeparator(*p) != MagickFalse)
1269 (void) CopyMagickString(component,p+1,MaxTextExtent);
1270 for (p=component+(strlen(component)-1); p > component; p--)
1271 if (*p == '.')
1272 {
1273 *p='\0';
1274 break;
1275 }
1276 break;
1277 }
1278 case ExtensionPath:
1279 {
1280 if (IsBasenameSeparator(*p) != MagickFalse)
1281 (void) CopyMagickString(component,p+1,MaxTextExtent);
1282 p=component;
1283 if (*p != '\0')
1284 for (p=component+strlen(component)-1; p > component; p--)
1285 if (*p == '.')
1286 break;
1287 *component='\0';
1288 if (*p == '.')
1289 (void) CopyMagickString(component,p+1,MaxTextExtent);
1290 break;
1291 }
1292 case SubimagePath:
1293 {
1294 (void) CopyMagickString(component,subimage,MaxTextExtent);
1295 break;
1296 }
1297 case CanonicalPath:
1298 case UndefinedPath:
1299 break;
1300 }
1301}
1302
1303/*
1304%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1305% %
1306% %
1307% %
1308% G e t P a t h C o m p o n e n t s %
1309% %
1310% %
1311% %
1312%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1313%
1314% GetPathComponents() returns a list of path components.
1315%
1316% The format of the GetPathComponents method is:
1317%
1318% char **GetPathComponents(const char *path,
cristybb503372010-05-27 20:51:26 +00001319% size_t *number_componenets)
cristy3ed852e2009-09-05 21:47:34 +00001320%
1321% A description of each parameter follows:
1322%
1323% o path: Specifies the string to segment into a list.
1324%
1325% o number_components: return the number of components in the list
1326%
1327*/
cristyd1dd6e42011-09-04 01:46:08 +00001328MagickPrivate char **GetPathComponents(const char *path,
cristybb503372010-05-27 20:51:26 +00001329 size_t *number_components)
cristy3ed852e2009-09-05 21:47:34 +00001330{
1331 char
1332 **components;
1333
1334 register const char
1335 *p,
1336 *q;
1337
cristybb503372010-05-27 20:51:26 +00001338 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001339 i;
1340
1341 if (path == (char *) NULL)
1342 return((char **) NULL);
1343 *number_components=1;
1344 for (p=path; *p != '\0'; p++)
1345 if (IsBasenameSeparator(*p))
1346 (*number_components)++;
1347 components=(char **) AcquireQuantumMemory((size_t) *number_components+1UL,
1348 sizeof(*components));
1349 if (components == (char **) NULL)
1350 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1351 p=path;
cristybb503372010-05-27 20:51:26 +00001352 for (i=0; i < (ssize_t) *number_components; i++)
cristy3ed852e2009-09-05 21:47:34 +00001353 {
1354 for (q=p; *q != '\0'; q++)
1355 if (IsBasenameSeparator(*q))
1356 break;
1357 components[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
cristyc92c1e12011-03-25 15:47:59 +00001358 sizeof(**components));
cristy3ed852e2009-09-05 21:47:34 +00001359 if (components[i] == (char *) NULL)
1360 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1361 (void) CopyMagickString(components[i],p,(size_t) (q-p+1));
1362 p=q+1;
1363 }
1364 components[i]=(char *) NULL;
1365 return(components);
1366}
1367
1368/*
1369%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1370% %
1371% %
1372% %
1373% I s P a t h A c c e s s i b l e %
1374% %
1375% %
1376% %
1377%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1378%
1379% IsPathAccessible() returns MagickTrue if the file as defined by the path is
1380% accessible.
1381%
1382% The format of the IsPathAccessible method is:
1383%
1384% MagickBooleanType IsPathAccessible(const char *filename)
1385%
1386% A description of each parameter follows.
1387%
1388% o path: Specifies a path to a file.
1389%
1390*/
1391MagickExport MagickBooleanType IsPathAccessible(const char *path)
1392{
1393 MagickBooleanType
1394 status;
1395
1396 struct stat
1397 attributes;
1398
1399 if ((path == (const char *) NULL) || (*path == '\0'))
1400 return(MagickFalse);
1401 status=GetPathAttributes(path,&attributes);
1402 if (status == MagickFalse)
1403 return(status);
1404 if (S_ISREG(attributes.st_mode) == 0)
1405 return(MagickFalse);
cristy18c6c272011-09-23 14:40:37 +00001406 if (access_utf8(path,F_OK) != 0)
cristy3ed852e2009-09-05 21:47:34 +00001407 return(MagickFalse);
1408 return(MagickTrue);
1409}
1410
1411/*
1412%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1413% %
1414% %
1415% %
1416+ I s P a t h D i r e c t o r y %
1417% %
1418% %
1419% %
1420%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1421%
1422% IsPathDirectory() returns -1 if the directory does not exist, 1 is returned
1423% if the path represents a directory otherwise 0.
1424%
1425% The format of the IsPathDirectory method is:
1426%
1427% int IsPathDirectory(const char *path)
1428%
1429% A description of each parameter follows.
1430%
1431% o path: The directory path.
1432%
1433*/
1434static int IsPathDirectory(const char *path)
1435{
1436 MagickBooleanType
1437 status;
1438
1439 struct stat
1440 attributes;
1441
1442 if ((path == (const char *) NULL) || (*path == '\0'))
1443 return(MagickFalse);
1444 status=GetPathAttributes(path,&attributes);
1445 if (status == MagickFalse)
1446 return(-1);
1447 if (S_ISDIR(attributes.st_mode) == 0)
1448 return(0);
1449 return(1);
1450}
1451
1452/*
1453%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1454% %
1455% %
1456% %
cristy3ed852e2009-09-05 21:47:34 +00001457% L i s t F i l e s %
1458% %
1459% %
1460% %
1461%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1462%
1463% ListFiles() reads the directory specified and returns a list of filenames
1464% contained in the directory sorted in ascending alphabetic order.
1465%
1466% The format of the ListFiles function is:
1467%
1468% char **ListFiles(const char *directory,const char *pattern,
cristybb503372010-05-27 20:51:26 +00001469% ssize_t *number_entries)
cristy3ed852e2009-09-05 21:47:34 +00001470%
1471% A description of each parameter follows:
1472%
1473% o filelist: Method ListFiles returns a list of filenames contained
1474% in the directory. If the directory specified cannot be read or it is
1475% a file a NULL list is returned.
1476%
1477% o directory: Specifies a pointer to a text string containing a directory
1478% name.
1479%
1480% o pattern: Specifies a pointer to a text string containing a pattern.
1481%
1482% o number_entries: This integer returns the number of filenames in the
1483% list.
1484%
1485*/
1486
1487#if defined(__cplusplus) || defined(c_plusplus)
1488extern "C" {
1489#endif
1490
1491static int FileCompare(const void *x,const void *y)
1492{
1493 register const char
1494 **p,
1495 **q;
1496
1497 p=(const char **) x;
1498 q=(const char **) y;
1499 return(LocaleCompare(*p,*q));
1500}
1501
1502#if defined(__cplusplus) || defined(c_plusplus)
1503}
1504#endif
1505
1506static inline int MagickReadDirectory(DIR *directory,struct dirent *entry,
1507 struct dirent **result)
1508{
1509#if defined(MAGICKCORE_HAVE_READDIR_R)
1510 return(readdir_r(directory,entry,result));
1511#else
1512 (void) entry;
1513 errno=0;
1514 *result=readdir(directory);
1515 return(errno);
1516#endif
1517}
1518
cristyd1dd6e42011-09-04 01:46:08 +00001519MagickPrivate char **ListFiles(const char *directory,const char *pattern,
cristybb503372010-05-27 20:51:26 +00001520 size_t *number_entries)
cristy3ed852e2009-09-05 21:47:34 +00001521{
1522 char
1523 **filelist;
1524
1525 DIR
1526 *current_directory;
1527
1528 struct dirent
1529 *buffer,
1530 *entry;
1531
cristybb503372010-05-27 20:51:26 +00001532 size_t
cristy3ed852e2009-09-05 21:47:34 +00001533 max_entries;
1534
1535 /*
1536 Open directory.
1537 */
1538 assert(directory != (const char *) NULL);
1539 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",directory);
1540 assert(pattern != (const char *) NULL);
cristybb503372010-05-27 20:51:26 +00001541 assert(number_entries != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001542 *number_entries=0;
1543 current_directory=opendir(directory);
1544 if (current_directory == (DIR *) NULL)
1545 return((char **) NULL);
1546 /*
1547 Allocate filelist.
1548 */
1549 max_entries=2048;
1550 filelist=(char **) AcquireQuantumMemory((size_t) max_entries,
1551 sizeof(*filelist));
1552 if (filelist == (char **) NULL)
1553 {
1554 (void) closedir(current_directory);
1555 return((char **) NULL);
1556 }
1557 /*
1558 Save the current and change to the new directory.
1559 */
cristy73bd4a52010-10-05 11:24:23 +00001560 buffer=(struct dirent *) AcquireMagickMemory(sizeof(*buffer)+
cristy0be53ea2010-06-23 19:12:05 +00001561 FILENAME_MAX+1);
cristy3ed852e2009-09-05 21:47:34 +00001562 if (buffer == (struct dirent *) NULL)
1563 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1564 while ((MagickReadDirectory(current_directory,buffer,&entry) == 0) &&
1565 (entry != (struct dirent *) NULL))
1566 {
1567 if (*entry->d_name == '.')
1568 continue;
1569 if ((IsPathDirectory(entry->d_name) > 0) ||
cristy0157aea2010-04-24 21:12:18 +00001570#if defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +00001571 (GlobExpression(entry->d_name,pattern,MagickTrue) != MagickFalse))
1572#else
1573 (GlobExpression(entry->d_name,pattern,MagickFalse) != MagickFalse))
1574#endif
1575 {
1576 if (*number_entries >= max_entries)
1577 {
1578 /*
1579 Extend the file list.
1580 */
1581 max_entries<<=1;
1582 filelist=(char **) ResizeQuantumMemory(filelist,(size_t)
1583 max_entries,sizeof(*filelist));
1584 if (filelist == (char **) NULL)
1585 break;
1586 }
1587#if defined(vms)
1588 {
1589 register char
1590 *p;
1591
1592 p=strchr(entry->d_name,';');
1593 if (p)
1594 *p='\0';
1595 if (*number_entries > 0)
1596 if (LocaleCompare(entry->d_name,filelist[*number_entries-1]) == 0)
1597 continue;
1598 }
1599#endif
1600 filelist[*number_entries]=(char *) AcquireString(entry->d_name);
cristy3ed852e2009-09-05 21:47:34 +00001601 (*number_entries)++;
1602 }
1603 }
1604 buffer=(struct dirent *) RelinquishMagickMemory(buffer);
1605 (void) closedir(current_directory);
1606 if (filelist == (char **) NULL)
1607 return((char **) NULL);
1608 /*
1609 Sort filelist in ascending order.
1610 */
1611 qsort((void *) filelist,(size_t) *number_entries,sizeof(*filelist),
1612 FileCompare);
1613 return(filelist);
1614}
1615
1616/*
1617%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1618% %
1619% %
1620% %
cristya21afde2010-07-02 00:45:40 +00001621% M a g i c k D e l a y %
1622% %
1623% %
1624% %
1625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1626%
1627% MagickDelay() suspends program execution for the number of milliseconds
1628% specified.
1629%
1630% The format of the Delay method is:
1631%
1632% void MagickDelay(const MagickSizeType milliseconds)
1633%
1634% A description of each parameter follows:
1635%
1636% o milliseconds: Specifies the number of milliseconds to delay before
1637% returning.
1638%
1639*/
cristyd1dd6e42011-09-04 01:46:08 +00001640MagickPrivate void MagickDelay(const MagickSizeType milliseconds)
cristya21afde2010-07-02 00:45:40 +00001641{
1642 if (milliseconds == 0)
1643 return;
1644#if defined(MAGICKCORE_HAVE_NANOSLEEP)
1645 {
1646 struct timespec
1647 timer;
1648
1649 timer.tv_sec=(time_t) (milliseconds/1000);
1650 timer.tv_nsec=(milliseconds % 1000)*1000*1000;
1651 (void) nanosleep(&timer,(struct timespec *) NULL);
1652 }
1653#elif defined(MAGICKCORE_HAVE_USLEEP)
1654 usleep(1000*milliseconds);
1655#elif defined(MAGICKCORE_HAVE_SELECT)
1656 {
1657 struct timeval
1658 timer;
1659
1660 timer.tv_sec=(long) milliseconds/1000;
1661 timer.tv_usec=(long) (milliseconds % 1000)*1000;
1662 (void) select(0,(XFD_SET *) NULL,(XFD_SET *) NULL,(XFD_SET *) NULL,&timer);
1663 }
1664#elif defined(MAGICKCORE_HAVE_POLL)
1665 (void) poll((struct pollfd *) NULL,0,(int) milliseconds);
1666#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
1667 Sleep((long) milliseconds);
1668#elif defined(vms)
1669 {
1670 float
1671 timer;
1672
1673 timer=milliseconds/1000.0;
1674 lib$wait(&timer);
1675 }
1676#elif defined(__BEOS__)
1677 snooze(1000*milliseconds);
1678#else
1679# error "Time delay method not defined."
1680#endif
1681}
1682
1683/*
1684%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1685% %
1686% %
1687% %
cristy3ed852e2009-09-05 21:47:34 +00001688% M u l t i l i n e C e n s u s %
1689% %
1690% %
1691% %
1692%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1693%
1694% MultilineCensus() returns the number of lines within a label. A line is
1695% represented by a \n character.
1696%
1697% The format of the MultilineCenus method is:
1698%
cristybb503372010-05-27 20:51:26 +00001699% size_t MultilineCensus(const char *label)
cristy3ed852e2009-09-05 21:47:34 +00001700%
1701% A description of each parameter follows.
1702%
1703% o label: This character string is the label.
1704%
cristy3ed852e2009-09-05 21:47:34 +00001705*/
cristybb503372010-05-27 20:51:26 +00001706MagickExport size_t MultilineCensus(const char *label)
cristy3ed852e2009-09-05 21:47:34 +00001707{
cristybb503372010-05-27 20:51:26 +00001708 size_t
cristy3ed852e2009-09-05 21:47:34 +00001709 number_lines;
1710
1711 /*
1712 Determine the number of lines within this label.
1713 */
1714 if (label == (char *) NULL)
1715 return(0);
1716 for (number_lines=1; *label != '\0'; label++)
1717 if (*label == '\n')
1718 number_lines++;
1719 return(number_lines);
1720}
1721
1722/*
1723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1724% %
1725% %
1726% %
cristy3ed852e2009-09-05 21:47:34 +00001727% S y s t e m C o m m a n d %
1728% %
1729% %
1730% %
1731%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1732%
1733% SystemCommand() executes the specified command and waits until it
1734% terminates. The returned value is the exit status of the command.
1735%
1736% The format of the SystemCommand method is:
1737%
cristy6de4bc22010-01-12 17:10:35 +00001738% int SystemCommand(const MagickBooleanType asynchronous,
1739% const MagickBooleanType verbose,const char *command,
cristyb32b90a2009-09-07 21:45:48 +00001740% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001741%
1742% A description of each parameter follows:
1743%
cristy6de4bc22010-01-12 17:10:35 +00001744% o asynchronous: a value other than 0 executes the parent program
1745% concurrently with the new child process.
1746%
cristyb32b90a2009-09-07 21:45:48 +00001747% o verbose: a value other than 0 prints the executed command before it is
cristy3ed852e2009-09-05 21:47:34 +00001748% invoked.
1749%
cristyb32b90a2009-09-07 21:45:48 +00001750% o command: this string is the command to execute.
1751%
1752% o exception: return any errors here.
cristy3ed852e2009-09-05 21:47:34 +00001753%
1754*/
cristy6de4bc22010-01-12 17:10:35 +00001755MagickExport int SystemCommand(const MagickBooleanType asynchronous,
1756 const MagickBooleanType verbose,const char *command,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001757{
cristyb32b90a2009-09-07 21:45:48 +00001758 char
cristy6de4bc22010-01-12 17:10:35 +00001759 **arguments,
1760 *shell_command;
cristyb32b90a2009-09-07 21:45:48 +00001761
cristy3ed852e2009-09-05 21:47:34 +00001762 int
cristyb32b90a2009-09-07 21:45:48 +00001763 number_arguments,
cristy3ed852e2009-09-05 21:47:34 +00001764 status;
1765
cristyb32b90a2009-09-07 21:45:48 +00001766 PolicyDomain
1767 domain;
1768
1769 PolicyRights
1770 rights;
1771
cristybb503372010-05-27 20:51:26 +00001772 register ssize_t
cristyb32b90a2009-09-07 21:45:48 +00001773 i;
1774
1775 status=(-1);
1776 arguments=StringToArgv(command,&number_arguments);
1777 if (arguments == (char **) NULL)
1778 return(status);
cristyb32b90a2009-09-07 21:45:48 +00001779 rights=ExecutePolicyRights;
cristy6de4bc22010-01-12 17:10:35 +00001780 domain=DelegatePolicyDomain;
cristyb32b90a2009-09-07 21:45:48 +00001781 if (IsRightsAuthorized(domain,rights,arguments[1]) == MagickFalse)
1782 {
cristya9197f62010-01-12 02:23:34 +00001783 errno=EPERM;
cristyb32b90a2009-09-07 21:45:48 +00001784 (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
anthonye5b39652012-04-21 05:37:29 +00001785 "NotAuthorized","'%s'",arguments[1]);
cristycee97112010-05-28 00:44:52 +00001786 for (i=0; i < (ssize_t) number_arguments; i++)
cristyb32b90a2009-09-07 21:45:48 +00001787 arguments[i]=DestroyString(arguments[i]);
1788 arguments=(char **) RelinquishMagickMemory(arguments);
1789 return(-1);
1790 }
cristy3ed852e2009-09-05 21:47:34 +00001791 if (verbose != MagickFalse)
1792 {
cristyb51dff52011-05-19 16:55:47 +00001793 (void) FormatLocaleFile(stderr,"%s\n",command);
cristy3ed852e2009-09-05 21:47:34 +00001794 (void) fflush(stderr);
1795 }
cristy6de4bc22010-01-12 17:10:35 +00001796 shell_command=(char *) command;
1797 if (asynchronous != MagickFalse)
1798 {
1799 shell_command=AcquireString(command);
1800 (void) ConcatenateMagickString(shell_command,"&",MaxTextExtent);
1801 }
cristy3ed852e2009-09-05 21:47:34 +00001802#if defined(MAGICKCORE_POSIX_SUPPORT)
cristya9197f62010-01-12 02:23:34 +00001803#if !defined(MAGICKCORE_HAVE_EXECVP)
cristy6de4bc22010-01-12 17:10:35 +00001804 status=system(shell_command);
cristy3ed852e2009-09-05 21:47:34 +00001805#else
cristye21dc962012-01-12 17:22:31 +00001806 if ((asynchronous != MagickFalse) ||
cristya4560912012-01-14 20:28:03 +00001807 (strpbrk(shell_command,"&;<>|") != (char *) NULL))
cristy6de4bc22010-01-12 17:10:35 +00001808 status=system(shell_command);
cristy3ed852e2009-09-05 21:47:34 +00001809 else
1810 {
cristyb32b90a2009-09-07 21:45:48 +00001811 pid_t
1812 child_pid;
cristy3ed852e2009-09-05 21:47:34 +00001813
cristyb32b90a2009-09-07 21:45:48 +00001814 /*
1815 Call application directly rather than from a shell.
1816 */
cristye42f6582012-02-11 17:59:50 +00001817 child_pid=(pid_t) fork();
cristyb32b90a2009-09-07 21:45:48 +00001818 if (child_pid == (pid_t) -1)
cristy3ed852e2009-09-05 21:47:34 +00001819 status=system(command);
1820 else
cristyb32b90a2009-09-07 21:45:48 +00001821 if (child_pid == 0)
1822 {
1823 status=execvp(arguments[1],arguments+1);
1824 _exit(1);
1825 }
1826 else
1827 {
1828 int
1829 child_status;
cristy3ed852e2009-09-05 21:47:34 +00001830
cristyb32b90a2009-09-07 21:45:48 +00001831 pid_t
1832 pid;
cristy3ed852e2009-09-05 21:47:34 +00001833
cristyb32b90a2009-09-07 21:45:48 +00001834 child_status=0;
cristye42f6582012-02-11 17:59:50 +00001835 pid=(pid_t) waitpid(child_pid,&child_status,0);
cristyb32b90a2009-09-07 21:45:48 +00001836 if (pid == -1)
1837 status=(-1);
cristy3ed852e2009-09-05 21:47:34 +00001838 else
1839 {
cristyb32b90a2009-09-07 21:45:48 +00001840 if (WIFEXITED(child_status) != 0)
1841 status=WEXITSTATUS(child_status);
cristy3ed852e2009-09-05 21:47:34 +00001842 else
cristyb32b90a2009-09-07 21:45:48 +00001843 if (WIFSIGNALED(child_status))
1844 status=(-1);
cristy3ed852e2009-09-05 21:47:34 +00001845 }
cristyb32b90a2009-09-07 21:45:48 +00001846 }
cristy3ed852e2009-09-05 21:47:34 +00001847 }
1848#endif
cristy0157aea2010-04-24 21:12:18 +00001849#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
cristyea7bce92011-12-12 00:24:44 +00001850 status=NTSystemCommand(shell_command);
cristy3ed852e2009-09-05 21:47:34 +00001851#elif defined(macintosh)
cristy6de4bc22010-01-12 17:10:35 +00001852 status=MACSystemCommand(shell_command);
cristy3ed852e2009-09-05 21:47:34 +00001853#elif defined(vms)
cristy6de4bc22010-01-12 17:10:35 +00001854 status=system(shell_command);
cristy3ed852e2009-09-05 21:47:34 +00001855#else
1856# error No suitable system() method.
1857#endif
1858 if (status < 0)
cristy6de4bc22010-01-12 17:10:35 +00001859 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
anthonye5b39652012-04-21 05:37:29 +00001860 "'%s' (%d)",command,status);
cristy6de4bc22010-01-12 17:10:35 +00001861 if (shell_command != command)
1862 shell_command=DestroyString(shell_command);
cristycee97112010-05-28 00:44:52 +00001863 for (i=0; i < (ssize_t) number_arguments; i++)
cristyb32b90a2009-09-07 21:45:48 +00001864 arguments[i]=DestroyString(arguments[i]);
1865 arguments=(char **) RelinquishMagickMemory(arguments);
cristy3ed852e2009-09-05 21:47:34 +00001866 return(status);
1867}