utility.c revision 4bb3ba9fd39af54bcb6f08b3e5a170eccdfb6fa9
1/*
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%                                  Cristy                                     %
17%                              January 1993                                   %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
21%  dedicated to making software imaging solutions freely available.           %
22%                                                                             %
23%  You may not use this file except in compliance with the License.  You may  %
24%  obtain a copy of the License at                                            %
25%                                                                             %
26%    http://www.imagemagick.org/script/license.php                            %
27%                                                                             %
28%  Unless required by applicable law or agreed to in writing, software        %
29%  distributed under the License is distributed on an "AS IS" BASIS,          %
30%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31%  See the License for the specific language governing permissions and        %
32%  limitations under the License.                                             %
33%                                                                             %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37*/
38
39/*
40  Include declarations.
41*/
42#include "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/image-private.h"
50#include "MagickCore/list.h"
51#include "MagickCore/log.h"
52#include "MagickCore/magick-private.h"
53#include "MagickCore/memory_.h"
54#include "MagickCore/nt-base-private.h"
55#include "MagickCore/option.h"
56#include "MagickCore/policy.h"
57#include "MagickCore/random_.h"
58#include "MagickCore/registry.h"
59#include "MagickCore/resource_.h"
60#include "MagickCore/semaphore.h"
61#include "MagickCore/signature-private.h"
62#include "MagickCore/statistic.h"
63#include "MagickCore/string_.h"
64#include "MagickCore/string-private.h"
65#include "MagickCore/token.h"
66#include "MagickCore/token-private.h"
67#include "MagickCore/utility.h"
68#include "MagickCore/utility-private.h"
69#if defined(MAGICKCORE_HAVE_PROCESS_H)
70#include <process.h>
71#endif
72#if defined(MAGICKCORE_HAVE_MACH_O_DYLD_H)
73#include <mach-o/dyld.h>
74#endif
75
76/*
77  Static declarations.
78*/
79static const char
80  Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
81
82/*
83  Forward declaration.
84*/
85static int
86  IsPathDirectory(const char *);
87
88/*
89%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
90%                                                                             %
91%                                                                             %
92%                                                                             %
93%   A c q u i r e U n i q u e F i l e n a m e                                 %
94%                                                                             %
95%                                                                             %
96%                                                                             %
97%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
98%
99%  AcquireUniqueFilename() replaces the contents of path by a unique path name.
100%
101%  The format of the AcquireUniqueFilename method is:
102%
103%      MagickBooleanType AcquireUniqueFilename(char *path)
104%
105%  A description of each parameter follows.
106%
107%   o  path:  Specifies a pointer to an array of characters.  The unique path
108%      name is returned in this array.
109%
110*/
111MagickExport MagickBooleanType AcquireUniqueFilename(char *path)
112{
113  int
114    file;
115
116  file=AcquireUniqueFileResource(path);
117  if (file == -1)
118    return(MagickFalse);
119  file=close(file)-1;
120  return(MagickTrue);
121}
122
123/*
124%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
125%                                                                             %
126%                                                                             %
127%                                                                             %
128%   A c q u i r e U n i q u e S ym b o l i c L i n k                          %
129%                                                                             %
130%                                                                             %
131%                                                                             %
132%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
133%
134%  AcquireUniqueSymbolicLink() creates a unique symbolic link to the specified
135%  source path and returns MagickTrue on success otherwise MagickFalse.  If the
136%  symlink() method fails or is not available, a unique file name is generated
137%  and the source file copied to it.  When you are finished with the file, use
138%  RelinquishUniqueFilename() to destroy it.
139%
140%  The format of the AcquireUniqueSymbolicLink method is:
141%
142%      MagickBooleanType AcquireUniqueSymbolicLink(const char *source,
143%        char destination)
144%
145%  A description of each parameter follows.
146%
147%   o  source:  the source path.
148%
149%   o  destination:  the destination path.
150%
151*/
152
153MagickExport MagickBooleanType AcquireUniqueSymbolicLink(const char *source,
154  char *destination)
155{
156  int
157    destination_file,
158    source_file;
159
160  size_t
161    length,
162    quantum;
163
164  ssize_t
165    count;
166
167  struct stat
168    attributes;
169
170  unsigned char
171    *buffer;
172
173  assert(source != (const char *) NULL);
174  assert(destination != (char *) NULL);
175#if defined(MAGICKCORE_HAVE_SYMLINK)
176  (void) AcquireUniqueFilename(destination);
177  (void) RelinquishUniqueFileResource(destination);
178  if (*source == *DirectorySeparator)
179    {
180      if (symlink(source,destination) == 0)
181        return(MagickTrue);
182    }
183  else
184    {
185      char
186        path[MagickPathExtent];
187
188      *path='\0';
189      if (getcwd(path,MagickPathExtent) == (char *) NULL)
190        return(MagickFalse);
191      (void) ConcatenateMagickString(path,DirectorySeparator,MagickPathExtent);
192      (void) ConcatenateMagickString(path,source,MagickPathExtent);
193      if (symlink(path,destination) == 0)
194        return(MagickTrue);
195    }
196#endif
197  destination_file=AcquireUniqueFileResource(destination);
198  if (destination_file == -1)
199    return(MagickFalse);
200  source_file=open_utf8(source,O_RDONLY | O_BINARY,0);
201  if (source_file == -1)
202    {
203      (void) close(destination_file);
204      (void) RelinquishUniqueFileResource(destination);
205      return(MagickFalse);
206    }
207  quantum=(size_t) MagickMaxBufferExtent;
208  if ((fstat(source_file,&attributes) == 0) && (attributes.st_size > 0))
209    quantum=(size_t) MagickMin(attributes.st_size,MagickMaxBufferExtent);
210  buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
211  if (buffer == (unsigned char *) NULL)
212    {
213      (void) close(source_file);
214      (void) close(destination_file);
215      (void) RelinquishUniqueFileResource(destination);
216      return(MagickFalse);
217    }
218  for (length=0; ; )
219  {
220    count=(ssize_t) read(source_file,buffer,quantum);
221    if (count <= 0)
222      break;
223    length=(size_t) count;
224    count=(ssize_t) write(destination_file,buffer,length);
225    if ((size_t) count != length)
226      {
227        (void) close(destination_file);
228        (void) close(source_file);
229        buffer=(unsigned char *) RelinquishMagickMemory(buffer);
230        (void) RelinquishUniqueFileResource(destination);
231        return(MagickFalse);
232      }
233  }
234  (void) close(destination_file);
235  (void) close(source_file);
236  buffer=(unsigned char *) RelinquishMagickMemory(buffer);
237  return(MagickTrue);
238}
239
240/*
241%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
242%                                                                             %
243%                                                                             %
244%                                                                             %
245%  A p p e n d I m a g e F o r m a t                                          %
246%                                                                             %
247%                                                                             %
248%                                                                             %
249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
250%
251%  AppendImageFormat() appends the image format type to the filename.  If an
252%  extension to the file already exists, it is first removed.
253%
254%  The format of the AppendImageFormat method is:
255%
256%      void AppendImageFormat(const char *format,char *filename)
257%
258%  A description of each parameter follows.
259%
260%   o  format:  Specifies a pointer to an array of characters.  This the
261%      format of the image.
262%
263%   o  filename:  Specifies a pointer to an array of characters.  The unique
264%      file name is returned in this array.
265%
266*/
267MagickExport void AppendImageFormat(const char *format,char *filename)
268{
269  char
270    extension[MagickPathExtent],
271    root[MagickPathExtent];
272
273  assert(format != (char *) NULL);
274  assert(filename != (char *) NULL);
275  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
276  if ((*format == '\0') || (*filename == '\0'))
277    return;
278  if (LocaleCompare(filename,"-") == 0)
279    {
280      char
281        message[MagickPathExtent];
282
283      (void) FormatLocaleString(message,MagickPathExtent,"%s:%s",format,
284        filename);
285      (void) CopyMagickString(filename,message,MagickPathExtent);
286      return;
287    }
288  GetPathComponent(filename,ExtensionPath,extension);
289  if ((LocaleCompare(extension,"Z") == 0) ||
290      (LocaleCompare(extension,"bz2") == 0) ||
291      (LocaleCompare(extension,"gz") == 0) ||
292      (LocaleCompare(extension,"wmz") == 0) ||
293      (LocaleCompare(extension,"svgz") == 0))
294    {
295      GetPathComponent(filename,RootPath,root);
296      (void) CopyMagickString(filename,root,MagickPathExtent);
297      GetPathComponent(filename,RootPath,root);
298      (void) FormatLocaleString(filename,MagickPathExtent,"%s.%s.%s",root,
299        format,extension);
300      return;
301    }
302  GetPathComponent(filename,RootPath,root);
303  (void) FormatLocaleString(filename,MagickPathExtent,"%s.%s",root,format);
304}
305
306/*
307%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
308%                                                                             %
309%                                                                             %
310%                                                                             %
311%   B a s e 6 4 D e c o d e                                                   %
312%                                                                             %
313%                                                                             %
314%                                                                             %
315%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
316%
317%  Base64Decode() decodes Base64-encoded text and returns its binary
318%  equivalent.  NULL is returned if the text is not valid Base64 data, or a
319%  memory allocation failure occurs.
320%
321%  The format of the Base64Decode method is:
322%
323%      unsigned char *Base64Decode(const char *source,length_t *length)
324%
325%  A description of each parameter follows:
326%
327%    o source:  A pointer to a Base64-encoded string.
328%
329%    o length: the number of bytes decoded.
330%
331*/
332MagickExport unsigned char *Base64Decode(const char *source,size_t *length)
333{
334  int
335    state;
336
337  register const char
338    *p,
339    *q;
340
341  register size_t
342    i;
343
344  unsigned char
345    *decode;
346
347  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
348  assert(source != (char *) NULL);
349  assert(length != (size_t *) NULL);
350  *length=0;
351  decode=(unsigned char *) AcquireQuantumMemory((strlen(source)+3)/4,
352    3*sizeof(*decode));
353  if (decode == (unsigned char *) NULL)
354    return((unsigned char *) NULL);
355  i=0;
356  state=0;
357  for (p=source; *p != '\0'; p++)
358  {
359    if (isspace((int) ((unsigned char) *p)) != 0)
360      continue;
361    if (*p == '=')
362      break;
363    q=strchr(Base64,*p);
364    if (q == (char *) NULL)
365      {
366        decode=(unsigned char *) RelinquishMagickMemory(decode);
367        return((unsigned char *) NULL);  /* non-Base64 character */
368      }
369    switch (state)
370    {
371      case 0:
372      {
373        decode[i]=(q-Base64) << 2;
374        state++;
375        break;
376      }
377      case 1:
378      {
379        decode[i++]|=(q-Base64) >> 4;
380        decode[i]=((q-Base64) & 0x0f) << 4;
381        state++;
382        break;
383      }
384      case 2:
385      {
386        decode[i++]|=(q-Base64) >> 2;
387        decode[i]=((q-Base64) & 0x03) << 6;
388        state++;
389        break;
390      }
391      case 3:
392      {
393        decode[i++]|=(q-Base64);
394        state=0;
395        break;
396      }
397    }
398  }
399  /*
400    Verify Base-64 string has proper terminal characters.
401  */
402  if (*p != '=')
403    {
404      if (state != 0)
405        {
406          decode=(unsigned char *) RelinquishMagickMemory(decode);
407          return((unsigned char *) NULL);
408        }
409    }
410  else
411    {
412      p++;
413      switch (state)
414      {
415        case 0:
416        case 1:
417        {
418          /*
419            Unrecognized '=' character.
420          */
421          decode=(unsigned char *) RelinquishMagickMemory(decode);
422          return((unsigned char *) NULL);
423        }
424        case 2:
425        {
426          for ( ; *p != '\0'; p++)
427            if (isspace((int) ((unsigned char) *p)) == 0)
428              break;
429          if (*p != '=')
430            {
431              decode=(unsigned char *) RelinquishMagickMemory(decode);
432              return((unsigned char *) NULL);
433            }
434          p++;
435        }
436        case 3:
437        {
438          for ( ; *p != '\0'; p++)
439            if (isspace((int) ((unsigned char) *p)) == 0)
440              {
441                decode=(unsigned char *) RelinquishMagickMemory(decode);
442                return((unsigned char *) NULL);
443              }
444          if ((int) decode[i] != 0)
445            {
446              decode=(unsigned char *) RelinquishMagickMemory(decode);
447              return((unsigned char *) NULL);
448            }
449          break;
450        }
451      }
452    }
453  *length=i;
454  return(decode);
455}
456
457/*
458%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
459%                                                                             %
460%                                                                             %
461%                                                                             %
462%   B a s e 6 4 E n c o d e                                                   %
463%                                                                             %
464%                                                                             %
465%                                                                             %
466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
467%
468%  Base64Encode() encodes arbitrary binary data to Base64 encoded format as
469%  described by the "Base64 Content-Transfer-Encoding" section of RFC 2045 and
470%  returns the result as a null-terminated ASCII string.  NULL is returned if
471%  a memory allocation failure occurs.
472%
473%  The format of the Base64Encode method is:
474%
475%      char *Base64Encode(const unsigned char *blob,const size_t blob_length,
476%        size_t *encode_length)
477%
478%  A description of each parameter follows:
479%
480%    o blob:  A pointer to binary data to encode.
481%
482%    o blob_length: the number of bytes to encode.
483%
484%    o encode_length:  The number of bytes encoded.
485%
486*/
487MagickExport char *Base64Encode(const unsigned char *blob,
488  const size_t blob_length,size_t *encode_length)
489{
490  char
491    *encode;
492
493  register const unsigned char
494    *p;
495
496  register size_t
497    i;
498
499  size_t
500    remainder;
501
502  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
503  assert(blob != (const unsigned char *) NULL);
504  assert(blob_length != 0);
505  assert(encode_length != (size_t *) NULL);
506  *encode_length=0;
507  encode=(char *) AcquireQuantumMemory(blob_length/3+4,4*sizeof(*encode));
508  if (encode == (char *) NULL)
509    return((char *) NULL);
510  i=0;
511  for (p=blob; p < (blob+blob_length-2); p+=3)
512  {
513    encode[i++]=Base64[(int) (*p >> 2)];
514    encode[i++]=Base64[(int) (((*p & 0x03) << 4)+(*(p+1) >> 4))];
515    encode[i++]=Base64[(int) (((*(p+1) & 0x0f) << 2)+(*(p+2) >> 6))];
516    encode[i++]=Base64[(int) (*(p+2) & 0x3f)];
517  }
518  remainder=blob_length % 3;
519  if (remainder != 0)
520    {
521      ssize_t
522        j;
523
524      unsigned char
525        code[3];
526
527      code[0]='\0';
528      code[1]='\0';
529      code[2]='\0';
530      for (j=0; j < (ssize_t) remainder; j++)
531        code[j]=(*p++);
532      encode[i++]=Base64[(int) (code[0] >> 2)];
533      encode[i++]=Base64[(int) (((code[0] & 0x03) << 4)+(code[1] >> 4))];
534      if (remainder == 1)
535        encode[i++]='=';
536      else
537        encode[i++]=Base64[(int) (((code[1] & 0x0f) << 2)+(code[2] >> 6))];
538      encode[i++]='=';
539    }
540  *encode_length=i;
541  encode[i++]='\0';
542  return(encode);
543}
544
545/*
546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
547%                                                                             %
548%                                                                             %
549%                                                                             %
550%   C h o p P a t h C o m p o n e n t s                                       %
551%                                                                             %
552%                                                                             %
553%                                                                             %
554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
555%
556%  ChopPathComponents() removes the number of specified file components from a
557%  path.
558%
559%  The format of the ChopPathComponents method is:
560%
561%      ChopPathComponents(char *path,size_t components)
562%
563%  A description of each parameter follows:
564%
565%    o path:  The path.
566%
567%    o components:  The number of components to chop.
568%
569*/
570MagickPrivate void ChopPathComponents(char *path,const size_t components)
571{
572  register ssize_t
573    i;
574
575  for (i=0; i < (ssize_t) components; i++)
576    GetPathComponent(path,HeadPath,path);
577}
578
579/*
580%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
581%                                                                             %
582%                                                                             %
583%                                                                             %
584%   E x p a n d F i l e n a m e                                               %
585%                                                                             %
586%                                                                             %
587%                                                                             %
588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
589%
590%  ExpandFilename() expands '~' in a path.
591%
592%  The format of the ExpandFilename function is:
593%
594%      ExpandFilename(char *path)
595%
596%  A description of each parameter follows:
597%
598%    o path: Specifies a pointer to a character array that contains the
599%      path.
600%
601*/
602MagickPrivate void ExpandFilename(char *path)
603{
604  char
605    expand_path[MagickPathExtent];
606
607  if (path == (char *) NULL)
608    return;
609  if (*path != '~')
610    return;
611  (void) CopyMagickString(expand_path,path,MagickPathExtent);
612  if ((*(path+1) == *DirectorySeparator) || (*(path+1) == '\0'))
613    {
614      char
615        *home;
616
617      /*
618        Substitute ~ with $HOME.
619      */
620      (void) CopyMagickString(expand_path,".",MagickPathExtent);
621      (void) ConcatenateMagickString(expand_path,path+1,MagickPathExtent);
622      home=GetEnvironmentValue("HOME");
623      if (home == (char *) NULL)
624        home=GetEnvironmentValue("USERPROFILE");
625      if (home != (char *) NULL)
626        {
627          (void) CopyMagickString(expand_path,home,MagickPathExtent);
628          (void) ConcatenateMagickString(expand_path,path+1,MagickPathExtent);
629          home=DestroyString(home);
630        }
631    }
632  else
633    {
634#if defined(MAGICKCORE_POSIX_SUPPORT) && !defined(__OS2__)
635      char
636        username[MagickPathExtent];
637
638      register char
639        *p;
640
641      struct passwd
642        *entry;
643
644      /*
645        Substitute ~ with home directory from password file.
646      */
647      (void) CopyMagickString(username,path+1,MagickPathExtent);
648      p=strchr(username,'/');
649      if (p != (char *) NULL)
650        *p='\0';
651      entry=getpwnam(username);
652      if (entry == (struct passwd *) NULL)
653        return;
654      (void) CopyMagickString(expand_path,entry->pw_dir,MagickPathExtent);
655      if (p != (char *) NULL)
656        {
657          (void) ConcatenateMagickString(expand_path,"/",MagickPathExtent);
658          (void) ConcatenateMagickString(expand_path,p+1,MagickPathExtent);
659        }
660#endif
661    }
662  (void) CopyMagickString(path,expand_path,MagickPathExtent);
663}
664
665/*
666%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
667%                                                                             %
668%                                                                             %
669%                                                                             %
670%   E x p a n d F i l e n a m e s                                             %
671%                                                                             %
672%                                                                             %
673%                                                                             %
674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
675%
676%  ExpandFilenames() checks each argument of the given argument array, and
677%  expands it if they have a wildcard character.
678%
679%  Any coder prefix (EG: 'coder:filename') or read modifier postfix (EG:
680%  'filename[...]') are ignored during the file the expansion, but will be
681%  included in the final argument.  If no filename matching the meta-character
682%  'glob' is found the original argument is returned.
683%
684%  For example, an argument of '*.gif[20x20]' will be replaced by the list
685%    'abc.gif[20x20]',  'foobar.gif[20x20]',  'xyzzy.gif[20x20]'
686%  if such filenames exist, (in the current directory in this case).
687%
688%  Meta-characters handled...
689%     @    read a list of filenames (no further expansion performed)
690%     ~    At start of filename expands to HOME environemtn variable
691%     *    matches any string including an empty string
692%     ?    matches by any single character
693%
694%  WARNING: filenames starting with '.' (hidden files in a UNIX file system)
695%  will never be expanded.  Attempting to epand '.*' will produce no change.
696%
697%  Expansion is ignored for coders "label:" "caption:" "pango:" and "vid:".
698%  Which provide their own '@' meta-character handling.
699%
700%  You can see the results of the expansion using "Configure" log events.
701%
702%  The returned list should be freed using  DestroyStringList().
703%
704%  However the strings in the original pointed to argv are not
705%  freed  (TO BE CHECKED).  So a copy of the original pointer (and count)
706%  should be kept separate if they need to be freed later.
707%
708%  The format of the ExpandFilenames function is:
709%
710%      status=ExpandFilenames(int *number_arguments,char ***arguments)
711%
712%  A description of each parameter follows:
713%
714%    o number_arguments: Specifies a pointer to an integer describing the
715%      number of elements in the argument vector.
716%
717%    o arguments: Specifies a pointer to a text array containing the command
718%      line arguments.
719%
720*/
721MagickExport MagickBooleanType ExpandFilenames(int *number_arguments,
722  char ***arguments)
723{
724  char
725    home_directory[MagickPathExtent],
726    **vector;
727
728  register ssize_t
729    i,
730    j;
731
732  size_t
733    number_files;
734
735  ssize_t
736    count,
737    parameters;
738
739  /*
740    Allocate argument vector.
741  */
742  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
743  assert(number_arguments != (int *) NULL);
744  assert(arguments != (char ***) NULL);
745  vector=(char **) AcquireQuantumMemory((size_t) (*number_arguments+1),
746    sizeof(*vector));
747  if (vector == (char **) NULL)
748    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
749  /*
750    Expand any wildcard filenames.
751  */
752  *home_directory='\0';
753  count=0;
754  for (i=0; i < (ssize_t) *number_arguments; i++)
755  {
756    char
757      **filelist,
758      filename[MagickPathExtent],
759      magick[MagickPathExtent],
760      *option,
761      path[MagickPathExtent],
762      subimage[MagickPathExtent];
763
764    MagickBooleanType
765      destroy;
766
767    option=(*arguments)[i];
768    *magick='\0';
769    *path='\0';
770    *filename='\0';
771    *subimage='\0';
772    number_files=0;
773    vector[count++]=ConstantString(option);
774    destroy=MagickTrue;
775    parameters=ParseCommandOption(MagickCommandOptions,MagickFalse,option);
776    if (parameters > 0)
777      {
778        /*
779          Do not expand command option parameters.
780        */
781        for (j=0; j < parameters; j++)
782        {
783          i++;
784          if (i == (ssize_t) *number_arguments)
785            break;
786          option=(*arguments)[i];
787          vector[count++]=ConstantString(option);
788        }
789        continue;
790      }
791    if ((*option == '"') || (*option == '\''))
792      continue;
793    GetPathComponent(option,TailPath,filename);
794    GetPathComponent(option,MagickPath,magick);
795    if ((LocaleCompare(magick,"CAPTION") == 0) ||
796        (LocaleCompare(magick,"LABEL") == 0) ||
797        (LocaleCompare(magick,"PANGO") == 0) ||
798        (LocaleCompare(magick,"VID") == 0))
799      continue;
800    if ((IsGlob(filename) == MagickFalse) && (*option != '@'))
801      continue;
802    if (*option != '@')
803      {
804        /*
805          Generate file list from wildcard filename (e.g. *.jpg).
806        */
807        GetPathComponent(option,HeadPath,path);
808        GetPathComponent(option,SubimagePath,subimage);
809        ExpandFilename(path);
810        if (*home_directory == '\0')
811          getcwd_utf8(home_directory,MagickPathExtent-1);
812        filelist=ListFiles(*path == '\0' ? home_directory : path,filename,
813          &number_files);
814      }
815    else
816      {
817        char
818          *files;
819
820        ExceptionInfo
821          *exception;
822
823        int
824          length;
825
826        /*
827          Generate file list from file list (e.g. @filelist.txt).
828        */
829        exception=AcquireExceptionInfo();
830        files=FileToString(option+1,~0UL,exception);
831        exception=DestroyExceptionInfo(exception);
832        if (files == (char *) NULL)
833          continue;
834        filelist=StringToArgv(files,&length);
835        if (filelist == (char **) NULL)
836          continue;
837        files=DestroyString(files);
838        filelist[0]=DestroyString(filelist[0]);
839        for (j=0; j < (ssize_t) (length-1); j++)
840          filelist[j]=filelist[j+1];
841        number_files=(size_t) length-1;
842      }
843    if (filelist == (char **) NULL)
844      continue;
845    for (j=0; j < (ssize_t) number_files; j++)
846      if (IsPathDirectory(filelist[j]) <= 0)
847        break;
848    if (j == (ssize_t) number_files)
849      {
850        for (j=0; j < (ssize_t) number_files; j++)
851          filelist[j]=DestroyString(filelist[j]);
852        filelist=(char **) RelinquishMagickMemory(filelist);
853        continue;
854      }
855    /*
856      Transfer file list to argument vector.
857    */
858    vector=(char **) ResizeQuantumMemory(vector,(size_t) *number_arguments+
859      count+number_files+1,sizeof(*vector));
860    if (vector == (char **) NULL)
861      {
862        for (j=0; j < (ssize_t) number_files; j++)
863          filelist[j]=DestroyString(filelist[j]);
864        filelist=(char **) RelinquishMagickMemory(filelist);
865        return(MagickFalse);
866      }
867    for (j=0; j < (ssize_t) number_files; j++)
868    {
869      option=filelist[j];
870      parameters=ParseCommandOption(MagickCommandOptions,MagickFalse,option);
871      if (parameters > 0)
872        {
873          ssize_t
874            k;
875
876          /*
877            Do not expand command option parameters.
878          */
879          vector[count++]=ConstantString(option);
880          for (k=0; k < parameters; k++)
881          {
882            j++;
883            if (j == (ssize_t) number_files)
884              break;
885            option=filelist[j];
886            vector[count++]=ConstantString(option);
887          }
888          continue;
889        }
890      (void) CopyMagickString(filename,path,MagickPathExtent);
891      if (*path != '\0')
892        (void) ConcatenateMagickString(filename,DirectorySeparator,
893          MagickPathExtent);
894      if (filelist[j] != (char *) NULL)
895        (void) ConcatenateMagickString(filename,filelist[j],MagickPathExtent);
896      filelist[j]=DestroyString(filelist[j]);
897      if (strlen(filename) >= (MagickPathExtent-1))
898        ThrowFatalException(OptionFatalError,"FilenameTruncated");
899      if (IsPathDirectory(filename) <= 0)
900        {
901          char
902            path[MagickPathExtent];
903
904          *path='\0';
905          if (*magick != '\0')
906            {
907              (void) ConcatenateMagickString(path,magick,MagickPathExtent);
908              (void) ConcatenateMagickString(path,":",MagickPathExtent);
909            }
910          (void) ConcatenateMagickString(path,filename,MagickPathExtent);
911          if (*subimage != '\0')
912            {
913              (void) ConcatenateMagickString(path,"[",MagickPathExtent);
914              (void) ConcatenateMagickString(path,subimage,MagickPathExtent);
915              (void) ConcatenateMagickString(path,"]",MagickPathExtent);
916            }
917          if (strlen(path) >= (MagickPathExtent-1))
918            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*/
977MagickPrivate MagickBooleanType GetExecutionPath(char *path,const size_t extent)
978{
979  char
980    *directory;
981
982  *path='\0';
983  directory=getcwd(path,(unsigned long) extent);
984  (void) directory;
985#if defined(MAGICKCORE_HAVE_GETPID) && defined(MAGICKCORE_HAVE_READLINK) && defined(PATH_MAX)
986  {
987    char
988      execution_path[PATH_MAX+1],
989      link_path[MagickPathExtent];
990
991    ssize_t
992      count;
993
994    (void) FormatLocaleString(link_path,MagickPathExtent,"/proc/%.20g/exe",
995      (double) getpid());
996    count=readlink(link_path,execution_path,PATH_MAX);
997    if (count == -1)
998      {
999        (void) FormatLocaleString(link_path,MagickPathExtent,"/proc/%.20g/file",
1000          (double) getpid());
1001        count=readlink(link_path,execution_path,PATH_MAX);
1002      }
1003    if ((count > 0) && (count <= (ssize_t) PATH_MAX))
1004      {
1005        execution_path[count]='\0';
1006        (void) CopyMagickString(path,execution_path,extent);
1007      }
1008  }
1009#endif
1010#if defined(MAGICKCORE_HAVE__NSGETEXECUTABLEPATH)
1011  {
1012    char
1013      executable_path[PATH_MAX << 1],
1014      execution_path[PATH_MAX+1];
1015
1016    uint32_t
1017      length;
1018
1019    length=sizeof(executable_path);
1020    if ((_NSGetExecutablePath(executable_path,&length) == 0) &&
1021        (realpath(executable_path,execution_path) != (char *) NULL))
1022      (void) CopyMagickString(path,execution_path,extent);
1023  }
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
1039#if defined(MAGICKCORE_WINDOWS_SUPPORT)
1040  NTGetExecutionPath(path,extent);
1041#endif
1042#if defined(__GNU__)
1043  {
1044    char
1045      *program_name,
1046      *execution_path;
1047
1048    ssize_t
1049      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
1059        extent=strlen(directory)+strlen(program_name)+2;
1060        program_name=AcquireQuantumMemory(extent,sizeof(*program_name));
1061        if (program_name == (char *) NULL)
1062          program_name=program_invocation_name;
1063        else
1064          count=FormatLocaleString(program_name,extent,"%s/%s",directory,
1065            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
1078#if defined(__OpenBSD__)
1079  {
1080    extern char
1081      *__progname;
1082
1083    (void) CopyMagickString(path,__progname,extent);
1084  }
1085#endif
1086  return(IsPathAccessible(path));
1087}
1088
1089/*
1090%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1091%                                                                             %
1092%                                                                             %
1093%                                                                             %
1094%   G e t M a g i c k P a g e S i z e                                         %
1095%                                                                             %
1096%                                                                             %
1097%                                                                             %
1098%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1099%
1100%  GetMagickPageSize() returns the memory page size.
1101%
1102%  The format of the GetMagickPageSize method is:
1103%
1104%      ssize_t GetMagickPageSize()
1105%
1106*/
1107MagickPrivate ssize_t GetMagickPageSize(void)
1108{
1109  static ssize_t
1110    page_size = -1;
1111
1112  if (page_size > 0)
1113    return(page_size);
1114#if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
1115  page_size=(ssize_t) sysconf(_SC_PAGE_SIZE);
1116#else
1117#if defined(MAGICKCORE_HAVE_GETPAGESIZE)
1118  page_size=(ssize_t) getpagesize();
1119#endif
1120#endif
1121  if (page_size <= 0)
1122    page_size=16384;
1123  return(page_size);
1124}
1125
1126/*
1127%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1128%                                                                             %
1129%                                                                             %
1130%                                                                             %
1131%   G e t P a t h A t t r i b u t e s                                         %
1132%                                                                             %
1133%                                                                             %
1134%                                                                             %
1135%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1136%
1137%  GetPathAttributes() returns attributes (e.g. size of file) about a path.
1138%
1139%  The path of the GetPathAttributes method is:
1140%
1141%      MagickBooleanType GetPathAttributes(const char *path,void *attributes)
1142%
1143%  A description of each parameter follows.
1144%
1145%   o  path: the file path.
1146%
1147%   o  attributes: the path attributes are returned here.
1148%
1149*/
1150MagickExport MagickBooleanType GetPathAttributes(const char *path,
1151  struct stat *attributes)
1152{
1153  MagickBooleanType
1154    status;
1155
1156  if (path == (const char *) NULL)
1157    {
1158      errno=EINVAL;
1159      return(MagickFalse);
1160    }
1161  (void) ResetMagickMemory(attributes,0,sizeof(*attributes));
1162  status=stat_utf8(path,attributes) == 0 ? MagickTrue : MagickFalse;
1163  return(status);
1164}
1165
1166/*
1167%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1168%                                                                             %
1169%                                                                             %
1170%                                                                             %
1171%   G e t P a t h C o m p o n e n t                                           %
1172%                                                                             %
1173%                                                                             %
1174%                                                                             %
1175%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1176%
1177%  GetPathComponent() returns the parent directory name, filename, basename, or
1178%  extension of a file path.
1179%
1180%  The component string pointed to must have at least MagickPathExtent space
1181%  for the results to be stored.
1182%
1183%  The format of the GetPathComponent function is:
1184%
1185%      GetPathComponent(const char *path,PathType type,char *component)
1186%
1187%  A description of each parameter follows:
1188%
1189%    o path: Specifies a pointer to a character array that contains the
1190%      file path.
1191%
1192%    o type: Specififies which file path component to return.
1193%
1194%    o component: the selected file path component is returned here.
1195%
1196*/
1197MagickExport void GetPathComponent(const char *path,PathType type,
1198  char *component)
1199{
1200  char
1201    *q;
1202
1203  register char
1204    *p;
1205
1206  size_t
1207    magick_length,
1208    subimage_offset,
1209    subimage_length;
1210
1211  assert(path != (const char *) NULL);
1212  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",path);
1213  assert(component != (char *) NULL);
1214  if (*path == '\0')
1215    {
1216      *component='\0';
1217      return;
1218    }
1219  (void) CopyMagickString(component,path,MagickPathExtent);
1220  magick_length=0;
1221#if defined(__OS2__)
1222  if (path[1] != ":")
1223#endif
1224  for (p=component; *p != '\0'; p++)
1225  {
1226    if ((*p == '%') && (*(p+1) == '['))
1227      {
1228        /*
1229          Skip over %[...].
1230        */
1231        for (p++; (*p != ']') && (*p != '\0'); p++) ;
1232        if (*p == '\0')
1233          break;
1234      }
1235    if ((*p == ':') && (IsPathDirectory(path) < 0) &&
1236        (IsPathAccessible(path) == MagickFalse))
1237      {
1238        /*
1239          Look for image format specification (e.g. ps3:image).
1240        */
1241        *p='\0';
1242        if (IsMagickConflict(component) != MagickFalse)
1243          *p=':';
1244        else
1245          {
1246            magick_length=(size_t) (p-component+1);
1247            for (q=component; *(++p) != '\0'; q++)
1248              *q=*p;
1249            *q='\0';
1250          }
1251        break;
1252      }
1253  }
1254  subimage_length=0;
1255  subimage_offset=0;
1256  p=component;
1257  if (*p != '\0')
1258    p=component+strlen(component)-1;
1259  if ((*p == ']') && (strchr(component,'[') != (char *) NULL) &&
1260      (IsPathAccessible(path) == MagickFalse))
1261    {
1262      /*
1263        Look for scene specification (e.g. img0001.pcd[4]).
1264      */
1265      for (q=p-1; q > component; q--)
1266        if (*q == '[')
1267          break;
1268      if (*q == '[')
1269        {
1270          *p='\0';
1271          if ((IsSceneGeometry(q+1,MagickFalse) == MagickFalse) &&
1272              (IsGeometry(q+1) == MagickFalse))
1273            *p=']';
1274          else
1275            {
1276              subimage_length=(size_t) (p-q);
1277              subimage_offset=magick_length+1+(size_t) (q-component);
1278              *q='\0';
1279            }
1280        }
1281    }
1282  p=component;
1283  if (*p != '\0')
1284    for (p=component+strlen(component)-1; p > component; p--)
1285      if (IsBasenameSeparator(*p) != MagickFalse)
1286        break;
1287  switch (type)
1288  {
1289    case MagickPath:
1290    {
1291      if (magick_length != 0)
1292        (void) CopyMagickString(component,path,magick_length);
1293      else
1294        *component = '\0';
1295      break;
1296    }
1297    case RootPath:
1298    {
1299      for (p=component+(strlen(component)-1); p > component; p--)
1300      {
1301        if (IsBasenameSeparator(*p) != MagickFalse)
1302          break;
1303        if (*p == '.')
1304          break;
1305      }
1306      if (*p == '.')
1307        *p='\0';
1308      break;
1309    }
1310    case HeadPath:
1311    {
1312      *p='\0';
1313      break;
1314    }
1315    case TailPath:
1316    {
1317      if (IsBasenameSeparator(*p) != MagickFalse)
1318        (void) CopyMagickMemory((unsigned char *) component,
1319          (const unsigned char *) (p+1),strlen(p+1)+1);
1320      break;
1321    }
1322    case BasePath:
1323    {
1324      if (IsBasenameSeparator(*p) != MagickFalse)
1325        (void) CopyMagickString(component,p+1,MagickPathExtent);
1326      for (p=component+(strlen(component)-1); p > component; p--)
1327        if (*p == '.')
1328          {
1329            *p='\0';
1330            break;
1331          }
1332      break;
1333    }
1334    case ExtensionPath:
1335    {
1336      if (IsBasenameSeparator(*p) != MagickFalse)
1337        (void) CopyMagickString(component,p+1,MagickPathExtent);
1338      p=component;
1339      if (*p != '\0')
1340        for (p=component+strlen(component)-1; p > component; p--)
1341          if (*p == '.')
1342            break;
1343      *component='\0';
1344      if (*p == '.')
1345        (void) CopyMagickString(component,p+1,MagickPathExtent);
1346      break;
1347    }
1348    case SubimagePath:
1349    {
1350      if (subimage_length != 0)
1351        (void) CopyMagickString(component,path+subimage_offset,subimage_length);
1352      else
1353        *component = '\0';
1354      break;
1355    }
1356    case CanonicalPath:
1357    case UndefinedPath:
1358      break;
1359  }
1360}
1361
1362/*
1363%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1364%                                                                             %
1365%                                                                             %
1366%                                                                             %
1367%  G e t P a t h C o m p o n e n t s                                          %
1368%                                                                             %
1369%                                                                             %
1370%                                                                             %
1371%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1372%
1373%  GetPathComponents() returns a list of path components.
1374%
1375%  The format of the GetPathComponents method is:
1376%
1377%      char **GetPathComponents(const char *path,
1378%        size_t *number_componenets)
1379%
1380%  A description of each parameter follows:
1381%
1382%    o path:  Specifies the string to segment into a list.
1383%
1384%    o number_components:  return the number of components in the list
1385%
1386*/
1387MagickPrivate char **GetPathComponents(const char *path,
1388  size_t *number_components)
1389{
1390  char
1391    **components;
1392
1393  register const char
1394    *p,
1395    *q;
1396
1397  register ssize_t
1398    i;
1399
1400  if (path == (char *) NULL)
1401    return((char **) NULL);
1402  *number_components=1;
1403  for (p=path; *p != '\0'; p++)
1404    if (IsBasenameSeparator(*p))
1405      (*number_components)++;
1406  components=(char **) AcquireQuantumMemory((size_t) *number_components+1UL,
1407    sizeof(*components));
1408  if (components == (char **) NULL)
1409    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1410  p=path;
1411  for (i=0; i < (ssize_t) *number_components; i++)
1412  {
1413    for (q=p; *q != '\0'; q++)
1414      if (IsBasenameSeparator(*q))
1415        break;
1416    components[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MagickPathExtent,
1417      sizeof(**components));
1418    if (components[i] == (char *) NULL)
1419      ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1420    (void) CopyMagickString(components[i],p,(size_t) (q-p+1));
1421    p=q+1;
1422  }
1423  components[i]=(char *) NULL;
1424  return(components);
1425}
1426
1427/*
1428%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1429%                                                                             %
1430%                                                                             %
1431%                                                                             %
1432%  I s P a t h A c c e s s i b l e                                            %
1433%                                                                             %
1434%                                                                             %
1435%                                                                             %
1436%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1437%
1438%  IsPathAccessible() returns MagickTrue if the file as defined by the path is
1439%  accessible.
1440%
1441%  The format of the IsPathAccessible method is:
1442%
1443%      MagickBooleanType IsPathAccessible(const char *path)
1444%
1445%  A description of each parameter follows.
1446%
1447%    o path:  Specifies a path to a file.
1448%
1449*/
1450MagickExport MagickBooleanType IsPathAccessible(const char *path)
1451{
1452  MagickBooleanType
1453    status;
1454
1455  struct stat
1456    attributes;
1457
1458  if ((path == (const char *) NULL) || (*path == '\0'))
1459    return(MagickFalse);
1460  if (LocaleCompare(path,"-") == 0)
1461    return(MagickTrue);
1462  status=GetPathAttributes(path,&attributes);
1463  if (status == MagickFalse)
1464    return(status);
1465  if (S_ISREG(attributes.st_mode) == 0)
1466    return(MagickFalse);
1467  if (access_utf8(path,F_OK) != 0)
1468    return(MagickFalse);
1469  return(MagickTrue);
1470}
1471
1472/*
1473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1474%                                                                             %
1475%                                                                             %
1476%                                                                             %
1477+  I s P a t h D i r e c t o r y                                              %
1478%                                                                             %
1479%                                                                             %
1480%                                                                             %
1481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1482%
1483%  IsPathDirectory() returns -1 if the directory does not exist,  1 is returned
1484%  if the path represents a directory otherwise 0.
1485%
1486%  The format of the IsPathDirectory method is:
1487%
1488%      int IsPathDirectory(const char *path)
1489%
1490%  A description of each parameter follows.
1491%
1492%   o  path:  The directory path.
1493%
1494*/
1495static int IsPathDirectory(const char *path)
1496{
1497  MagickBooleanType
1498    status;
1499
1500  struct stat
1501    attributes;
1502
1503  if ((path == (const char *) NULL) || (*path == '\0'))
1504    return(MagickFalse);
1505  status=GetPathAttributes(path,&attributes);
1506  if (status == MagickFalse)
1507    return(-1);
1508  if (S_ISDIR(attributes.st_mode) == 0)
1509    return(0);
1510  return(1);
1511}
1512
1513/*
1514%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1515%                                                                             %
1516%                                                                             %
1517%                                                                             %
1518%   L i s t F i l e s                                                         %
1519%                                                                             %
1520%                                                                             %
1521%                                                                             %
1522%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1523%
1524%  ListFiles() reads the directory specified and returns a list of filenames
1525%  contained in the directory sorted in ascending alphabetic order.
1526%
1527%  The format of the ListFiles function is:
1528%
1529%      char **ListFiles(const char *directory,const char *pattern,
1530%        ssize_t *number_entries)
1531%
1532%  A description of each parameter follows:
1533%
1534%    o filelist: Method ListFiles returns a list of filenames contained
1535%      in the directory.  If the directory specified cannot be read or it is
1536%      a file a NULL list is returned.
1537%
1538%    o directory: Specifies a pointer to a text string containing a directory
1539%      name.
1540%
1541%    o pattern: Specifies a pointer to a text string containing a pattern.
1542%
1543%    o number_entries:  This integer returns the number of filenames in the
1544%      list.
1545%
1546*/
1547
1548#if defined(__cplusplus) || defined(c_plusplus)
1549extern "C" {
1550#endif
1551
1552static int FileCompare(const void *x,const void *y)
1553{
1554  register const char
1555    **p,
1556    **q;
1557
1558  p=(const char **) x;
1559  q=(const char **) y;
1560  return(LocaleCompare(*p,*q));
1561}
1562
1563#if defined(__cplusplus) || defined(c_plusplus)
1564}
1565#endif
1566
1567static inline int MagickReadDirectory(DIR *directory,struct dirent *entry,
1568  struct dirent **result)
1569{
1570#if defined(MAGICKCORE_HAVE_READDIR_R)
1571  return(readdir_r(directory,entry,result));
1572#else
1573  (void) entry;
1574  errno=0;
1575  *result=readdir(directory);
1576  return(errno);
1577#endif
1578}
1579
1580MagickPrivate char **ListFiles(const char *directory,const char *pattern,
1581  size_t *number_entries)
1582{
1583  char
1584    **filelist;
1585
1586  DIR
1587    *current_directory;
1588
1589  struct dirent
1590    *buffer,
1591    *entry;
1592
1593  size_t
1594    max_entries;
1595
1596  /*
1597    Open directory.
1598  */
1599  assert(directory != (const char *) NULL);
1600  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",directory);
1601  assert(pattern != (const char *) NULL);
1602  assert(number_entries != (size_t *) NULL);
1603  *number_entries=0;
1604  current_directory=opendir(directory);
1605  if (current_directory == (DIR *) NULL)
1606    return((char **) NULL);
1607  /*
1608    Allocate filelist.
1609  */
1610  max_entries=2048;
1611  filelist=(char **) AcquireQuantumMemory((size_t) max_entries,
1612    sizeof(*filelist));
1613  if (filelist == (char **) NULL)
1614    {
1615      (void) closedir(current_directory);
1616      return((char **) NULL);
1617    }
1618  /*
1619    Save the current and change to the new directory.
1620  */
1621  buffer=(struct dirent *) AcquireMagickMemory(sizeof(*buffer)+FILENAME_MAX+1);
1622  if (buffer == (struct dirent *) NULL)
1623    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1624  while ((MagickReadDirectory(current_directory,buffer,&entry) == 0) &&
1625         (entry != (struct dirent *) NULL))
1626  {
1627    if (*entry->d_name == '.')
1628      continue;
1629    if ((IsPathDirectory(entry->d_name) > 0) ||
1630#if defined(MAGICKCORE_WINDOWS_SUPPORT)
1631        (GlobExpression(entry->d_name,pattern,MagickTrue) != MagickFalse))
1632#else
1633        (GlobExpression(entry->d_name,pattern,MagickFalse) != MagickFalse))
1634#endif
1635      {
1636        if (*number_entries >= max_entries)
1637          {
1638            /*
1639              Extend the file list.
1640            */
1641            max_entries<<=1;
1642            filelist=(char **) ResizeQuantumMemory(filelist,(size_t)
1643              max_entries,sizeof(*filelist));
1644            if (filelist == (char **) NULL)
1645              break;
1646          }
1647#if defined(vms)
1648        {
1649          register char
1650            *p;
1651
1652          p=strchr(entry->d_name,';');
1653          if (p)
1654            *p='\0';
1655          if (*number_entries > 0)
1656            if (LocaleCompare(entry->d_name,filelist[*number_entries-1]) == 0)
1657              continue;
1658        }
1659#endif
1660        filelist[*number_entries]=(char *) AcquireString(entry->d_name);
1661        (*number_entries)++;
1662      }
1663  }
1664  buffer=(struct dirent *) RelinquishMagickMemory(buffer);
1665  (void) closedir(current_directory);
1666  if (filelist == (char **) NULL)
1667    return((char **) NULL);
1668  /*
1669    Sort filelist in ascending order.
1670  */
1671  qsort((void *) filelist,(size_t) *number_entries,sizeof(*filelist),
1672    FileCompare);
1673  return(filelist);
1674}
1675
1676/*
1677%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1678%                                                                             %
1679%                                                                             %
1680%                                                                             %
1681%   M a g i c k D e l a y                                                     %
1682%                                                                             %
1683%                                                                             %
1684%                                                                             %
1685%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1686%
1687%  MagickDelay() suspends program execution for the number of milliseconds
1688%  specified.
1689%
1690%  The format of the Delay method is:
1691%
1692%      void MagickDelay(const MagickSizeType milliseconds)
1693%
1694%  A description of each parameter follows:
1695%
1696%    o milliseconds: Specifies the number of milliseconds to delay before
1697%      returning.
1698%
1699*/
1700MagickExport void MagickDelay(const MagickSizeType milliseconds)
1701{
1702  if (milliseconds == 0)
1703    return;
1704#if defined(MAGICKCORE_HAVE_NANOSLEEP)
1705  {
1706    struct timespec
1707      timer;
1708
1709    timer.tv_sec=(time_t) (milliseconds/1000);
1710    timer.tv_nsec=(milliseconds % 1000)*1000*1000;
1711    (void) nanosleep(&timer,(struct timespec *) NULL);
1712  }
1713#elif defined(MAGICKCORE_HAVE_USLEEP)
1714  usleep(1000*milliseconds);
1715#elif defined(MAGICKCORE_HAVE_SELECT)
1716  {
1717    struct timeval
1718      timer;
1719
1720    timer.tv_sec=(long) milliseconds/1000;
1721    timer.tv_usec=(long) (milliseconds % 1000)*1000;
1722    (void) select(0,(XFD_SET *) NULL,(XFD_SET *) NULL,(XFD_SET *) NULL,&timer);
1723  }
1724#elif defined(MAGICKCORE_HAVE_POLL)
1725  (void) poll((struct pollfd *) NULL,0,(int) milliseconds);
1726#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
1727  Sleep((long) milliseconds);
1728#elif defined(vms)
1729  {
1730    float
1731      timer;
1732
1733    timer=milliseconds/1000.0;
1734    lib$wait(&timer);
1735  }
1736#elif defined(__BEOS__)
1737  snooze(1000*milliseconds);
1738#else
1739# error "Time delay method not defined."
1740#endif
1741}
1742
1743/*
1744%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1745%                                                                             %
1746%                                                                             %
1747%                                                                             %
1748%  M u l t i l i n e C e n s u s                                              %
1749%                                                                             %
1750%                                                                             %
1751%                                                                             %
1752%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1753%
1754%  MultilineCensus() returns the number of lines within a label.  A line is
1755%  represented by a \n character.
1756%
1757%  The format of the MultilineCenus method is:
1758%
1759%      size_t MultilineCensus(const char *label)
1760%
1761%  A description of each parameter follows.
1762%
1763%   o  label:  This character string is the label.
1764%
1765*/
1766MagickExport size_t MultilineCensus(const char *label)
1767{
1768  size_t
1769    number_lines;
1770
1771  /*
1772    Determine the number of lines within this label.
1773  */
1774  if (label == (char *) NULL)
1775    return(0);
1776  for (number_lines=1; *label != '\0'; label++)
1777    if (*label == '\n')
1778      number_lines++;
1779  return(number_lines);
1780}
1781
1782/*
1783%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1784%                                                                             %
1785%                                                                             %
1786%                                                                             %
1787%   S h r e d F i l e                                                         %
1788%                                                                             %
1789%                                                                             %
1790%                                                                             %
1791%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1792%
1793%  ShredFile() overwrites the specified file with zeros or random data and then
1794%  removes it.  The overwrite is optional and is only required to help keep
1795%  the contents of the file private.  On the first pass, the file is zeroed.
1796%  For subsequent passes, random data is written.
1797%
1798%  The format of the ShredFile method is:
1799%
1800%      MagickBooleanType ShredFile(const char *path)
1801%
1802%  A description of each parameter follows.
1803%
1804%    o path:  Specifies a path to a file.
1805%
1806*/
1807MagickPrivate MagickBooleanType ShredFile(const char *path)
1808{
1809  char
1810    *passes;
1811
1812  int
1813    file,
1814    status;
1815
1816  MagickSizeType
1817    length;
1818
1819  register ssize_t
1820    i;
1821
1822  size_t
1823    quantum;
1824
1825  struct stat
1826    file_stats;
1827
1828  if ((path == (const char *) NULL) || (*path == '\0'))
1829    return(MagickFalse);
1830  passes=GetEnvironmentValue("MAGICK_SHRED_PASSES");
1831  if (passes == (char *) NULL)
1832    {
1833      /*
1834        Don't shred the file, just remove it.
1835      */
1836      status=remove_utf8(path);
1837      if (status == -1)
1838        {
1839          (void) LogMagickEvent(ExceptionEvent,GetMagickModule(),
1840            "Failed to remove: %s",path);
1841          return(MagickFalse);
1842        }
1843      return(MagickTrue);
1844    }
1845  file=open_utf8(path,O_WRONLY | O_EXCL | O_BINARY,S_MODE);
1846  if (file == -1)
1847    {
1848      /*
1849        Don't shred the file, just remove it.
1850      */
1851      passes=DestroyString(passes);
1852      status=remove_utf8(path);
1853      if (status == -1)
1854        (void) LogMagickEvent(ExceptionEvent,GetMagickModule(),
1855          "Failed to remove: %s",path);
1856      return(MagickFalse);
1857    }
1858  /*
1859    Shred the file.
1860  */
1861  quantum=(size_t) MagickMaxBufferExtent;
1862  if ((fstat(file,&file_stats) == 0) && (file_stats.st_size > 0))
1863    quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
1864  length=(MagickSizeType) file_stats.st_size;
1865  for (i=0; i < (ssize_t) StringToInteger(passes); i++)
1866  {
1867    RandomInfo
1868      *random_info;
1869
1870    register MagickOffsetType
1871      j;
1872
1873    ssize_t
1874      count;
1875
1876    if (lseek(file,0,SEEK_SET) < 0)
1877      break;
1878    random_info=AcquireRandomInfo();
1879    for (j=0; j < (MagickOffsetType) length; j+=count)
1880    {
1881      StringInfo
1882        *key;
1883
1884      key=GetRandomKey(random_info,quantum);
1885      if (i == 0)
1886        ResetStringInfo(key);  /* zero on first pass */
1887      count=write(file,GetStringInfoDatum(key),(size_t)
1888        MagickMin(quantum,length-j));
1889      key=DestroyStringInfo(key);
1890      if (count <= 0)
1891        {
1892          count=0;
1893          if (errno != EINTR)
1894            break;
1895        }
1896    }
1897    random_info=DestroyRandomInfo(random_info);
1898    if (j < (MagickOffsetType) length)
1899      break;
1900  }
1901  status=close(file);
1902  status=remove_utf8(path);
1903  if (status != -1)
1904    status=StringToInteger(passes);
1905  passes=DestroyString(passes);
1906  return((status == -1 || i < (ssize_t) status) ? MagickFalse : MagickTrue);
1907}
1908