blob: d44808332227a7f1f58cd060217cfd4f1014a7f2 [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%
anthonyde897b72012-04-27 00:16:17 +0000678% ExpandFilenames() checks each argument of the given argument array, and
679% expands it if they have a wildcard character.
680%
681% Any coder prefix (EG: 'coder:filename') or read modifier postfix (EG:
682% 'filename[...]') are ignored during the file the expansion, but will be
683% included in the final argument. If no filename matching the meta-character
684% 'glob' is found the original argument is returned.
685%
686% For example, an argument of '*.gif[20x20]' will be replaced by the list
687% 'abc.gif[20x20]', 'foobar.gif[20x20]', 'xyzzy.gif[20x20]'
688% if such filenames exist, (in the current directory in this case).
689%
690% Meta-characters handled...
691% @ read a list of filenames (no further expansion performed)
692% ~ At start of filename expands to HOME environemtn variable
693% * matches any string including an empty string
694% ? matches by any single character
695%
696% WARNING: filenames starting with '.' (hidden files in a UNIX file system)
697% will never be expanded. Attempting to epand '.*' will produce no change.
698%
699% Expansion is ignored for coders "label:" "caption:" "pango:" and "vid:".
700% Which provide their own '@' meta-character handling.
701%
anthony451f9092012-05-11 01:56:24 +0000702% You can see the results of the expansion using "Configure" log
703% events.
704%
705%
706% The returned list should be freed using DestroyStringList().
707%
708% However the strings in the original pointed to argv are not
709% freed (TO BE CHECKED). So a copy of the original pointer (and count)
710% should be kept separate if they need to be freed later.
711%
cristy3ed852e2009-09-05 21:47:34 +0000712%
713% The format of the ExpandFilenames function is:
714%
715% status=ExpandFilenames(int *number_arguments,char ***arguments)
716%
717% A description of each parameter follows:
718%
719% o number_arguments: Specifies a pointer to an integer describing the
720% number of elements in the argument vector.
721%
722% o arguments: Specifies a pointer to a text array containing the command
723% line arguments.
724%
725*/
726MagickExport MagickBooleanType ExpandFilenames(int *number_arguments,
727 char ***arguments)
728{
729 char
cristy00976d82011-02-20 20:31:28 +0000730 *directory,
cristy3ed852e2009-09-05 21:47:34 +0000731 home_directory[MaxTextExtent],
732 **vector;
733
cristybb503372010-05-27 20:51:26 +0000734 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000735 i,
736 j;
737
cristybb503372010-05-27 20:51:26 +0000738 size_t
cristy3ed852e2009-09-05 21:47:34 +0000739 number_files;
740
cristy00976d82011-02-20 20:31:28 +0000741 ssize_t
742 count,
743 parameters;
744
cristy3ed852e2009-09-05 21:47:34 +0000745 /*
746 Allocate argument vector.
747 */
748 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
749 assert(number_arguments != (int *) NULL);
750 assert(arguments != (char ***) NULL);
751 vector=(char **) AcquireQuantumMemory((size_t) (*number_arguments+1),
752 sizeof(*vector));
753 if (vector == (char **) NULL)
754 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
755 /*
756 Expand any wildcard filenames.
757 */
758 *home_directory='\0';
cristy3ed852e2009-09-05 21:47:34 +0000759 count=0;
cristybb503372010-05-27 20:51:26 +0000760 for (i=0; i < (ssize_t) *number_arguments; i++)
cristy3ed852e2009-09-05 21:47:34 +0000761 {
762 char
763 **filelist,
764 filename[MaxTextExtent],
765 magick[MaxTextExtent],
766 *option,
767 path[MaxTextExtent],
768 subimage[MaxTextExtent];
769
770 MagickBooleanType
771 destroy;
772
773 option=(*arguments)[i];
774 *magick='\0';
775 *path='\0';
776 *filename='\0';
777 *subimage='\0';
778 vector[count++]=ConstantString(option);
779 destroy=MagickTrue;
cristy042ee782011-04-22 18:48:30 +0000780 parameters=ParseCommandOption(MagickCommandOptions,MagickFalse,option);
cristy3ed852e2009-09-05 21:47:34 +0000781 if (parameters > 0)
782 {
783 /*
784 Do not expand command option parameters.
785 */
786 for (j=0; j < parameters; j++)
787 {
788 i++;
cristybb503372010-05-27 20:51:26 +0000789 if (i == (ssize_t) *number_arguments)
cristy3ed852e2009-09-05 21:47:34 +0000790 break;
791 option=(*arguments)[i];
792 vector[count++]=ConstantString(option);
793 }
794 continue;
795 }
796 if ((*option == '"') || (*option == '\''))
797 continue;
cristy4b064822012-04-29 13:26:43 +0000798 GetPathComponent(option,TailPath,filename);
cristy3ed852e2009-09-05 21:47:34 +0000799 GetPathComponent(option,MagickPath,magick);
800 if ((LocaleCompare(magick,"CAPTION") == 0) ||
801 (LocaleCompare(magick,"LABEL") == 0) ||
cristyc0732c42012-03-20 19:28:35 +0000802 (LocaleCompare(magick,"PANGO") == 0) ||
cristy3ed852e2009-09-05 21:47:34 +0000803 (LocaleCompare(magick,"VID") == 0))
804 continue;
cristy127425f2012-04-29 13:38:05 +0000805 if ((IsGlob(filename) == MagickFalse) && (*option != '@'))
cristy3ed852e2009-09-05 21:47:34 +0000806 continue;
cristy127425f2012-04-29 13:38:05 +0000807 if (*option != '@')
cristy3ed852e2009-09-05 21:47:34 +0000808 {
809 /*
810 Generate file list from wildcard filename (e.g. *.jpg).
811 */
812 GetPathComponent(option,HeadPath,path);
813 GetPathComponent(option,SubimagePath,subimage);
814 ExpandFilename(path);
cristyf5ee5be2009-11-06 02:22:56 +0000815 if (*home_directory == '\0')
cristy00976d82011-02-20 20:31:28 +0000816 directory=getcwd(home_directory,MaxTextExtent-1);
817 (void) directory;
cristy4b064822012-04-29 13:26:43 +0000818 filelist=ListFiles(*path == '\0' ? home_directory : path,filename,
cristy3ed852e2009-09-05 21:47:34 +0000819 &number_files);
820 }
821 else
822 {
823 char
824 *files;
825
826 ExceptionInfo
827 *exception;
828
829 int
cristyf9218a72010-07-03 17:29:40 +0000830 length;
cristy3ed852e2009-09-05 21:47:34 +0000831
832 /*
833 Generate file list from file list (e.g. @filelist.txt).
834 */
835 exception=AcquireExceptionInfo();
cristy47b20292012-04-26 18:18:48 +0000836 files=FileToString(option+1,~0,exception);
cristy3ed852e2009-09-05 21:47:34 +0000837 exception=DestroyExceptionInfo(exception);
838 if (files == (char *) NULL)
839 continue;
cristyf9218a72010-07-03 17:29:40 +0000840 filelist=StringToArgv(files,&length);
841 if (filelist == (char **) NULL)
842 continue;
cristy3ed852e2009-09-05 21:47:34 +0000843 files=DestroyString(files);
cristyf9218a72010-07-03 17:29:40 +0000844 filelist[0]=DestroyString(filelist[0]);
845 for (j=0; j < (ssize_t) (length-1); j++)
846 filelist[j]=filelist[j+1];
847 number_files=(size_t) length-1;
cristy3ed852e2009-09-05 21:47:34 +0000848 }
849 if (filelist == (char **) NULL)
850 continue;
cristybb503372010-05-27 20:51:26 +0000851 for (j=0; j < (ssize_t) number_files; j++)
cristy3ed852e2009-09-05 21:47:34 +0000852 if (IsPathDirectory(filelist[j]) <= 0)
853 break;
cristybb503372010-05-27 20:51:26 +0000854 if (j == (ssize_t) number_files)
cristy3ed852e2009-09-05 21:47:34 +0000855 {
cristybb503372010-05-27 20:51:26 +0000856 for (j=0; j < (ssize_t) number_files; j++)
cristy3ed852e2009-09-05 21:47:34 +0000857 filelist[j]=DestroyString(filelist[j]);
858 filelist=(char **) RelinquishMagickMemory(filelist);
859 continue;
860 }
861 /*
862 Transfer file list to argument vector.
863 */
864 vector=(char **) ResizeQuantumMemory(vector,(size_t) *number_arguments+
865 count+number_files+1,sizeof(*vector));
866 if (vector == (char **) NULL)
867 return(MagickFalse);
cristybb503372010-05-27 20:51:26 +0000868 for (j=0; j < (ssize_t) number_files; j++)
cristy3ed852e2009-09-05 21:47:34 +0000869 {
cristy0e526222010-05-06 14:07:32 +0000870 option=filelist[j];
cristy042ee782011-04-22 18:48:30 +0000871 parameters=ParseCommandOption(MagickCommandOptions,MagickFalse,option);
cristy0e526222010-05-06 14:07:32 +0000872 if (parameters > 0)
873 {
cristybb503372010-05-27 20:51:26 +0000874 ssize_t
cristy0e526222010-05-06 14:07:32 +0000875 k;
876
877 /*
878 Do not expand command option parameters.
879 */
880 vector[count++]=ConstantString(option);
881 for (k=0; k < parameters; k++)
882 {
883 j++;
cristybb503372010-05-27 20:51:26 +0000884 if (j == (ssize_t) number_files)
cristy0e526222010-05-06 14:07:32 +0000885 break;
886 option=filelist[j];
887 vector[count++]=ConstantString(option);
888 }
889 continue;
890 }
cristy3ed852e2009-09-05 21:47:34 +0000891 (void) CopyMagickString(filename,path,MaxTextExtent);
892 if (*path != '\0')
893 (void) ConcatenateMagickString(filename,DirectorySeparator,
894 MaxTextExtent);
895 (void) ConcatenateMagickString(filename,filelist[j],MaxTextExtent);
896 filelist[j]=DestroyString(filelist[j]);
cristycfef62c2010-05-05 01:21:43 +0000897 if (strlen(filename) >= (MaxTextExtent-1))
cristy3ed852e2009-09-05 21:47:34 +0000898 ThrowFatalException(OptionFatalError,"FilenameTruncated");
cristy47dc34d2010-04-22 16:12:43 +0000899 if (IsPathDirectory(filename) <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000900 {
901 char
902 path[MaxTextExtent];
903
904 *path='\0';
905 if (*magick != '\0')
906 {
907 (void) ConcatenateMagickString(path,magick,MaxTextExtent);
908 (void) ConcatenateMagickString(path,":",MaxTextExtent);
909 }
910 (void) ConcatenateMagickString(path,filename,MaxTextExtent);
911 if (*subimage != '\0')
912 {
913 (void) ConcatenateMagickString(path,"[",MaxTextExtent);
914 (void) ConcatenateMagickString(path,subimage,MaxTextExtent);
915 (void) ConcatenateMagickString(path,"]",MaxTextExtent);
916 }
cristy37e0b382011-06-07 13:31:21 +0000917 if (strlen(path) >= (MaxTextExtent-1))
cristy3ed852e2009-09-05 21:47:34 +0000918 ThrowFatalException(OptionFatalError,"FilenameTruncated");
919 if (destroy != MagickFalse)
920 {
921 count--;
922 vector[count]=DestroyString(vector[count]);
923 destroy=MagickFalse;
924 }
925 vector[count++]=ConstantString(path);
926 }
927 }
928 filelist=(char **) RelinquishMagickMemory(filelist);
929 }
930 vector[count]=(char *) NULL;
931 if (IsEventLogging() != MagickFalse)
932 {
933 char
934 *command_line;
935
936 command_line=AcquireString(vector[0]);
937 for (i=1; i < count; i++)
938 {
939 (void) ConcatenateString(&command_line," {");
940 (void) ConcatenateString(&command_line,vector[i]);
941 (void) ConcatenateString(&command_line,"}");
942 }
943 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
944 "Command line: %s",command_line);
945 command_line=DestroyString(command_line);
946 }
947 *number_arguments=(int) count;
948 *arguments=vector;
949 return(MagickTrue);
950}
951
952/*
953%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
954% %
955% %
956% %
957% G e t E x e c u t i o n P a t h %
958% %
959% %
960% %
961%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
962%
963% GetExecutionPath() returns the pathname of the executable that started
964% the process. On success MagickTrue is returned, otherwise MagickFalse.
965%
966% The format of the GetExecutionPath method is:
967%
968% MagickBooleanType GetExecutionPath(char *path,const size_t extent)
969%
970% A description of each parameter follows:
971%
972% o path: the pathname of the executable that started the process.
973%
974% o extent: the maximum extent of the path.
975%
976*/
cristyd1dd6e42011-09-04 01:46:08 +0000977MagickPrivate MagickBooleanType GetExecutionPath(char *path,const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +0000978{
cristyfbe485a2011-02-22 13:54:48 +0000979 char
980 *directory;
981
cristy3ed852e2009-09-05 21:47:34 +0000982 *path='\0';
cristyfbe485a2011-02-22 13:54:48 +0000983 directory=getcwd(path,(unsigned long) extent);
984 (void) directory;
cristyfa09d142009-10-15 01:02:25 +0000985#if defined(MAGICKCORE_HAVE_GETPID) && defined(MAGICKCORE_HAVE_READLINK) && defined(PATH_MAX)
cristy3ed852e2009-09-05 21:47:34 +0000986 {
987 char
988 link_path[MaxTextExtent],
cristyfa09d142009-10-15 01:02:25 +0000989 execution_path[PATH_MAX+1];
cristy3ed852e2009-09-05 21:47:34 +0000990
991 ssize_t
992 count;
993
cristyb51dff52011-05-19 16:55:47 +0000994 (void) FormatLocaleString(link_path,MaxTextExtent,"/proc/%.20g/exe",
cristye8c25f92010-06-03 00:53:06 +0000995 (double) getpid());
cristyfa09d142009-10-15 01:02:25 +0000996 count=readlink(link_path,execution_path,PATH_MAX);
cristy3ed852e2009-09-05 21:47:34 +0000997 if (count == -1)
998 {
cristyb51dff52011-05-19 16:55:47 +0000999 (void) FormatLocaleString(link_path,MaxTextExtent,"/proc/%.20g/file",
cristye8c25f92010-06-03 00:53:06 +00001000 (double) getpid());
cristyfa09d142009-10-15 01:02:25 +00001001 count=readlink(link_path,execution_path,PATH_MAX);
cristy3ed852e2009-09-05 21:47:34 +00001002 }
1003 if ((count > 0) && (count <= (ssize_t) PATH_MAX))
1004 {
cristyfa09d142009-10-15 01:02:25 +00001005 execution_path[count]='\0';
1006 (void) CopyMagickString(path,execution_path,extent);
cristy3ed852e2009-09-05 21:47:34 +00001007 }
1008 }
1009#endif
1010#if defined(MAGICKCORE_HAVE__NSGETEXECUTABLEPATH)
1011 {
1012 char
1013 executable_path[PATH_MAX << 1],
cristyfa09d142009-10-15 01:02:25 +00001014 execution_path[PATH_MAX+1];
cristy3ed852e2009-09-05 21:47:34 +00001015
1016 uint32_t
1017 length;
1018
1019 length=sizeof(executable_path);
1020 if ((_NSGetExecutablePath(executable_path,&length) == 0) &&
cristyfa09d142009-10-15 01:02:25 +00001021 (realpath(executable_path,execution_path) != (char *) NULL))
1022 (void) CopyMagickString(path,execution_path,extent);
cristy3ed852e2009-09-05 21:47:34 +00001023 }
1024#endif
1025#if defined(MAGICKCORE_HAVE_GETEXECNAME)
1026 {
1027 const char
1028 *execution_path;
1029
1030 execution_path=(const char *) getexecname();
1031 if (execution_path != (const char *) NULL)
1032 {
1033 if (*execution_path != *DirectorySeparator)
1034 (void) ConcatenateMagickString(path,DirectorySeparator,extent);
1035 (void) ConcatenateMagickString(path,execution_path,extent);
1036 }
1037 }
1038#endif
cristy0157aea2010-04-24 21:12:18 +00001039#if defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +00001040 NTGetExecutionPath(path,extent);
1041#endif
cristyfa09d142009-10-15 01:02:25 +00001042#if defined(__GNU__)
1043 {
1044 char
1045 *program_name,
1046 *execution_path;
1047
cristybb503372010-05-27 20:51:26 +00001048 ssize_t
cristyfa09d142009-10-15 01:02:25 +00001049 count;
1050
1051 count=0;
1052 execution_path=(char *) NULL;
1053 program_name=program_invocation_name;
1054 if (*program_invocation_name != '/')
1055 {
1056 size_t
1057 extent;
1058
cristyb29bea52011-05-26 17:54:31 +00001059 extent=strlen(directory)+strlen(program_name)+2;
cristyfa09d142009-10-15 01:02:25 +00001060 program_name=AcquireQuantumMemory(extent,sizeof(*program_name));
1061 if (program_name == (char *) NULL)
1062 program_name=program_invocation_name;
1063 else
cristyb29bea52011-05-26 17:54:31 +00001064 count=FormatLocaleString(program_name,extent,"%s/%s",directory,
cristyfa09d142009-10-15 01:02:25 +00001065 program_invocation_name);
1066 }
1067 if (count != -1)
1068 {
1069 execution_path=realpath(program_name,NULL);
1070 if (execution_path != (char *) NULL)
1071 (void) CopyMagickString(path,execution_path,extent);
1072 }
1073 if (program_name != program_invocation_name)
1074 program_name=(char *) RelinquishMagickMemory(program_name);
1075 execution_path=(char *) RelinquishMagickMemory(execution_path);
1076 }
1077#endif
cristy3ed852e2009-09-05 21:47:34 +00001078 return(IsPathAccessible(path));
1079}
1080
1081/*
1082%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1083% %
1084% %
1085% %
cristy688f07b2009-09-27 15:19:13 +00001086% G e t M a g i c k P a g e S i z e %
1087% %
1088% %
1089% %
1090%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1091%
1092% GetMagickPageSize() returns the memory page size.
1093%
1094% The format of the GetMagickPageSize method is:
1095%
cristybb503372010-05-27 20:51:26 +00001096% ssize_t GetMagickPageSize()
cristy688f07b2009-09-27 15:19:13 +00001097%
1098*/
cristyd1dd6e42011-09-04 01:46:08 +00001099MagickPrivate ssize_t GetMagickPageSize(void)
cristy688f07b2009-09-27 15:19:13 +00001100{
cristybb503372010-05-27 20:51:26 +00001101 static ssize_t
cristy688f07b2009-09-27 15:19:13 +00001102 page_size = -1;
1103
1104 if (page_size > 0)
1105 return(page_size);
1106#if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
cristyecd0ab52010-05-30 14:59:20 +00001107 page_size=(ssize_t) sysconf(_SC_PAGE_SIZE);
cristy09449f72010-01-23 03:08:36 +00001108#else
cristy688f07b2009-09-27 15:19:13 +00001109#if defined(MAGICKCORE_HAVE_GETPAGESIZE)
cristyecd0ab52010-05-30 14:59:20 +00001110 page_size=(ssize_t) getpagesize();
cristy09449f72010-01-23 03:08:36 +00001111#endif
cristy688f07b2009-09-27 15:19:13 +00001112#endif
1113 if (page_size <= 0)
1114 page_size=16384;
1115 return(page_size);
1116}
1117
1118/*
1119%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1120% %
1121% %
1122% %
cristy3ed852e2009-09-05 21:47:34 +00001123% G e t P a t h A t t r i b u t e s %
1124% %
1125% %
1126% %
1127%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1128%
1129% GetPathAttributes() returns attributes (e.g. size of file) about a path.
1130%
1131% The path of the GetPathAttributes method is:
1132%
1133% MagickBooleanType GetPathAttributes(const char *path,void *attributes)
1134%
1135% A description of each parameter follows.
1136%
1137% o path: the file path.
1138%
1139% o attributes: the path attributes are returned here.
1140%
1141*/
cristy3ed852e2009-09-05 21:47:34 +00001142MagickExport MagickBooleanType GetPathAttributes(const char *path,
1143 void *attributes)
1144{
1145 MagickBooleanType
1146 status;
1147
1148 if (path == (const char *) NULL)
1149 {
1150 errno=EINVAL;
1151 return(MagickFalse);
1152 }
cristy18c6c272011-09-23 14:40:37 +00001153 status=stat_utf8(path,(struct stat *) attributes) == 0 ? MagickTrue :
1154 MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00001155 return(status);
1156}
1157
1158/*
1159%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1160% %
1161% %
1162% %
1163% G e t P a t h C o m p o n e n t %
1164% %
1165% %
1166% %
1167%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1168%
1169% GetPathComponent() returns the parent directory name, filename, basename, or
1170% extension of a file path.
1171%
anthony104f8932012-05-13 01:54:53 +00001172% The component string pointed to must have at least MaxTextExtent space
1173% for the results to be stored.
1174%
cristy3ed852e2009-09-05 21:47:34 +00001175% The format of the GetPathComponent function is:
1176%
1177% GetPathComponent(const char *path,PathType type,char *component)
1178%
1179% A description of each parameter follows:
1180%
1181% o path: Specifies a pointer to a character array that contains the
1182% file path.
1183%
1184% o type: Specififies which file path component to return.
1185%
1186% o component: the selected file path component is returned here.
1187%
1188*/
1189MagickExport void GetPathComponent(const char *path,PathType type,
1190 char *component)
1191{
1192 char
1193 magick[MaxTextExtent],
1194 *q,
1195 subimage[MaxTextExtent];
1196
1197 register char
1198 *p;
1199
1200 assert(path != (const char *) NULL);
1201 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",path);
1202 assert(component != (char *) NULL);
1203 if (*path == '\0')
1204 {
1205 *component='\0';
1206 return;
1207 }
1208 (void) CopyMagickString(component,path,MaxTextExtent);
1209 *magick='\0';
cristy1224a992011-10-12 19:23:41 +00001210#if defined(__OS2__)
1211 if (path[1] != ":")
1212#endif
1213 for (p=component; *p != '\0'; p++)
1214 {
1215 if ((*p == '%') && (*(p+1) == '['))
1216 {
1217 /*
1218 Skip over %[...].
1219 */
1220 for (p++; (*p != ']') && (*p != '\0'); p++) ;
1221 if (*p == '\0')
1222 break;
1223 }
1224 if ((*p == ':') && (IsPathDirectory(path) < 0) &&
1225 (IsPathAccessible(path) == MagickFalse))
1226 {
1227 /*
1228 Look for image format specification (e.g. ps3:image).
1229 */
1230 (void) CopyMagickString(magick,component,(size_t) (p-component+1));
1231 if (IsMagickConflict(magick) != MagickFalse)
1232 *magick='\0';
1233 else
1234 for (q=component; *q != '\0'; q++)
1235 *q=(*++p);
1236 break;
1237 }
1238 }
cristy86057c42011-08-03 18:12:58 +00001239 *subimage='\0';
1240 p=component;
1241 if (*p != '\0')
1242 p=component+strlen(component)-1;
1243 if ((*p == ']') && (strchr(component,'[') != (char *) NULL) &&
1244 (IsPathAccessible(path) == MagickFalse))
1245 {
1246 /*
1247 Look for scene specification (e.g. img0001.pcd[4]).
1248 */
1249 for (q=p-1; q > component; q--)
1250 if (*q == '[')
1251 break;
1252 if (*q == '[')
1253 {
1254 (void) CopyMagickString(subimage,q+1,MaxTextExtent);
1255 subimage[p-q-1]='\0';
1256 if ((IsSceneGeometry(subimage,MagickFalse) == MagickFalse) &&
1257 (IsGeometry(subimage) == MagickFalse))
1258 *subimage='\0';
cristy1224a992011-10-12 19:23:41 +00001259 else
1260 *q='\0';
cristy86057c42011-08-03 18:12:58 +00001261 }
1262 }
cristy3ed852e2009-09-05 21:47:34 +00001263 p=component;
1264 if (*p != '\0')
1265 for (p=component+strlen(component)-1; p > component; p--)
1266 if (IsBasenameSeparator(*p) != MagickFalse)
1267 break;
1268 switch (type)
1269 {
1270 case MagickPath:
1271 {
1272 (void) CopyMagickString(component,magick,MaxTextExtent);
1273 break;
1274 }
1275 case RootPath:
1276 {
1277 for (p=component+(strlen(component)-1); p > component; p--)
1278 {
1279 if (IsBasenameSeparator(*p) != MagickFalse)
1280 break;
1281 if (*p == '.')
1282 break;
1283 }
1284 if (*p == '.')
1285 *p='\0';
1286 break;
1287 }
1288 case HeadPath:
1289 {
1290 *p='\0';
1291 break;
1292 }
1293 case TailPath:
1294 {
1295 if (IsBasenameSeparator(*p) != MagickFalse)
1296 (void) CopyMagickMemory((unsigned char *) component,
1297 (const unsigned char *) (p+1),strlen(p+1)+1);
1298 break;
1299 }
1300 case BasePath:
1301 {
1302 if (IsBasenameSeparator(*p) != MagickFalse)
1303 (void) CopyMagickString(component,p+1,MaxTextExtent);
1304 for (p=component+(strlen(component)-1); p > component; p--)
1305 if (*p == '.')
1306 {
1307 *p='\0';
1308 break;
1309 }
1310 break;
1311 }
1312 case ExtensionPath:
1313 {
1314 if (IsBasenameSeparator(*p) != MagickFalse)
1315 (void) CopyMagickString(component,p+1,MaxTextExtent);
1316 p=component;
1317 if (*p != '\0')
1318 for (p=component+strlen(component)-1; p > component; p--)
1319 if (*p == '.')
1320 break;
1321 *component='\0';
1322 if (*p == '.')
1323 (void) CopyMagickString(component,p+1,MaxTextExtent);
1324 break;
1325 }
1326 case SubimagePath:
1327 {
1328 (void) CopyMagickString(component,subimage,MaxTextExtent);
1329 break;
1330 }
1331 case CanonicalPath:
1332 case UndefinedPath:
1333 break;
1334 }
1335}
1336
1337/*
1338%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1339% %
1340% %
1341% %
1342% G e t P a t h C o m p o n e n t s %
1343% %
1344% %
1345% %
1346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1347%
1348% GetPathComponents() returns a list of path components.
1349%
1350% The format of the GetPathComponents method is:
1351%
1352% char **GetPathComponents(const char *path,
cristybb503372010-05-27 20:51:26 +00001353% size_t *number_componenets)
cristy3ed852e2009-09-05 21:47:34 +00001354%
1355% A description of each parameter follows:
1356%
1357% o path: Specifies the string to segment into a list.
1358%
1359% o number_components: return the number of components in the list
1360%
1361*/
cristyd1dd6e42011-09-04 01:46:08 +00001362MagickPrivate char **GetPathComponents(const char *path,
cristybb503372010-05-27 20:51:26 +00001363 size_t *number_components)
cristy3ed852e2009-09-05 21:47:34 +00001364{
1365 char
1366 **components;
1367
1368 register const char
1369 *p,
1370 *q;
1371
cristybb503372010-05-27 20:51:26 +00001372 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001373 i;
1374
1375 if (path == (char *) NULL)
1376 return((char **) NULL);
1377 *number_components=1;
1378 for (p=path; *p != '\0'; p++)
1379 if (IsBasenameSeparator(*p))
1380 (*number_components)++;
1381 components=(char **) AcquireQuantumMemory((size_t) *number_components+1UL,
1382 sizeof(*components));
1383 if (components == (char **) NULL)
1384 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1385 p=path;
cristybb503372010-05-27 20:51:26 +00001386 for (i=0; i < (ssize_t) *number_components; i++)
cristy3ed852e2009-09-05 21:47:34 +00001387 {
1388 for (q=p; *q != '\0'; q++)
1389 if (IsBasenameSeparator(*q))
1390 break;
1391 components[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
cristyc92c1e12011-03-25 15:47:59 +00001392 sizeof(**components));
cristy3ed852e2009-09-05 21:47:34 +00001393 if (components[i] == (char *) NULL)
1394 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1395 (void) CopyMagickString(components[i],p,(size_t) (q-p+1));
1396 p=q+1;
1397 }
1398 components[i]=(char *) NULL;
1399 return(components);
1400}
1401
1402/*
1403%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1404% %
1405% %
1406% %
1407% I s P a t h A c c e s s i b l e %
1408% %
1409% %
1410% %
1411%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1412%
1413% IsPathAccessible() returns MagickTrue if the file as defined by the path is
1414% accessible.
1415%
1416% The format of the IsPathAccessible method is:
1417%
1418% MagickBooleanType IsPathAccessible(const char *filename)
1419%
1420% A description of each parameter follows.
1421%
1422% o path: Specifies a path to a file.
1423%
1424*/
1425MagickExport MagickBooleanType IsPathAccessible(const char *path)
1426{
1427 MagickBooleanType
1428 status;
1429
1430 struct stat
1431 attributes;
1432
1433 if ((path == (const char *) NULL) || (*path == '\0'))
1434 return(MagickFalse);
1435 status=GetPathAttributes(path,&attributes);
1436 if (status == MagickFalse)
1437 return(status);
1438 if (S_ISREG(attributes.st_mode) == 0)
1439 return(MagickFalse);
cristy18c6c272011-09-23 14:40:37 +00001440 if (access_utf8(path,F_OK) != 0)
cristy3ed852e2009-09-05 21:47:34 +00001441 return(MagickFalse);
1442 return(MagickTrue);
1443}
1444
1445/*
1446%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1447% %
1448% %
1449% %
1450+ I s P a t h D i r e c t o r y %
1451% %
1452% %
1453% %
1454%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1455%
1456% IsPathDirectory() returns -1 if the directory does not exist, 1 is returned
1457% if the path represents a directory otherwise 0.
1458%
1459% The format of the IsPathDirectory method is:
1460%
1461% int IsPathDirectory(const char *path)
1462%
1463% A description of each parameter follows.
1464%
1465% o path: The directory path.
1466%
1467*/
1468static int IsPathDirectory(const char *path)
1469{
1470 MagickBooleanType
1471 status;
1472
1473 struct stat
1474 attributes;
1475
1476 if ((path == (const char *) NULL) || (*path == '\0'))
1477 return(MagickFalse);
1478 status=GetPathAttributes(path,&attributes);
1479 if (status == MagickFalse)
1480 return(-1);
1481 if (S_ISDIR(attributes.st_mode) == 0)
1482 return(0);
1483 return(1);
1484}
1485
1486/*
1487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1488% %
1489% %
1490% %
cristy3ed852e2009-09-05 21:47:34 +00001491% L i s t F i l e s %
1492% %
1493% %
1494% %
1495%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1496%
1497% ListFiles() reads the directory specified and returns a list of filenames
1498% contained in the directory sorted in ascending alphabetic order.
1499%
1500% The format of the ListFiles function is:
1501%
1502% char **ListFiles(const char *directory,const char *pattern,
cristybb503372010-05-27 20:51:26 +00001503% ssize_t *number_entries)
cristy3ed852e2009-09-05 21:47:34 +00001504%
1505% A description of each parameter follows:
1506%
1507% o filelist: Method ListFiles returns a list of filenames contained
1508% in the directory. If the directory specified cannot be read or it is
1509% a file a NULL list is returned.
1510%
1511% o directory: Specifies a pointer to a text string containing a directory
1512% name.
1513%
1514% o pattern: Specifies a pointer to a text string containing a pattern.
1515%
1516% o number_entries: This integer returns the number of filenames in the
1517% list.
1518%
1519*/
1520
1521#if defined(__cplusplus) || defined(c_plusplus)
1522extern "C" {
1523#endif
1524
1525static int FileCompare(const void *x,const void *y)
1526{
1527 register const char
1528 **p,
1529 **q;
1530
1531 p=(const char **) x;
1532 q=(const char **) y;
1533 return(LocaleCompare(*p,*q));
1534}
1535
1536#if defined(__cplusplus) || defined(c_plusplus)
1537}
1538#endif
1539
1540static inline int MagickReadDirectory(DIR *directory,struct dirent *entry,
1541 struct dirent **result)
1542{
1543#if defined(MAGICKCORE_HAVE_READDIR_R)
1544 return(readdir_r(directory,entry,result));
1545#else
1546 (void) entry;
1547 errno=0;
1548 *result=readdir(directory);
1549 return(errno);
1550#endif
1551}
1552
cristyd1dd6e42011-09-04 01:46:08 +00001553MagickPrivate char **ListFiles(const char *directory,const char *pattern,
cristybb503372010-05-27 20:51:26 +00001554 size_t *number_entries)
cristy3ed852e2009-09-05 21:47:34 +00001555{
1556 char
1557 **filelist;
1558
1559 DIR
1560 *current_directory;
1561
1562 struct dirent
1563 *buffer,
1564 *entry;
1565
cristybb503372010-05-27 20:51:26 +00001566 size_t
cristy3ed852e2009-09-05 21:47:34 +00001567 max_entries;
1568
1569 /*
1570 Open directory.
1571 */
1572 assert(directory != (const char *) NULL);
1573 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",directory);
1574 assert(pattern != (const char *) NULL);
cristybb503372010-05-27 20:51:26 +00001575 assert(number_entries != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001576 *number_entries=0;
1577 current_directory=opendir(directory);
1578 if (current_directory == (DIR *) NULL)
1579 return((char **) NULL);
1580 /*
1581 Allocate filelist.
1582 */
1583 max_entries=2048;
1584 filelist=(char **) AcquireQuantumMemory((size_t) max_entries,
1585 sizeof(*filelist));
1586 if (filelist == (char **) NULL)
1587 {
1588 (void) closedir(current_directory);
1589 return((char **) NULL);
1590 }
1591 /*
1592 Save the current and change to the new directory.
1593 */
cristy73bd4a52010-10-05 11:24:23 +00001594 buffer=(struct dirent *) AcquireMagickMemory(sizeof(*buffer)+
cristy0be53ea2010-06-23 19:12:05 +00001595 FILENAME_MAX+1);
cristy3ed852e2009-09-05 21:47:34 +00001596 if (buffer == (struct dirent *) NULL)
1597 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1598 while ((MagickReadDirectory(current_directory,buffer,&entry) == 0) &&
1599 (entry != (struct dirent *) NULL))
1600 {
1601 if (*entry->d_name == '.')
1602 continue;
1603 if ((IsPathDirectory(entry->d_name) > 0) ||
cristy0157aea2010-04-24 21:12:18 +00001604#if defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +00001605 (GlobExpression(entry->d_name,pattern,MagickTrue) != MagickFalse))
1606#else
1607 (GlobExpression(entry->d_name,pattern,MagickFalse) != MagickFalse))
1608#endif
1609 {
1610 if (*number_entries >= max_entries)
1611 {
1612 /*
1613 Extend the file list.
1614 */
1615 max_entries<<=1;
1616 filelist=(char **) ResizeQuantumMemory(filelist,(size_t)
1617 max_entries,sizeof(*filelist));
1618 if (filelist == (char **) NULL)
1619 break;
1620 }
1621#if defined(vms)
1622 {
1623 register char
1624 *p;
1625
1626 p=strchr(entry->d_name,';');
1627 if (p)
1628 *p='\0';
1629 if (*number_entries > 0)
1630 if (LocaleCompare(entry->d_name,filelist[*number_entries-1]) == 0)
1631 continue;
1632 }
1633#endif
1634 filelist[*number_entries]=(char *) AcquireString(entry->d_name);
cristy3ed852e2009-09-05 21:47:34 +00001635 (*number_entries)++;
1636 }
1637 }
1638 buffer=(struct dirent *) RelinquishMagickMemory(buffer);
1639 (void) closedir(current_directory);
1640 if (filelist == (char **) NULL)
1641 return((char **) NULL);
1642 /*
1643 Sort filelist in ascending order.
1644 */
1645 qsort((void *) filelist,(size_t) *number_entries,sizeof(*filelist),
1646 FileCompare);
1647 return(filelist);
1648}
1649
1650/*
1651%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1652% %
1653% %
1654% %
cristya21afde2010-07-02 00:45:40 +00001655% M a g i c k D e l a y %
1656% %
1657% %
1658% %
1659%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1660%
1661% MagickDelay() suspends program execution for the number of milliseconds
1662% specified.
1663%
1664% The format of the Delay method is:
1665%
1666% void MagickDelay(const MagickSizeType milliseconds)
1667%
1668% A description of each parameter follows:
1669%
1670% o milliseconds: Specifies the number of milliseconds to delay before
1671% returning.
1672%
1673*/
cristyd1dd6e42011-09-04 01:46:08 +00001674MagickPrivate void MagickDelay(const MagickSizeType milliseconds)
cristya21afde2010-07-02 00:45:40 +00001675{
1676 if (milliseconds == 0)
1677 return;
1678#if defined(MAGICKCORE_HAVE_NANOSLEEP)
1679 {
1680 struct timespec
1681 timer;
1682
1683 timer.tv_sec=(time_t) (milliseconds/1000);
1684 timer.tv_nsec=(milliseconds % 1000)*1000*1000;
1685 (void) nanosleep(&timer,(struct timespec *) NULL);
1686 }
1687#elif defined(MAGICKCORE_HAVE_USLEEP)
1688 usleep(1000*milliseconds);
1689#elif defined(MAGICKCORE_HAVE_SELECT)
1690 {
1691 struct timeval
1692 timer;
1693
1694 timer.tv_sec=(long) milliseconds/1000;
1695 timer.tv_usec=(long) (milliseconds % 1000)*1000;
1696 (void) select(0,(XFD_SET *) NULL,(XFD_SET *) NULL,(XFD_SET *) NULL,&timer);
1697 }
1698#elif defined(MAGICKCORE_HAVE_POLL)
1699 (void) poll((struct pollfd *) NULL,0,(int) milliseconds);
1700#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
1701 Sleep((long) milliseconds);
1702#elif defined(vms)
1703 {
1704 float
1705 timer;
1706
1707 timer=milliseconds/1000.0;
1708 lib$wait(&timer);
1709 }
1710#elif defined(__BEOS__)
1711 snooze(1000*milliseconds);
1712#else
1713# error "Time delay method not defined."
1714#endif
1715}
1716
1717/*
1718%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1719% %
1720% %
1721% %
cristy3ed852e2009-09-05 21:47:34 +00001722% M u l t i l i n e C e n s u s %
1723% %
1724% %
1725% %
1726%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1727%
1728% MultilineCensus() returns the number of lines within a label. A line is
1729% represented by a \n character.
1730%
1731% The format of the MultilineCenus method is:
1732%
cristybb503372010-05-27 20:51:26 +00001733% size_t MultilineCensus(const char *label)
cristy3ed852e2009-09-05 21:47:34 +00001734%
1735% A description of each parameter follows.
1736%
1737% o label: This character string is the label.
1738%
cristy3ed852e2009-09-05 21:47:34 +00001739*/
cristybb503372010-05-27 20:51:26 +00001740MagickExport size_t MultilineCensus(const char *label)
cristy3ed852e2009-09-05 21:47:34 +00001741{
cristybb503372010-05-27 20:51:26 +00001742 size_t
cristy3ed852e2009-09-05 21:47:34 +00001743 number_lines;
1744
1745 /*
1746 Determine the number of lines within this label.
1747 */
1748 if (label == (char *) NULL)
1749 return(0);
1750 for (number_lines=1; *label != '\0'; label++)
1751 if (*label == '\n')
1752 number_lines++;
1753 return(number_lines);
1754}
1755
1756/*
1757%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1758% %
1759% %
1760% %
cristy3ed852e2009-09-05 21:47:34 +00001761% S y s t e m C o m m a n d %
1762% %
1763% %
1764% %
1765%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1766%
1767% SystemCommand() executes the specified command and waits until it
1768% terminates. The returned value is the exit status of the command.
1769%
1770% The format of the SystemCommand method is:
1771%
cristy6de4bc22010-01-12 17:10:35 +00001772% int SystemCommand(const MagickBooleanType asynchronous,
1773% const MagickBooleanType verbose,const char *command,
cristyb32b90a2009-09-07 21:45:48 +00001774% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001775%
1776% A description of each parameter follows:
1777%
cristy6de4bc22010-01-12 17:10:35 +00001778% o asynchronous: a value other than 0 executes the parent program
1779% concurrently with the new child process.
1780%
cristyb32b90a2009-09-07 21:45:48 +00001781% o verbose: a value other than 0 prints the executed command before it is
cristy3ed852e2009-09-05 21:47:34 +00001782% invoked.
1783%
cristyb32b90a2009-09-07 21:45:48 +00001784% o command: this string is the command to execute.
1785%
1786% o exception: return any errors here.
cristy3ed852e2009-09-05 21:47:34 +00001787%
1788*/
cristy6de4bc22010-01-12 17:10:35 +00001789MagickExport int SystemCommand(const MagickBooleanType asynchronous,
1790 const MagickBooleanType verbose,const char *command,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001791{
cristyb32b90a2009-09-07 21:45:48 +00001792 char
cristy6de4bc22010-01-12 17:10:35 +00001793 **arguments,
1794 *shell_command;
cristyb32b90a2009-09-07 21:45:48 +00001795
cristy3ed852e2009-09-05 21:47:34 +00001796 int
cristyb32b90a2009-09-07 21:45:48 +00001797 number_arguments,
cristy3ed852e2009-09-05 21:47:34 +00001798 status;
1799
cristyb32b90a2009-09-07 21:45:48 +00001800 PolicyDomain
1801 domain;
1802
1803 PolicyRights
1804 rights;
1805
cristybb503372010-05-27 20:51:26 +00001806 register ssize_t
cristyb32b90a2009-09-07 21:45:48 +00001807 i;
1808
1809 status=(-1);
1810 arguments=StringToArgv(command,&number_arguments);
1811 if (arguments == (char **) NULL)
1812 return(status);
cristyb32b90a2009-09-07 21:45:48 +00001813 rights=ExecutePolicyRights;
cristy6de4bc22010-01-12 17:10:35 +00001814 domain=DelegatePolicyDomain;
cristyb32b90a2009-09-07 21:45:48 +00001815 if (IsRightsAuthorized(domain,rights,arguments[1]) == MagickFalse)
1816 {
cristya9197f62010-01-12 02:23:34 +00001817 errno=EPERM;
cristyb32b90a2009-09-07 21:45:48 +00001818 (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
anthonye5b39652012-04-21 05:37:29 +00001819 "NotAuthorized","'%s'",arguments[1]);
cristycee97112010-05-28 00:44:52 +00001820 for (i=0; i < (ssize_t) number_arguments; i++)
cristyb32b90a2009-09-07 21:45:48 +00001821 arguments[i]=DestroyString(arguments[i]);
1822 arguments=(char **) RelinquishMagickMemory(arguments);
1823 return(-1);
1824 }
cristy3ed852e2009-09-05 21:47:34 +00001825 if (verbose != MagickFalse)
1826 {
cristyb51dff52011-05-19 16:55:47 +00001827 (void) FormatLocaleFile(stderr,"%s\n",command);
cristy3ed852e2009-09-05 21:47:34 +00001828 (void) fflush(stderr);
1829 }
cristy6de4bc22010-01-12 17:10:35 +00001830 shell_command=(char *) command;
1831 if (asynchronous != MagickFalse)
1832 {
1833 shell_command=AcquireString(command);
1834 (void) ConcatenateMagickString(shell_command,"&",MaxTextExtent);
1835 }
cristy3ed852e2009-09-05 21:47:34 +00001836#if defined(MAGICKCORE_POSIX_SUPPORT)
cristya9197f62010-01-12 02:23:34 +00001837#if !defined(MAGICKCORE_HAVE_EXECVP)
cristy6de4bc22010-01-12 17:10:35 +00001838 status=system(shell_command);
cristy3ed852e2009-09-05 21:47:34 +00001839#else
cristye21dc962012-01-12 17:22:31 +00001840 if ((asynchronous != MagickFalse) ||
cristya4560912012-01-14 20:28:03 +00001841 (strpbrk(shell_command,"&;<>|") != (char *) NULL))
cristy6de4bc22010-01-12 17:10:35 +00001842 status=system(shell_command);
cristy3ed852e2009-09-05 21:47:34 +00001843 else
1844 {
cristyb32b90a2009-09-07 21:45:48 +00001845 pid_t
1846 child_pid;
cristy3ed852e2009-09-05 21:47:34 +00001847
cristyb32b90a2009-09-07 21:45:48 +00001848 /*
1849 Call application directly rather than from a shell.
1850 */
cristye42f6582012-02-11 17:59:50 +00001851 child_pid=(pid_t) fork();
cristyb32b90a2009-09-07 21:45:48 +00001852 if (child_pid == (pid_t) -1)
cristy3ed852e2009-09-05 21:47:34 +00001853 status=system(command);
1854 else
cristyb32b90a2009-09-07 21:45:48 +00001855 if (child_pid == 0)
1856 {
1857 status=execvp(arguments[1],arguments+1);
1858 _exit(1);
1859 }
1860 else
1861 {
1862 int
1863 child_status;
cristy3ed852e2009-09-05 21:47:34 +00001864
cristyb32b90a2009-09-07 21:45:48 +00001865 pid_t
1866 pid;
cristy3ed852e2009-09-05 21:47:34 +00001867
cristyb32b90a2009-09-07 21:45:48 +00001868 child_status=0;
cristye42f6582012-02-11 17:59:50 +00001869 pid=(pid_t) waitpid(child_pid,&child_status,0);
cristyb32b90a2009-09-07 21:45:48 +00001870 if (pid == -1)
1871 status=(-1);
cristy3ed852e2009-09-05 21:47:34 +00001872 else
1873 {
cristyb32b90a2009-09-07 21:45:48 +00001874 if (WIFEXITED(child_status) != 0)
1875 status=WEXITSTATUS(child_status);
cristy3ed852e2009-09-05 21:47:34 +00001876 else
cristyb32b90a2009-09-07 21:45:48 +00001877 if (WIFSIGNALED(child_status))
1878 status=(-1);
cristy3ed852e2009-09-05 21:47:34 +00001879 }
cristyb32b90a2009-09-07 21:45:48 +00001880 }
cristy3ed852e2009-09-05 21:47:34 +00001881 }
1882#endif
cristy0157aea2010-04-24 21:12:18 +00001883#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
cristyea7bce92011-12-12 00:24:44 +00001884 status=NTSystemCommand(shell_command);
cristy3ed852e2009-09-05 21:47:34 +00001885#elif defined(macintosh)
cristy6de4bc22010-01-12 17:10:35 +00001886 status=MACSystemCommand(shell_command);
cristy3ed852e2009-09-05 21:47:34 +00001887#elif defined(vms)
cristy6de4bc22010-01-12 17:10:35 +00001888 status=system(shell_command);
cristy3ed852e2009-09-05 21:47:34 +00001889#else
1890# error No suitable system() method.
1891#endif
1892 if (status < 0)
cristy6de4bc22010-01-12 17:10:35 +00001893 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
anthonye5b39652012-04-21 05:37:29 +00001894 "'%s' (%d)",command,status);
cristy6de4bc22010-01-12 17:10:35 +00001895 if (shell_command != command)
1896 shell_command=DestroyString(shell_command);
cristycee97112010-05-28 00:44:52 +00001897 for (i=0; i < (ssize_t) number_arguments; i++)
cristyb32b90a2009-09-07 21:45:48 +00001898 arguments[i]=DestroyString(arguments[i]);
1899 arguments=(char **) RelinquishMagickMemory(arguments);
cristy3ed852e2009-09-05 21:47:34 +00001900 return(status);
1901}