1 /* @source ajsys **************************************************************
2 **
3 ** AJAX system functions
4 **
5 ** Copyright (c) Alan Bleasby 1999
6 ** @version $Revision: 1.90 $
7 ** @modified $Date: 2011/11/23 09:52:54 $ by $Author: rice $
8 ** @@
9 **
10 ** This library is free software; you can redistribute it and/or
11 ** modify it under the terms of the GNU Lesser General Public
12 ** License as published by the Free Software Foundation; either
13 ** version 2.1 of the License, or (at your option) any later version.
14 **
15 ** This library is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 ** Lesser General Public License for more details.
19 **
20 ** You should have received a copy of the GNU Lesser General Public
21 ** License along with this library; if not, write to the Free Software
22 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 ** MA 02110-1301, USA.
24 **
25 ******************************************************************************/
26
27
28 #include "ajlib.h"
29
30 #include "ajsys.h"
31 #include "ajlist.h"
32 #include "ajfile.h"
33 #include "ajreg.h"
34 #include "ajnam.h"
35 #include "ajutil.h"
36
37 #ifndef WIN32
38 #ifndef __VMS
39 #include <termios.h>
40 #endif
41 #include <sys/file.h>
42 #include <sys/types.h>
43 #include <sys/wait.h>
44 #include <unistd.h>
45 #include <locale.h>
46 #include <pwd.h>
47 #include <fcntl.h>
48 #else
49 #include "win32.h"
50 #include <direct.h>
51 #include <stdio.h>
52 #include <io.h>
53 #define open _open
54 #define close _close
55 #define read _read
56 #define write _write
57 #define strnicmp _strnicmp
58 #define fdopen _fdopen
59 #define rmdir _rmdir
60
61 #pragma warning(disable:4142) /* benign redefinition of type */
62 #include <ShlObj.h>
63 #include <Sddl.h>
64 #endif
65
66 #include <errno.h>
67
68
69 static AjPStr sysTname = NULL;
70 static AjPStr sysFname = NULL;
71 static AjPStr sysTokRets = NULL;
72 static AjPStr sysTokSou = NULL;
73 static const char *sysTokp = NULL;
74 static AjPStr sysUserPath = NULL;
75
76 #ifndef WIN32
77 static void sysTimeoutAbort(int sig);
78 #else
79 static void CALLBACK sysTimeoutAbort(LPVOID arg, DWORD low, DWORD high);
80 #endif
81
82
83
84
85 /* @filesection ajutil ********************************************************
86 **
87 ** @nam1rule aj Function belongs to the AJAX library.
88 **
89 */
90
91
92
93
94 /* @datasection [none] System utility functions *******************************
95 **
96 ** @nam2rule Sys Function belongs to the AJAX ajsys library.
97 **
98 */
99
100
101
102
103 /* @section Argument list manipulation functions ******************************
104 **
105 ** Function for manipulating argument list.
106 **
107 ** @fdata [none]
108 **
109 ** @nam3rule Arglist Function for manipulating argument list.
110 ** @nam4rule ArglistBuild Generates a program name and argument list from a
111 ** command line string.
112 ** @nam4rule ArglistFree Free memory in an argument list allocated by
113 ** ajSysArglistBuild.
114 ** @suffix C Accept C character string parameters
115 ** @suffix S Accept string object parameters
116 **
117 ** @argrule C cmdlinetxt [const char*] Original command line
118 ** @argrule S cmdline [const AjPStr] Original command line
119 ** @argrule Build Pname [char**] Returned program name
120 ** @argrule Arglist PParglist [char***] Returns argument array
121 **
122 ** @valrule Build [AjBool] True on success
123 ** @valrule Free [void]
124 **
125 ** @fcategory misc
126 **
127 ******************************************************************************/
128
129
130
131
132 /* @func ajSysArglistBuildC ***************************************************
133 **
134 ** Generates a program name and argument list from a command line string.
135 **
136 ** @param [r] cmdlinetxt [const char*] Command line.
137 ** @param [w] Pname [char**] Program name.
138 ** @param [w] PParglist [char***] Argument list.
139 ** @return [AjBool] ajTrue on success.
140 **
141 ** @release 6.3.0
142 ** @@
143 ******************************************************************************/
144
ajSysArglistBuildC(const char * cmdlinetxt,char ** Pname,char *** PParglist)145 AjBool ajSysArglistBuildC(const char* cmdlinetxt,
146 char** Pname, char*** PParglist)
147 {
148 static AjPRegexp argexp = NULL;
149 AjPStr tmpline = NULL;
150 const char* cp;
151 ajint ipos = 0;
152 ajint iarg = 0;
153 ajint ilen = 0;
154 ajint i;
155 char** al;
156 AjPStr argstr = NULL;
157
158 if(!argexp)
159 argexp = ajRegCompC("^[ \t]*(\"([^\"]*)\"|'([^']*)'|([^ \t]+))");
160
161 ajDebug("ajSysArglistBuildC '%s'\n", cmdlinetxt);
162
163 ajStrAssignC(&tmpline, cmdlinetxt);
164
165 cp = cmdlinetxt;
166 ipos = 0;
167 while(ajRegExecC(argexp, &cp[ipos]))
168 {
169 ipos += ajRegLenI(argexp, 0);
170 iarg++;
171 }
172
173 AJCNEW(*PParglist, iarg+1);
174 al = *PParglist;
175 ipos = 0;
176 iarg = 0;
177 while(ajRegExecC(argexp, &cp[ipos]))
178 {
179 ilen = ajRegLenI(argexp, 0);
180 ajStrDelStatic(&argstr);
181 for(i=2;i<5;i++)
182 {
183 if(ajRegLenI(argexp, i))
184 {
185 ajRegSubI(argexp, i, &argstr);
186 ajDebug("parsed [%d] '%S'\n", i, argstr);
187 break;
188 }
189 }
190 ipos += ilen;
191
192 if(!iarg)
193 *Pname = ajCharNewS(argstr);
194
195 al[iarg] = ajCharNewS(argstr);
196 iarg++;
197 }
198
199 al[iarg] = NULL;
200
201 ajRegFree(&argexp);
202 argexp = NULL;
203 ajStrDel(&tmpline);
204 ajStrDel(&argstr);
205
206 ajDebug("ajSysArglistBuildC %d args for '%s'\n", iarg, *Pname);
207
208 return ajTrue;
209 }
210
211
212
213
214 /* @func ajSysArglistBuildS ***************************************************
215 **
216 ** Generates a program name and argument list from a command line string.
217 **
218 ** @param [r] cmdline [const AjPStr] Command line.
219 ** @param [w] Pname [char**] Program name.
220 ** @param [w] PParglist [char***] Argument list.
221 ** @return [AjBool] ajTrue on success.
222 **
223 ** @release 6.3.0
224 ** @@
225 ******************************************************************************/
226
ajSysArglistBuildS(const AjPStr cmdline,char ** Pname,char *** PParglist)227 AjBool ajSysArglistBuildS(const AjPStr cmdline, char** Pname, char*** PParglist)
228 {
229 return ajSysArglistBuildC(MAJSTRGETPTR(cmdline), Pname, PParglist);
230 }
231
232
233
234
235 /* @func ajSysArglistFree *****************************************************
236 **
237 ** Free memory in an argument list allocated by ajSysArgList
238 **
239 ** @param [w] PParglist [char***] Argument list.
240 ** @return [void]
241 **
242 ** @release 5.0.0
243 ** @@
244 ******************************************************************************/
245
ajSysArglistFree(char *** PParglist)246 void ajSysArglistFree(char*** PParglist)
247 {
248 char** ca;
249 ajint i;
250
251 ca = *PParglist;
252
253 i = 0;
254 while(ca[i])
255 {
256 AJFREE(ca[i]);
257 ++i;
258 }
259
260 AJFREE(*PParglist);
261
262 return;
263 }
264
265
266
267
268 /* @section System cast functions *********************************************
269 **
270 ** Function for casting one datatype to another.
271 **
272 ** @fdata [none]
273 ** @fcategory misc
274 **
275 ** @nam3rule Cast Function for casting one datatype to another.
276 ** @nam4rule CastItoc Convert Int to Char (for fussy compilers)
277 ** @nam4rule CastItouc Convert Int to Unsigned Char (for fussy compilers).
278 **
279 ** @argrule * v [ajint] Character as an integer
280 **
281 ** @valrule *Itoc [char] Character
282 ** @valrule *Itouc [unsigned char] Unsigned character
283 **
284 ******************************************************************************/
285
286
287
288
289 /* @func ajSysCastItoc ********************************************************
290 **
291 ** Convert Int to Char
292 ** Needed for very fussy compilers i.e. Digital C
293 **
294 ** @param [r] v [ajint] integer
295 ** @return [char] Character cast
296 **
297 ** @release 5.0.0
298 ** @@
299 ******************************************************************************/
300
ajSysCastItoc(ajint v)301 char ajSysCastItoc(ajint v)
302 {
303 char c;
304
305 c = (char) v;
306 return c;
307 }
308
309
310
311
312 /* @func ajSysCastItouc *******************************************************
313 **
314 ** Convert Int to Unsigned Char
315 ** Needed for very fussy compilers i.e. Digital C
316 **
317 ** @param [r] v [ajint] integer
318 ** @return [unsigned char] Unsigned character cast
319 **
320 ** @release 5.0.0
321 ** @@
322 ******************************************************************************/
323
ajSysCastItouc(ajint v)324 unsigned char ajSysCastItouc(ajint v)
325 {
326 char c;
327
328 c = (unsigned char) v;
329 return c;
330 }
331
332
333
334
335 /* @section System functions for files ****************************************
336 **
337 ** System functions for files.
338 **
339 ** @fdata [none]
340 ** @fcategory misc
341 **
342 ** @nam3rule File System functions for files.
343 ** @nam4rule FileRmrf Recursively deletes a directory tree
344 ** @nam4rule FileWhich Searches $PATH sequentially for a user-EXECUTABLE
345 ** file.
346 ** @nam5rule FileWhichEnv Uses environment to extract the PATH list.
347 ** @nam4rule FileUnlink Deletes a file or link
348 ** @nam3rule Get Return attribute
349 ** @nam4rule GetHomedir Return home directory
350 ** @nam5rule GetHomedirFrom Get home directory from parameter
351 ** @nam6rule FromName Get home directory for a named user
352 **
353 ** @suffix C Accept C character string parameters
354 ** @suffix S Accept string object parameters
355 **
356 ** @argrule RmrfC path [const char*] Directory name
357 ** @argrule RmrfS path [const AjPStr] Directory name
358 ** @argrule UnlinkC filename [const char*] File name
359 ** @argrule UnlinkS filename [const AjPStr] File name
360 ** @argrule Which Pfilename [AjPStr*] File name (updated when found)
361 ** @argrule Env env [char* const[]] File name (updated when found)
362 ** @argrule FromName username [const char*] Username
363 **
364 ** @valrule Homedir [char*] Home directory name
365 ** @valrule File [AjBool] True if operation is successful.
366 **
367 ******************************************************************************/
368
369
370
371
372 /* @func ajSysFileRmrfC *******************************************************
373 **
374 ** Forcibly delete a directory tree
375 **
376 ** @param [r] path [const char*] Directory path
377 ** @return [AjBool] true if deleted false otherwise
378 **
379 ** @release 6.3.0
380 ** @@
381 ******************************************************************************/
382
ajSysFileRmrfC(const char * path)383 AjBool ajSysFileRmrfC(const char *path)
384 {
385 AjPList flist = NULL;
386
387 AjPStr wild = NULL;
388 AjPStr fname = NULL;
389 AjPStr dirpath = NULL;
390 const char *pdir = NULL;
391
392 AjBool ret;
393
394
395 if(ajCharMatchC(path,".") || ajCharMatchC(path,".."))
396 return ajFalse;
397
398 flist = ajListNew();
399 wild = ajStrNewC("*");
400
401 dirpath = ajStrNewC(path);
402
403 ret = ajTrue;
404
405 if(!ajFilenameExistsDir(dirpath))
406 {
407 ajListFree(&flist);
408 ajStrDel(&wild);
409 ajStrDel(&dirpath);
410
411 return ajFalse;
412 }
413
414 ajFilelistAddPathWildDir(flist, dirpath, wild);
415
416 while(ajListPop(flist, (void **) &fname))
417 {
418 if(ajFilenameExistsDir(fname))
419 {
420 pdir = ajStrGetPtr(fname);
421 ret = ajSysFileRmrfC(pdir);
422
423 if(!ret)
424 break;
425
426 }
427 else
428 {
429 ret = ajSysFileUnlinkS(fname);
430
431 if(!ret)
432 break;
433 }
434
435 ajStrDel(&fname);
436 }
437
438 if(!(ajCharMatchC(path,".") || ajCharMatchC(path,"..")))
439 if(rmdir(path))
440 ret = ajFalse;
441
442 while(ajListPop(flist, (void **) &fname))
443 ajStrDel(&fname);
444
445 ajStrDel(&wild);
446 ajStrDel(&dirpath);
447
448 ajListFree(&flist);
449
450 return ret;
451 }
452
453
454
455
456 /* @func ajSysFileRmrfS *******************************************************
457 **
458 ** Forcibly delete a directory tree
459 **
460 ** @param [r] path [const AjPStr] Directory path
461 ** @return [AjBool] true if deleted false otherwise
462 **
463 ** @release 6.5.0
464 ** @@
465 ******************************************************************************/
466
ajSysFileRmrfS(const AjPStr path)467 AjBool ajSysFileRmrfS(const AjPStr path)
468 {
469 return ajSysFileRmrfC(MAJSTRGETPTR(path));
470 }
471
472
473
474
475 /* @func ajSysFileUnlinkC *****************************************************
476 **
477 ** Deletes a file or link
478 **
479 ** @param [r] filename [const char*] Filename in AjStr.
480 ** @return [AjBool] true if deleted false otherwise
481 **
482 ** @release 6.3.0
483 ** @@
484 ******************************************************************************/
485
ajSysFileUnlinkC(const char * filename)486 AjBool ajSysFileUnlinkC(const char* filename)
487 {
488 ajDebug("ajSysFileUnlinkC '%s'\n", filename);
489
490 #ifndef WIN32
491 if(!unlink(filename))
492 return ajTrue;
493
494 ajErr("File '%s' remove failed, error:%d '%s'", filename,
495 errno, strerror(errno));
496 #else
497 if(DeleteFile(filename))
498 return ajTrue;
499 #endif
500 ajDebug("ajSysFileUnlinkC failed to delete '%s'\n", filename);
501
502 return ajFalse;
503 }
504
505
506
507
508 /* @func ajSysFileUnlinkS *****************************************************
509 **
510 ** Deletes a file or link
511 **
512 ** @param [r] filename [const AjPStr] Filename in AjStr.
513 ** @return [AjBool] true if deleted false otherwise
514 **
515 ** @release 6.3.0
516 ** @@
517 ******************************************************************************/
518
ajSysFileUnlinkS(const AjPStr filename)519 AjBool ajSysFileUnlinkS(const AjPStr filename)
520 {
521 return ajSysFileUnlinkC(MAJSTRGETPTR(filename));
522 }
523
524
525
526
527 /* @func ajSysFileWhich *******************************************************
528 **
529 ** Gets the Basename of a file then searches $PATH sequentially until it
530 ** finds a user-EXECUTABLE file of the same name.
531 **
532 ** @param [u] Pfilename [AjPStr*] Filename in AjStr, replaced by full pathname
533 ** @return [AjBool] True if executable found, false otherwise
534 **
535 ** @release 5.0.0
536 ** @@
537 ******************************************************************************/
538
ajSysFileWhich(AjPStr * Pfilename)539 AjBool ajSysFileWhich(AjPStr *Pfilename)
540 {
541 char *p;
542
543 if(!ajStrGetLen(sysUserPath))
544 ajStrAssignC(&sysUserPath, getenv("PATH"));
545
546 if(!ajStrGetLen(sysUserPath))
547 return ajFalse;
548
549 p = ajStrGetuniquePtr(&sysUserPath);
550
551 if(!ajNamGetValueS(*Pfilename, &sysTname))
552 ajStrAssignS(&sysTname, *Pfilename);
553
554 if(ajFilenameExistsExec(sysTname))
555 {
556 ajStrAssignS(Pfilename,sysTname);
557 ajStrDelStatic(&sysTname);
558 return ajTrue;
559 }
560
561 if(!sysFname)
562 sysFname = ajStrNew();
563
564 p=ajSysFuncStrtok(p,PATH_SEPARATOR);
565
566 if(p==NULL)
567 {
568 ajStrDelStatic(&sysFname);
569 ajStrDelStatic(&sysTname);
570 return ajFalse;
571 }
572
573
574 while(1)
575 {
576 #if !defined(WIN32) && !defined(__CYGWIN__)
577 ajFmtPrintS(&sysFname,"%s%s%S",p,SLASH_STRING,sysTname);
578 #else
579 ajFmtPrintS(&sysFname,"%s%s%S.exe",p,SLASH_STRING,sysTname);
580 #endif
581
582 if(ajFilenameExistsExec(sysFname))
583 {
584 ajStrAssignS(Pfilename,sysFname);
585 break;
586 }
587
588 if((p = ajSysFuncStrtok(NULL,PATH_SEPARATOR))==NULL)
589 {
590 ajStrDelStatic(&sysFname);
591 ajStrDelStatic(&sysTname);
592 return ajFalse;
593 }
594 }
595
596 ajStrDelStatic(&sysFname);
597 ajStrDelStatic(&sysTname);
598
599 return ajTrue;
600 }
601
602
603
604
605 /* @func ajSysFileWhichEnv ****************************************************
606 **
607 ** Gets the Basename of a file then searches $PATH sequentially until it
608 ** finds a user-EXECUTABLE file of the same name. Reentrant.
609 **
610 ** @param [u] Pfilename [AjPStr*] Filename in AjStr, replaced by full pathname
611 ** @param [r] env [char* const[]] Environment
612 ** @return [AjBool] True if executable found, false otherwise
613 **
614 ** @release 5.0.0
615 ** @@
616 ******************************************************************************/
617
ajSysFileWhichEnv(AjPStr * Pfilename,char * const env[])618 AjBool ajSysFileWhichEnv(AjPStr *Pfilename, char * const env[])
619 {
620 ajint count;
621 char *p = NULL;
622 const char *cp;
623 AjPStr tname = NULL;
624 AjPStr fname = NULL;
625 AjPStr path = NULL;
626 const char *save = NULL;
627 AjPStr buf = NULL;
628 AjPStr tmp = NULL;
629
630
631 buf = ajStrNew();
632 tname = ajStrNew();
633 tmp = ajStrNew();
634 ajStrAssignS(&tname,*Pfilename);
635
636 fname = ajStrNew();
637 path = ajStrNew();
638
639 ajFilenameTrimPath(&tname);
640
641 #ifdef WIN32
642 ajStrAppendC(&tname,".exe");
643 #endif
644
645 ajDebug("ajSysFileWhichEnv '%S' => %S\n", *Pfilename, tname);
646
647 count = 0;
648 while(env[count]!=NULL)
649 {
650 if(!(*env[count]))
651 break;
652
653 /*ajDebug(" env[%d] '%s'\n", count, env[count]);*/
654
655 #ifndef WIN32
656 if(!strncmp("PATH=",env[count],5))
657 #else
658 if(!strnicmp("PATH=",env[count],5))
659 #endif
660 break;
661
662 ++count;
663 }
664
665 /* ajDebug("PATH env[%d] '%s'\n", count, env[count]);*/
666
667 if(env[count]==NULL || !(*env[count]))
668 {
669 ajStrDel(&fname);
670 ajStrDel(&tname);
671 ajStrDel(&path);
672 ajStrDel(&buf);
673 ajStrDel(&tmp);
674 return ajFalse;
675 }
676
677 ajStrAssignC(&path, env[count]);
678 cp = ajStrGetPtr(path);
679 cp += 5;
680 ajStrAssignC(&tmp,cp);
681
682 /*ajDebug("tmp '%S' save '%S' buf '%S'\n", tmp, save, buf);*/
683
684 p = ajSysFuncStrtokR(ajStrGetuniquePtr(&tmp),PATH_SEPARATOR,&save,&buf);
685
686 if(p==NULL)
687 {
688 ajStrDel(&fname);
689 ajStrDel(&tname);
690 ajStrDel(&path);
691 ajStrDel(&buf);
692 ajStrDel(&tmp);
693 return ajFalse;
694 }
695
696
697 ajFmtPrintS(&fname,"%s%s%S",p,SLASH_STRING,tname);
698
699 while(!ajFilenameExistsExec(fname))
700 {
701 if((p = ajSysFuncStrtokR(NULL,PATH_SEPARATOR,&save,&buf))==NULL)
702 {
703 ajStrDel(&fname);
704 ajStrDel(&tname);
705 ajStrDel(&path);
706 ajStrDel(&buf);
707 ajStrDel(&tmp);
708 return ajFalse;
709 }
710
711 ajFmtPrintS(&fname,"%s%s%S",p,SLASH_STRING,tname);
712 }
713
714
715 ajStrAssignS(Pfilename,fname);
716 ajDebug("ajSysFileWhichEnv returns '%S'\n", *Pfilename);
717
718 ajStrDel(&fname);
719 ajStrDel(&tname);
720 ajStrDel(&path);
721 ajStrDel(&buf);
722 ajStrDel(&tmp);
723
724 return ajTrue;
725 }
726
727
728
729
730 /* @func ajSysGetHomedir ******************************************************
731 **
732 ** Get the home directory of the current user
733 **
734 ** @return [char*] Home directory or NULL
735 **
736 ** @release 6.3.0
737 ** @@
738 ******************************************************************************/
739
ajSysGetHomedir(void)740 char* ajSysGetHomedir(void)
741 {
742 char *hdir = NULL;
743 #ifndef WIN32
744 char *p = NULL;
745
746 if(!(p = getenv("HOME")))
747 return NULL;
748
749 hdir = ajCharNewC(p);
750 #else
751 TCHAR wpath[MAX_PATH];
752 HRESULT ret;
753
754 /* Replace with SHGetKnownFolderPath when XP is no longer supported */
755 ret = SHGetFolderPath(NULL,CSIDL_PROFILE,NULL,0,wpath);
756
757 if(ret != S_OK)
758 return NULL;
759
760 hdir = ajCharNewC(wpath);
761 #endif
762
763 return hdir;
764 }
765
766
767
768
769 /* @func ajSysGetHomedirFromName **********************************************
770 **
771 ** Get a home directory location from a username
772 **
773 ** @param [r] username [const char*] Username
774 ** @return [char*] Home directory or NULL
775 **
776 ** @release 6.3.0
777 ** @@
778 ******************************************************************************/
779
ajSysGetHomedirFromName(const char * username)780 char* ajSysGetHomedirFromName(const char *username)
781 {
782 char *hdir = NULL;
783 #ifndef WIN32
784 struct passwd *pass = NULL;
785
786
787 pass = getpwnam(username);
788
789 if(!pass)
790 return NULL;
791
792 hdir = ajCharNewC(pass->pw_dir);
793 #else
794 LPTSTR domainname = NULL;
795 LPTSTR localsvr = NULL;
796 DWORD dnsize = 0;
797 PSID psid = NULL;
798 DWORD sidsize = 0;
799
800 SID_NAME_USE sidtype;
801
802 LPTSTR strsid = NULL;
803 AjPStr subkey = NULL;
804
805 DWORD hdbuffsize = MAX_PATH;
806 char hdbuff[MAX_PATH];
807
808 LONG ret;
809 HKEY hkey = NULL;
810
811 if(!LookupAccountName(localsvr, username, psid, &sidsize, domainname,
812 &dnsize, &sidtype))
813 {
814 if(GetLastError() == ERROR_NONE_MAPPED)
815 {
816 ajWarn("No Windows username found for '%s'", username);
817 return NULL;
818 }
819 else if(GetLastError() == ERROR_INSUFFICIENT_BUFFER)
820 {
821 psid = (LPTSTR) LocalAlloc(LPTR,sidsize * sizeof(TCHAR));
822 if(!psid)
823 {
824 ajWarn("ajSysLookupAccount: SID allocation failure");
825 return NULL;
826 }
827
828 domainname = (LPTSTR) LocalAlloc(LPTR, dnsize * sizeof(TCHAR));
829 if(!domainname)
830 {
831 ajWarn("ajSysLookupAccount: Domain allocation failure");
832 LocalFree(psid);
833 return NULL;
834 }
835
836 if(!LookupAccountName(localsvr, username, psid, &sidsize,
837 domainname, &dnsize, &sidtype))
838 {
839 ajWarn("LookupAccountName failed with %d", GetLastError());
840 LocalFree(psid);
841 LocalFree(domainname);
842 return NULL;
843 }
844 }
845 else
846 {
847 ajWarn("General LookupAccountName failure with %d", GetLastError());
848 return NULL;
849 }
850 }
851
852
853 if(!ConvertSidToStringSid(psid, &strsid))
854 {
855 LocalFree(psid);
856
857 return NULL;
858 }
859
860 LocalFree(psid);
861
862 subkey = ajStrNew();
863
864 ajFmtPrintS(&subkey,"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\"
865 "ProfileList\\%s",strsid);
866
867 LocalFree(strsid);
868
869 ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,ajStrGetPtr(subkey),(DWORD) 0,
870 KEY_QUERY_VALUE,&hkey);
871
872 ajStrDel(&subkey);
873
874 if(ret != ERROR_SUCCESS)
875 return NULL;
876
877 ret = RegQueryValueEx(hkey,"ProfileImagePath",NULL,NULL,(LPBYTE)hdbuff,
878 &hdbuffsize);
879
880 if(ret != ERROR_SUCCESS)
881 return NULL;
882
883 ret = RegCloseKey(hkey);
884
885 if(ret != ERROR_SUCCESS)
886 return NULL;
887
888 hdir = ajCharNewC(hdbuff);
889 #endif
890
891
892 return hdir;
893 }
894
895
896
897
898 /* @section Wrappers to commands **********************************************
899 **
900 ** Functions for invoking commands
901 **
902 ** @fdata [none]
903 ** @fcategory misc
904 **
905 ** @nam3rule Command Execute the equivalent of a command
906 ** @nam4rule CommandClear Execute a clear screen command
907 ** @nam4rule CommandCopy Execute a copy command
908 ** @nam4rule CommandMakedir Execute a make directory command
909 ** @nam4rule CommandRemove Execute a remove file command
910 ** @nam4rule CommandRemovedir Execute a remove directory command
911 ** @nam4rule CommandRename Execute a fle rename command
912 ** @suffix C Accept C character string parameters
913 ** @suffix S Accept string object parameters
914 **
915 ** @argrule C name [const char*] Filename or directory name
916 ** @argrule S strname [const AjPStr] Filename or directory name
917 ** @argrule CopyC name2 [const char*] Destination filename
918 ** @argrule CopyS strname2 [const AjPStr] Destination filename
919 ** @argrule RenameC name2 [const char*] Destination filename
920 ** @argrule RenameS strname2 [const AjPStr] Destination filename
921 **
922 ** @valrule * [AjBool] True on success
923 **
924 ******************************************************************************/
925
926
927
928
929 /* @func ajSysCommandCopyC ****************************************************
930 **
931 ** Copy a file
932 **
933 ** @param [r] name [const char*] Source filename
934 ** @param [r] name2 [const char*] Target filename
935 ** @return [AjBool] True on success
936 **
937 **
938 ** @release 6.3.0
939 ******************************************************************************/
940
ajSysCommandCopyC(const char * name,const char * name2)941 AjBool ajSysCommandCopyC(const char* name, const char* name2)
942 {
943 int from;
944 int to;
945 int n;
946 int nw;
947 char cbuf[1024];
948 char *buf;
949
950 from = open(name, O_RDONLY);
951 if(from < 0)
952 {
953 ajErr("Unable to copy '%s' error %d: %s",
954 name, errno, strerror(errno));
955 return ajFalse;
956 }
957
958 to = open(name2, O_WRONLY|O_CREAT, 0644);
959 if(to < 0)
960 {
961 ajErr("Unable to copy to '%s' error %d: %s",
962 name2, errno, strerror(errno));
963 return ajFalse;
964 }
965
966 while((n = read(from, cbuf, sizeof(cbuf))) > 0)
967 {
968 buf = cbuf;
969 do
970 {
971 nw = write(to, buf, n);
972 if(nw == n)
973 break;
974 if(nw > 0)
975 {
976 buf += nw;
977 n -= nw;
978 }
979 } while (nw >= 0 || errno == EINTR);
980 if(nw < 0)
981 {
982 ajErr("Write to %s failed, error:%d %s",
983 name2, errno, strerror(errno));
984 return ajFalse;
985 }
986 }
987
988 close(from);
989 close(to);
990
991 return ajTrue;
992 }
993
994
995
996
997 /* @func ajSysCommandCopyS ****************************************************
998 **
999 ** Copy a file
1000 **
1001 ** @param [r] strname [const AjPStr] Source filename
1002 ** @param [r] strname2 [const AjPStr] Target filename
1003 ** @return [AjBool] True on success
1004 **
1005 **
1006 ** @release 6.3.0
1007 ******************************************************************************/
1008
ajSysCommandCopyS(const AjPStr strname,const AjPStr strname2)1009 AjBool ajSysCommandCopyS(const AjPStr strname, const AjPStr strname2)
1010 {
1011 return ajSysCommandCopyC(MAJSTRGETPTR(strname), MAJSTRGETPTR(strname2));
1012 }
1013
1014
1015
1016
1017 /* @func ajSysCommandMakedirC *************************************************
1018 **
1019 ** Delete a file
1020 **
1021 ** @param [r] name [const char*] Directory
1022 ** @return [AjBool] True on success
1023 **
1024 **
1025 ** @release 6.3.0
1026 ******************************************************************************/
1027
ajSysCommandMakedirC(const char * name)1028 AjBool ajSysCommandMakedirC(const char* name)
1029 {
1030 #ifndef WIN32
1031 if(!mkdir(name, 0775))
1032 return ajTrue;
1033 #else
1034 if(!_mkdir(name))
1035 return ajTrue;
1036 #endif
1037
1038 ajErr("Unable to make directory '%s' (%d): %s",
1039 name, errno, strerror(errno));
1040
1041 return ajFalse;
1042 }
1043
1044
1045
1046
1047 /* @func ajSysCommandMakedirS *************************************************
1048 **
1049 ** Delete a file
1050 **
1051 ** @param [r] strname [const AjPStr] Directory
1052 ** @return [AjBool] True on success
1053 **
1054 **
1055 ** @release 6.3.0
1056 ******************************************************************************/
1057
ajSysCommandMakedirS(const AjPStr strname)1058 AjBool ajSysCommandMakedirS(const AjPStr strname)
1059 {
1060 return ajSysCommandMakedirC(MAJSTRGETPTR(strname));
1061 }
1062
1063
1064
1065
1066 /* @func ajSysCommandRemoveC **************************************************
1067 **
1068 ** Delete a file
1069 **
1070 ** @param [r] name [const char*] Filename
1071 ** @return [AjBool] True on success
1072 **
1073 **
1074 ** @release 6.3.0
1075 ******************************************************************************/
1076
ajSysCommandRemoveC(const char * name)1077 AjBool ajSysCommandRemoveC(const char* name)
1078 {
1079 return ajSysFileUnlinkC(name);
1080 }
1081
1082
1083
1084
1085 /* @func ajSysCommandRemoveS **************************************************
1086 **
1087 ** Delete a file
1088 **
1089 ** @param [r] strname [const AjPStr] Filename
1090 ** @return [AjBool] True on success
1091 **
1092 **
1093 ** @release 6.3.0
1094 ******************************************************************************/
1095
ajSysCommandRemoveS(const AjPStr strname)1096 AjBool ajSysCommandRemoveS(const AjPStr strname)
1097 {
1098 return ajSysFileUnlinkC(MAJSTRGETPTR(strname));
1099 }
1100
1101
1102
1103
1104 /* @func ajSysCommandRemovedirC ***********************************************
1105 **
1106 ** Delete a file
1107 **
1108 ** @param [r] name [const char*] Directory
1109 ** @return [AjBool] True on success
1110 **
1111 **
1112 ** @release 6.3.0
1113 ******************************************************************************/
1114
ajSysCommandRemovedirC(const char * name)1115 AjBool ajSysCommandRemovedirC(const char* name)
1116 {
1117 AjPStr cmdstr = NULL;
1118 AjBool ret;
1119
1120 ret = ajTrue;
1121
1122 cmdstr = ajStrNewC(name);
1123 if(!ajFilenameExistsDir(cmdstr))
1124 {
1125 if(!ajFilenameExists(cmdstr))
1126 ajErr("Unable to remove directory '%S' not found", cmdstr);
1127 else
1128 ajErr("Unable to remove directory '%S' not a directory", cmdstr);
1129
1130 return ajFalse;
1131 }
1132
1133 ret = ajSysFileRmrfC(name);
1134
1135 ajStrDel(&cmdstr);
1136
1137 return ret;
1138 }
1139
1140
1141
1142
1143 /* @func ajSysCommandRemovedirS ***********************************************
1144 **
1145 ** Delete a file
1146 **
1147 ** @param [r] strname [const AjPStr] Directory
1148 ** @return [AjBool] True on success
1149 **
1150 **
1151 ** @release 6.3.0
1152 ******************************************************************************/
1153
ajSysCommandRemovedirS(const AjPStr strname)1154 AjBool ajSysCommandRemovedirS(const AjPStr strname)
1155 {
1156 return ajSysCommandRemovedirC(MAJSTRGETPTR(strname));
1157 }
1158
1159
1160
1161
1162 /* @func ajSysCommandRenameC **************************************************
1163 **
1164 ** Rename a file
1165 **
1166 ** @param [r] name [const char*] Source filename
1167 ** @param [r] name2 [const char*] Target filename
1168 ** @return [AjBool] True on success
1169 **
1170 **
1171 ** @release 6.3.0
1172 ******************************************************************************/
1173
ajSysCommandRenameC(const char * name,const char * name2)1174 AjBool ajSysCommandRenameC(const char* name, const char* name2)
1175 {
1176 if(!rename(name, name2))
1177 return ajTrue;
1178
1179 ajErr("File rename failed (%d): %s",
1180 errno, strerror(errno));
1181
1182 return ajFalse;
1183 }
1184
1185
1186
1187
1188 /* @func ajSysCommandRenameS **************************************************
1189 **
1190 ** Rename a file
1191 **
1192 ** @param [r] strname [const AjPStr] Source filename
1193 ** @param [r] strname2 [const AjPStr] Target filename
1194 ** @return [AjBool] True on success
1195 **
1196 **
1197 ** @release 6.3.0
1198 ******************************************************************************/
1199
ajSysCommandRenameS(const AjPStr strname,const AjPStr strname2)1200 AjBool ajSysCommandRenameS(const AjPStr strname, const AjPStr strname2)
1201 {
1202 return ajSysCommandRenameC(MAJSTRGETPTR(strname), MAJSTRGETPTR(strname2));
1203 }
1204
1205
1206
1207
1208 /* @section Wrappers to C functions *******************************************
1209 **
1210 ** Functions for calling or substituting C-functions.
1211 **
1212 ** @fdata [none]
1213 ** @fcategory misc
1214 **
1215 ** @nam3rule Func Replacement for C-function.
1216 ** @nam4rule FuncStrtok strtok that doesn't corrupt the source string
1217 ** @nam5rule FuncStrtokR Reentrant version.
1218 ** @nam4rule FuncFgets An fgets replacement that will cope with Mac OSX
1219 ** files
1220 ** @nam4rule FuncFopen An fopen replacement to cope with cygwin and windows
1221 ** @nam4rule FuncFdopen Calls non-ANSI fdopen.
1222 ** @nam4rule FuncSocket A socket function fore UNIX and Windows
1223 ** @nam4rule FuncStrdup Duplicate BSD strdup function for very strict ANSI
1224 ** @nam3rule System Execute a command line as if from the C shell
1225 ** @nam4rule SystemEnv Execute command line and pass the environment
1226 ** received from main to extract the PATH list
1227 ** @nam4rule SystemOut Execute command line and write standard output to
1228 ** a named file
1229 ** @suffix C Accept C character string parameters
1230 ** @suffix S Accept string object parameters
1231 **
1232 ** @argrule Fdopen filedes [ajint] file descriptor
1233 ** @argrule Fdopen mode [const char*] file mode
1234 ** @argrule Fgets buf [char*] buffer
1235 ** @argrule Fgets size [int] maximum length to read
1236 ** @argrule Fgets fp [FILE*] stream
1237 ** @argrule Fopen name [const char*] Name of file to open
1238 ** @argrule Fopen flags [const char*] Read/write/append flags
1239 ** @argrule Socket domain [int] Domain
1240 ** @argrule Socket type [int] Type
1241 ** @argrule Socket protocol [int] Protocol
1242 ** @argrule Strdup dupstr [const char*] String to duplicate
1243 ** @argrule Strtok srcstr [const char*] source string
1244 ** @argrule Strtok delimstr [const char*] delimiter string
1245 ** @argrule R ptrptr [const char**] Saved pointer
1246 ** @argrule R buf [AjPStr*] Independent buffer provided by caller
1247 ** @argrule System cmdline [const AjPStr] The command line
1248 ** @argrule SystemEnv env [char* const[]] Environment variables and values
1249 ** @argrule SystemOut outfname [const AjPStr] The output file name
1250 **
1251 ** @valrule Fdopen [FILE*] C open file
1252 ** @valrule Fgets [char*] Buffer on success
1253 ** @valrule Fopen [FILE*] C open file
1254 ** @valrule Strdup [char*] New string
1255 ** @valrule Strtok [char*] New string
1256 ** @valrule Socket [SOCKRET] Socketvoid
1257 ** @valrule System [void]
1258 **
1259 ******************************************************************************/
1260
1261
1262
1263
1264 /* @func ajSysFuncFdopen ******************************************************
1265 **
1266 ** Place non-ANSI fdopen here
1267 **
1268 ** @param [r] filedes [ajint] file descriptor
1269 ** @param [r] mode [const char*] file mode
1270 ** @return [FILE*] file pointer
1271 **
1272 ** @release 5.0.0
1273 ** @@
1274 ******************************************************************************/
1275
ajSysFuncFdopen(ajint filedes,const char * mode)1276 FILE* ajSysFuncFdopen(ajint filedes, const char *mode)
1277 {
1278 FILE *ret;
1279
1280 ret = fdopen(filedes,mode);
1281 if(ret)
1282 errno = 0; /* set to "Illegal seek" on some systems */
1283
1284 return ret;
1285 }
1286
1287
1288
1289
1290 /* @func ajSysFuncFgets *******************************************************
1291 **
1292 ** An fgets replacement that will cope with Mac OSX <CR> files
1293 **
1294 ** @param [w] buf [char*] buffer
1295 ** @param [r] size [int] maximum length to read
1296 ** @param [u] fp [FILE*] stream
1297 **
1298 ** @return [char*] buf or NULL
1299 **
1300 ** @release 5.0.0
1301 ** @@
1302 ******************************************************************************/
1303
ajSysFuncFgets(char * buf,int size,FILE * fp)1304 char* ajSysFuncFgets(char *buf, int size, FILE *fp)
1305 {
1306 #ifdef __ppc__
1307 int c = 0;
1308 char *p;
1309 int cnt;
1310
1311 p = buf;
1312 if(!size || size<0)
1313 return NULL;
1314
1315 cnt = 0;
1316
1317 while(cnt!=size-1)
1318 {
1319 c = getc(fp);
1320 if(c==EOF || c=='\r' || c=='\n')
1321 break;
1322 *(p++) = c;
1323 ++cnt;
1324 }
1325
1326
1327 *p ='\0';
1328
1329 if(c==EOF && !cnt)
1330 return NULL;
1331
1332 if(cnt == size-1)
1333 return buf;
1334
1335 if(c=='\r' || c=='\n')
1336 {
1337 if(c=='\r' && cnt<size-2)
1338 {
1339 if((c=getc(fp)) == '\n')
1340 *(p++) = '\r';
1341 else
1342 ungetc(c,fp);
1343 }
1344 *(p++) = '\n';
1345 }
1346
1347 *p = '\0';
1348
1349 return buf;
1350 #else
1351 return fgets(buf,size,fp);
1352 #endif
1353 }
1354
1355
1356
1357
1358 /* @func ajSysFuncFopen *******************************************************
1359 **
1360 ** An fopen replacement to cope with cygwin and windows
1361 **
1362 ** @param [r] name [const char*] file to open
1363 ** @param [r] flags [const char*] r/w/a flags
1364 **
1365 ** @return [FILE*] file or NULL
1366 **
1367 ** @release 5.0.0
1368 ** @@
1369 ******************************************************************************/
1370
ajSysFuncFopen(const char * name,const char * flags)1371 FILE* ajSysFuncFopen(const char *name, const char *flags)
1372 {
1373 FILE *ret = NULL;
1374 #ifdef __CYGWIN__
1375 AjPStr fname = NULL;
1376 #endif
1377
1378 #ifdef __CYGWIN__
1379 if(*(name+1) == ':')
1380 {
1381 fname = ajStrNew();
1382 ajFmtPrintS(&fname,"/cygdrive/%c/%s",*name,name+2);
1383 ret = fopen(ajStrGetPtr(fname),flags);
1384 ajStrDel(&fname);
1385 }
1386 else
1387 ret = fopen(name,flags);
1388 #else
1389 ret = fopen(name,flags);
1390 #endif
1391
1392 return ret;
1393 }
1394
1395
1396
1397
1398 /* @func ajSysFuncSocket ******************************************************
1399 **
1400 ** Socket function coping with UNIX and WIN32
1401 **
1402 ** @param [r] domain [int] Domain
1403 ** @param [r] type [int] Type
1404 ** @param [r] protocol [int] Protocol
1405 ** @return [SOCKRET] Universal (UNIX/WIN32) socket value
1406 **
1407 ** @release 6.3.0
1408 ** @@
1409 ******************************************************************************/
1410
ajSysFuncSocket(int domain,int type,int protocol)1411 SOCKRET ajSysFuncSocket(int domain, int type, int protocol)
1412 {
1413 SOCKRET ret;
1414
1415 #ifndef WIN32
1416 ret = socket(domain, type, protocol);
1417 #else
1418 ret = WSASocket(domain, type, protocol,NULL,0,0);
1419 #endif
1420
1421 return ret;
1422 }
1423
1424
1425
1426
1427 /* @func ajSysFuncStrdup ******************************************************
1428 **
1429 ** Duplicate BSD strdup function for very strict ANSI compilers
1430 **
1431 ** @param [r] dupstr [const char*] string to duplicate
1432 ** @return [char*] Text string as for strdup
1433 **
1434 ** @release 5.0.0
1435 ** @@
1436 ******************************************************************************/
1437
ajSysFuncStrdup(const char * dupstr)1438 char* ajSysFuncStrdup(const char *dupstr)
1439 {
1440 static char *p;
1441
1442 AJCNEW(p, strlen(dupstr)+1);
1443 strcpy(p,dupstr);
1444
1445 return p;
1446 }
1447
1448
1449
1450
1451 /* @func ajSysFuncStrtok ******************************************************
1452 **
1453 ** strtok that doesn't corrupt the source string
1454 **
1455 ** @param [r] srcstr [const char*] source string
1456 ** @param [r] delimstr [const char*] delimiter string
1457 **
1458 ** @return [char*] pointer or NULL when nothing is found
1459 **
1460 ** @release 5.0.0
1461 ** @@
1462 ******************************************************************************/
1463
ajSysFuncStrtok(const char * srcstr,const char * delimstr)1464 char* ajSysFuncStrtok(const char *srcstr, const char *delimstr)
1465 {
1466 ajint len;
1467
1468 if(srcstr)
1469 {
1470 if(!sysTokRets)
1471 {
1472 sysTokSou = ajStrNew();
1473 sysTokRets = ajStrNew();
1474 }
1475 ajStrAssignC(&sysTokSou,srcstr);
1476 sysTokp = ajStrGetPtr(sysTokSou);
1477 }
1478
1479 if(!*sysTokp)
1480 return NULL;
1481
1482 len = strspn(sysTokp,delimstr); /* skip over delimiters */
1483 sysTokp += len;
1484 if(!*sysTokp)
1485 return NULL;
1486
1487 len = strcspn(sysTokp,delimstr); /* count non-delimiters */
1488 ajStrAssignSubC(&sysTokRets,sysTokp,0,len-1);
1489 sysTokp += len; /* skip over first delimiter only */
1490
1491 return ajStrGetuniquePtr(&sysTokRets);
1492 }
1493
1494
1495
1496
1497 /* @func ajSysFuncStrtokR *****************************************************
1498 **
1499 ** Reentrant strtok that doesn't corrupt the source string.
1500 ** This function uses a string buffer provided by the caller.
1501 **
1502 ** @param [u] srcstr [const char*] source string
1503 ** @param [r] delimstr [const char*] delimiter string
1504 ** @param [u] ptrptr [const char**] ptr save
1505 ** @param [w] buf [AjPStr*] result buffer
1506 **
1507 ** @return [char*] pointer or NULL
1508 **
1509 ** @release 5.0.0
1510 ** @@
1511 ******************************************************************************/
1512
ajSysFuncStrtokR(const char * srcstr,const char * delimstr,const char ** ptrptr,AjPStr * buf)1513 char* ajSysFuncStrtokR(const char *srcstr, const char *delimstr,
1514 const char **ptrptr,AjPStr *buf)
1515 {
1516 const char *p;
1517 ajint len;
1518
1519 if(!*buf)
1520 *buf = ajStrNew();
1521
1522 if(srcstr!=NULL)
1523 p = srcstr;
1524 else
1525 p = *ptrptr;
1526
1527 if(!*p)
1528 return NULL;
1529
1530 len = strspn(p,delimstr); /* skip over delimiters */
1531 p += len;
1532 if(!*p)
1533 return NULL;
1534
1535 len = strcspn(p,delimstr); /* count non-delimiters */
1536 ajStrAssignSubC(buf,p,0,len-1);
1537 p += len; /* skip to first delimiter */
1538
1539 *ptrptr = p;
1540
1541 return ajStrGetuniquePtr(buf);
1542 }
1543
1544
1545
1546
1547 /* @section executing commands ************************************************
1548 **
1549 ** Functions for executing commands
1550 **
1551 ** @fdata [none]
1552 ** @fcategory misc
1553 **
1554 ** @nam3rule Exec Execute the equivalent of a command
1555 ** @nam4rule Env Execute under local environment
1556 ** @nam4rule Locale Execute under defined locale
1557 ** @nam4rule Outname Write to output file
1558 ** @nam4rule Redirect Redirect standard input and output
1559 **
1560 ** @suffix Append Append to output file
1561 ** @suffix Err Write standard error to output file
1562 ** @suffix Path Look for progam name in current PATH
1563 ** @suffix C Accept C character string parameters
1564 ** @suffix S Accept string object parameters
1565 **
1566 ** @argrule C cmdlinetxt [const char*] The command line
1567 ** @argrule S cmdline [const AjPStr] The command line
1568 ** @argrule Env env [char* const[]] The environment
1569 ** @argrule LocaleC localetxt [const char*] The locale value
1570 ** @argrule LocaleS localestr [const AjPStr] The locale value
1571 ** @argrule AppendC outfnametxt [const char*] The output file name
1572 ** @argrule AppendS outfname [const AjPStr] The output file name
1573 ** @argrule ErrC outfnametxt [const char*] The output file name
1574 ** @argrule ErrS outfname [const AjPStr] The output file name
1575 ** @argrule OutnameC outfnametxt [const char*] The output file name
1576 ** @argrule OutnameS outfname [const AjPStr] The output file name
1577 ** @argrule Redirect pipeto [int**] pipes to the process
1578 ** @argrule Redirect pipefrom [int**] pipes from the process
1579 **
1580 ** @valrule Exec [ajint] Exit status
1581 ** @valrule *Redirect [AjBool] True on success
1582 **
1583 ******************************************************************************/
1584
1585
1586
1587
1588 /* @func ajSysExecC ***********************************************************
1589 **
1590 ** Exec a command line as if from the C shell
1591 **
1592 ** The exec'd program is passed a new argv array in argptr
1593 **
1594 ** @param [r] cmdlinetxt [const char*] The command line
1595 ** @return [ajint] Exit status
1596 **
1597 ** @release 6.3.0
1598 ** @@
1599 ******************************************************************************/
1600
ajSysExecC(const char * cmdlinetxt)1601 ajint ajSysExecC(const char* cmdlinetxt)
1602 {
1603 #ifndef WIN32
1604 pid_t pid;
1605 pid_t retval;
1606 ajint status = 0;
1607 char *pgm;
1608 char **argptr;
1609 ajint i;
1610
1611 AjPStr pname = NULL;
1612
1613 ajDebug("ajSysExecC '%s'\n", cmdlinetxt);
1614
1615 if(!ajSysArglistBuildC(cmdlinetxt, &pgm, &argptr))
1616 return -1;
1617
1618 pname = ajStrNewC(pgm);
1619
1620 pid=fork();
1621
1622 if(pid==-1)
1623 ajFatal("System fork failed");
1624
1625 if(pid)
1626 {
1627 while((retval=waitpid(pid,&status,0))!=pid)
1628 {
1629 if(retval == -1)
1630 if(errno != EINTR)
1631 break;
1632 }
1633 }
1634 else
1635 {
1636 execv(ajStrGetPtr(pname), argptr);
1637 ajExitAbort(); /* just in case */
1638 }
1639
1640 ajStrDel(&pname);
1641
1642 i = 0;
1643 while(argptr[i])
1644 {
1645 AJFREE(argptr[i]);
1646 ++i;
1647 }
1648 AJFREE(argptr);
1649
1650 AJFREE(pgm);
1651
1652 #else
1653 PROCESS_INFORMATION procInfo;
1654 STARTUPINFO startInfo;
1655 ajint status = 0;
1656
1657 ajDebug ("Launching process '%s'\n", cmdlinetxt);
1658
1659 ZeroMemory(&startInfo, sizeof(startInfo));
1660 startInfo.cb = sizeof(startInfo);
1661
1662 if(!CreateProcess(NULL, (char *)cmdlinetxt, NULL, NULL, FALSE,
1663 CREATE_NO_WINDOW, NULL, NULL, &startInfo, &procInfo))
1664 ajFatal("CreateProcess failed: %s", cmdlinetxt);
1665
1666 if(!WaitForSingleObject(procInfo.hProcess, INFINITE))
1667 status = 0;
1668 else
1669 status = -1;
1670
1671 CloseHandle(procInfo.hProcess);
1672 CloseHandle(procInfo.hThread);
1673
1674 #endif
1675
1676 return status;
1677 }
1678
1679
1680
1681
1682 /* @func ajSysExecS ***********************************************************
1683 **
1684 ** Exec a command line as if from the C shell
1685 **
1686 ** The exec'd program is passed a new argv array in argptr
1687 **
1688 ** @param [r] cmdline [const AjPStr] The command line
1689 ** @return [ajint] Exit status
1690 **
1691 ** @release 6.3.0
1692 ** @@
1693 ******************************************************************************/
1694
ajSysExecS(const AjPStr cmdline)1695 ajint ajSysExecS(const AjPStr cmdline)
1696 {
1697 return ajSysExecC(MAJSTRGETPTR(cmdline));
1698 }
1699
1700
1701
1702
1703 /* @func ajSysExecEnvC ********************************************************
1704 **
1705 ** Exec a command line as if from the C shell
1706 **
1707 ** This routine must be passed the environment received from
1708 ** main(ajint argc, char **argv, char **env)
1709 ** The environment is used to extract the PATH list (see ajWhich)
1710 **
1711 ** Note that the environment is passed through unaltered. The exec'd
1712 ** program is passed a new argv array
1713 **
1714 ** @param [r] cmdlinetxt [const char*] The command line
1715 ** @param [r] env [char* const[]] The environment
1716 ** @return [ajint] Exit status
1717 **
1718 ** @release 6.3.0
1719 ** @@
1720 ******************************************************************************/
1721
ajSysExecEnvC(const char * cmdlinetxt,char * const env[])1722 ajint ajSysExecEnvC(const char* cmdlinetxt, char * const env[])
1723 {
1724 ajint status = 0;
1725
1726 #ifndef WIN32
1727 pid_t pid;
1728 pid_t retval;
1729 char *pgm = NULL;
1730 char **argptr = NULL;
1731 ajint i;
1732
1733 AjPStr pname = NULL;
1734
1735 if(!ajSysArglistBuildC(cmdlinetxt, &pgm, &argptr))
1736 return -1;
1737
1738 pname = ajStrNew();
1739
1740 ajDebug("ajSysSystemEnv '%s' %s \n", pgm, cmdlinetxt);
1741 ajStrAssignC(&pname, pgm);
1742 if(!ajSysFileWhichEnv(&pname, env))
1743 ajFatal("cannot find program '%S'", pname);
1744
1745 ajDebug("ajSysSystemEnv %S = %s\n", pname, cmdlinetxt);
1746 for (i=0;argptr[i]; i++)
1747 {
1748 ajDebug("%4d '%s'\n", i, argptr[i]);
1749 }
1750
1751 pid = fork();
1752 if(pid==-1)
1753 ajFatal("System fork failed");
1754
1755 if(pid)
1756 {
1757 while((retval=waitpid(pid,&status,0))!=pid)
1758 {
1759 if(retval == -1)
1760 if(errno != EINTR)
1761 break;
1762 }
1763 }
1764 else
1765 {
1766 execve(ajStrGetPtr(pname), argptr, env);
1767 ajExitAbort(); /* just in case */
1768 }
1769
1770 ajStrDel(&pname);
1771
1772 i = 0;
1773 while(argptr[i])
1774 {
1775 AJFREE(argptr[i]);
1776 ++i;
1777 }
1778 AJFREE(argptr);
1779
1780 AJFREE(pgm);
1781
1782 #endif
1783
1784 return status;
1785 }
1786
1787
1788
1789
1790 /* @func ajSysExecEnvS ********************************************************
1791 **
1792 ** Exec a command line as if from the C shell
1793 **
1794 ** This routine must be passed the environment received from
1795 ** main(ajint argc, char **argv, char **env)
1796 ** The environment is used to extract the PATH list (see ajWhich)
1797 **
1798 ** Note that the environment is passed through unaltered. The exec'd
1799 ** program is passed a new argv array
1800 **
1801 ** @param [r] cmdline [const AjPStr] The command line
1802 ** @param [r] env [char* const[]] The environment
1803 ** @return [ajint] Exit status
1804 **
1805 ** @release 6.3.0
1806 ** @@
1807 ******************************************************************************/
1808
ajSysExecEnvS(const AjPStr cmdline,char * const env[])1809 ajint ajSysExecEnvS(const AjPStr cmdline, char * const env[])
1810 {
1811 return ajSysExecEnvC(MAJSTRGETPTR(cmdline), env);
1812 }
1813
1814
1815
1816
1817 /* @func ajSysExecLocaleC *****************************************************
1818 **
1819 ** Exec a command line as if from the C shell with a defined locale
1820 ** variable.
1821 **
1822 ** The exec'd program is passed a new argv array in argptr
1823 **
1824 ** @param [r] cmdlinetxt [const char*] The command line
1825 ** @param [r] localetxt [const char*] The locale value
1826 ** @return [ajint] Exit status
1827 **
1828 ** @release 6.3.0
1829 ** @@
1830 ******************************************************************************/
1831
ajSysExecLocaleC(const char * cmdlinetxt,const char * localetxt)1832 ajint ajSysExecLocaleC(const char* cmdlinetxt, const char* localetxt)
1833 {
1834 #ifndef WIN32
1835 pid_t pid;
1836 pid_t retval;
1837 ajint status = 0;
1838 char *pgm;
1839 char **argptr;
1840 ajint i;
1841
1842 AjPStr pname = NULL;
1843
1844 ajDebug("ajSysExecLocaleC '%s' '%s'\n", cmdlinetxt, localetxt);
1845
1846 if(!ajSysArglistBuildC(cmdlinetxt, &pgm, &argptr))
1847 return -1;
1848
1849 pname = ajStrNewC(pgm);
1850
1851 pid=fork();
1852
1853 if(pid==-1)
1854 ajFatal("System fork failed");
1855
1856 if(pid)
1857 {
1858 while((retval=waitpid(pid,&status,0))!=pid)
1859 {
1860 if(retval == -1)
1861 if(errno != EINTR)
1862 break;
1863 }
1864 }
1865 else
1866 {
1867 setlocale(LC_ALL, localetxt);
1868 execv(ajStrGetPtr(pname), argptr);
1869 ajExitAbort(); /* just in case */
1870 }
1871
1872 ajStrDel(&pname);
1873
1874 i = 0;
1875 while(argptr[i])
1876 {
1877 AJFREE(argptr[i]);
1878 ++i;
1879 }
1880 AJFREE(argptr);
1881
1882 AJFREE(pgm);
1883
1884 #else
1885 PROCESS_INFORMATION procInfo;
1886 STARTUPINFO startInfo;
1887 ajint status = 0;
1888
1889 ajDebug ("Launching process '%s'\n", cmdlinetxt);
1890
1891 ZeroMemory(&startInfo, sizeof(startInfo));
1892 startInfo.cb = sizeof(startInfo);
1893
1894 if(!CreateProcess(NULL, (char *)cmdlinetxt, NULL, NULL, FALSE,
1895 CREATE_NO_WINDOW, NULL, NULL, &startInfo, &procInfo))
1896 ajFatal("CreateProcess failed: %s", cmdlinetxt);
1897
1898 if(!WaitForSingleObject(procInfo.hProcess, INFINITE))
1899 status = 0;
1900 else
1901 status = -1;
1902
1903 CloseHandle(procInfo.hProcess);
1904 CloseHandle(procInfo.hThread);
1905
1906 #endif
1907
1908 return status;
1909 }
1910
1911
1912
1913
1914 /* @func ajSysExecLocaleS *****************************************************
1915 **
1916 ** Exec a command line as if from the C shell with a defined locale
1917 ** variable.
1918 **
1919 ** The exec'd program is passed a new argv array in argptr
1920 **
1921 ** @param [r] cmdline [const AjPStr] The command line
1922 ** @param [r] localestr [const AjPStr] The locale value
1923 ** @return [ajint] Exit status
1924 **
1925 ** @release 6.3.0
1926 ** @@
1927 ******************************************************************************/
1928
ajSysExecLocaleS(const AjPStr cmdline,const AjPStr localestr)1929 ajint ajSysExecLocaleS(const AjPStr cmdline, const AjPStr localestr)
1930 {
1931 return ajSysExecLocaleC(MAJSTRGETPTR(cmdline), MAJSTRGETPTR(localestr));
1932 }
1933
1934
1935
1936
1937 /* @func ajSysExecOutnameC ****************************************************
1938 **
1939 ** Exec a command line as if from the C shell with standard output redirected
1940 ** to and overwriting a named file
1941 **
1942 ** The exec'd program is passed a new argv array in argptr
1943 **
1944 ** @param [r] cmdlinetxt [const char*] The command line
1945 ** @param [r] outfnametxt [const char*] The output file name
1946 ** @return [ajint] Exit status
1947 **
1948 ** @release 6.3.0
1949 ** @@
1950 ******************************************************************************/
1951
ajSysExecOutnameC(const char * cmdlinetxt,const char * outfnametxt)1952 ajint ajSysExecOutnameC(const char* cmdlinetxt, const char* outfnametxt)
1953 {
1954 #ifndef WIN32
1955 pid_t pid;
1956 pid_t retval;
1957 ajint status;
1958 char *pgm;
1959 char **argptr;
1960 ajint i;
1961
1962 AjPStr pname = NULL;
1963
1964 if(!ajSysArglistBuildC(cmdlinetxt, &pgm, &argptr))
1965 return -1;
1966
1967 pname = ajStrNew();
1968
1969 ajStrAssignC(&pname, pgm);
1970
1971 if(!ajSysFileWhich(&pname))
1972 ajFatal("cannot find program '%S'", pname);
1973
1974 fflush(stdout);
1975
1976 pid=fork();
1977
1978 if(pid==-1)
1979 ajFatal("System fork failed");
1980
1981 if(pid)
1982 {
1983 while((retval=waitpid(pid,&status,0))!=pid)
1984 {
1985 if(retval == -1)
1986 if(errno != EINTR)
1987 break;
1988 }
1989 }
1990 else
1991 {
1992 /* this is the child process */
1993
1994 if(!freopen(outfnametxt, "wb", stdout))
1995 ajErr("Failed to redirect standard output to '%s'", outfnametxt);
1996 execv(ajStrGetPtr(pname), argptr);
1997 ajExitAbort(); /* just in case */
1998 }
1999
2000 ajStrDel(&pname);
2001
2002 i = 0;
2003 while(argptr[i])
2004 {
2005 AJFREE(argptr[i]);
2006 ++i;
2007 }
2008 AJFREE(argptr);
2009
2010 AJFREE(pgm);
2011
2012 #else
2013
2014 PROCESS_INFORMATION pinf;
2015 STARTUPINFO si;
2016 HANDLE fp;
2017 SECURITY_ATTRIBUTES sa;
2018 ajint status = 0;
2019
2020 ajDebug ("Launching process '%s'\n", cmdlinetxt);
2021
2022 fflush(stdout);
2023
2024 ZeroMemory(&si, sizeof(si));
2025 si.cb = sizeof(si);
2026 si.dwFlags |= STARTF_USESTDHANDLES;
2027
2028
2029 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
2030 sa.bInheritHandle = TRUE;
2031 sa.lpSecurityDescriptor = NULL;
2032
2033 fp = CreateFile(TEXT(outfnametxt), GENERIC_WRITE, 0 , &sa,
2034 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2035
2036 if(fp == INVALID_HANDLE_VALUE)
2037 ajFatal("Cannot open file %s\n",outfnametxt);
2038
2039
2040 si.hStdOutput = fp;
2041 si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
2042 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
2043
2044
2045 if(!CreateProcess(NULL, (char *) cmdlinetxt, NULL, NULL, TRUE,
2046 CREATE_NO_WINDOW, NULL, NULL, &si, &pinf))
2047 {
2048 ajFatal("CreateProcess failed: %s", cmdlinetxt);
2049 }
2050
2051 if(!WaitForSingleObject(pinf.hProcess, INFINITE))
2052 status = 0;
2053 else
2054 status = -1;
2055
2056 CloseHandle(pinf.hProcess);
2057 CloseHandle(pinf.hThread);
2058 #endif
2059
2060 return status;
2061 }
2062
2063
2064
2065
2066 /* @func ajSysExecOutnameS ****************************************************
2067 **
2068 ** Exec a command line as if from the C shell with standard output redirected
2069 ** to and overwriting a named file
2070 **
2071 ** The exec'd program is passed a new argv array in argptr
2072 **
2073 ** @param [r] cmdline [const AjPStr] The command line
2074 ** @param [r] outfname [const AjPStr] The output file name
2075 ** @return [ajint] Exit status
2076 **
2077 ** @release 6.3.0
2078 ** @@
2079 ******************************************************************************/
2080
ajSysExecOutnameS(const AjPStr cmdline,const AjPStr outfname)2081 ajint ajSysExecOutnameS(const AjPStr cmdline, const AjPStr outfname)
2082 {
2083 return ajSysExecOutnameC(MAJSTRGETPTR(cmdline), MAJSTRGETPTR(outfname));
2084 }
2085
2086
2087
2088
2089 /* @func ajSysExecOutnameAppendC **********************************************
2090 **
2091 ** Exec a command line as if from the C shell with standard output redirected
2092 ** and appended to a named file
2093 **
2094 ** The exec'd program is passed a new argv array in argptr
2095 **
2096 ** @param [r] cmdlinetxt [const char*] The command line
2097 ** @param [r] outfnametxt [const char*] The output file name
2098 ** @return [ajint] Exit status
2099 **
2100 ** @release 6.3.0
2101 ** @@
2102 ******************************************************************************/
2103
ajSysExecOutnameAppendC(const char * cmdlinetxt,const char * outfnametxt)2104 ajint ajSysExecOutnameAppendC(const char* cmdlinetxt, const char* outfnametxt)
2105 {
2106 #ifndef WIN32
2107 pid_t pid;
2108 pid_t retval;
2109 ajint status;
2110 char *pgm;
2111 char **argptr;
2112 ajint i;
2113
2114 AjPStr pname = NULL;
2115
2116 if(!ajSysArglistBuildC(cmdlinetxt, &pgm, &argptr))
2117 return -1;
2118
2119 fflush(stdout);
2120
2121 pname = ajStrNew();
2122
2123 ajStrAssignC(&pname, pgm);
2124
2125 if(!ajSysFileWhich(&pname))
2126 ajFatal("cannot find program '%S'", pname);
2127
2128 fflush(stdout);
2129
2130 pid=fork();
2131
2132 if(pid==-1)
2133 ajFatal("System fork failed");
2134
2135 if(pid)
2136 {
2137 while((retval=waitpid(pid,&status,0))!=pid)
2138 {
2139 if(retval == -1)
2140 if(errno != EINTR)
2141 break;
2142 }
2143 }
2144 else
2145 {
2146 /* this is the child process */
2147
2148 if(!freopen(outfnametxt, "ab", stdout))
2149 ajErr("Failed to redirect standard output to '%s'", outfnametxt);
2150 execv(ajStrGetPtr(pname), argptr);
2151 ajExitAbort(); /* just in case */
2152 }
2153
2154 ajStrDel(&pname);
2155
2156 i = 0;
2157 while(argptr[i])
2158 {
2159 AJFREE(argptr[i]);
2160 ++i;
2161 }
2162 AJFREE(argptr);
2163
2164 AJFREE(pgm);
2165
2166 #else
2167
2168 PROCESS_INFORMATION pinf;
2169 STARTUPINFO si;
2170 HANDLE fp;
2171 SECURITY_ATTRIBUTES sa;
2172 ajint status = 0;
2173
2174 ajDebug ("Launching process '%s'\n", cmdlinetxt);
2175
2176 fflush(stdout);
2177
2178 ZeroMemory(&si, sizeof(si));
2179 si.cb = sizeof(si);
2180 si.dwFlags |= STARTF_USESTDHANDLES;
2181
2182
2183 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
2184 sa.bInheritHandle = TRUE;
2185 sa.lpSecurityDescriptor = NULL;
2186
2187 fp = CreateFile(TEXT(outfnametxt), GENERIC_WRITE, 0 , &sa,
2188 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
2189
2190 if(fp == INVALID_HANDLE_VALUE)
2191 ajFatal("Cannot open file %s\n",outfnametxt);
2192
2193 SetFilePointer(fp, 0, NULL, FILE_END);
2194
2195 si.hStdOutput = fp;
2196 si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
2197 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
2198
2199
2200 if(!CreateProcess(NULL, (char *) cmdlinetxt, NULL, NULL, TRUE,
2201 CREATE_NO_WINDOW, NULL, NULL, &si, &pinf))
2202 {
2203 ajFatal("CreateProcess failed: %s", cmdlinetxt);
2204 }
2205
2206 if(!WaitForSingleObject(pinf.hProcess, INFINITE))
2207 status = 0;
2208 else
2209 status = -1;
2210
2211 CloseHandle(pinf.hProcess);
2212 CloseHandle(pinf.hThread);
2213
2214 #endif
2215
2216 return status;
2217 }
2218
2219
2220
2221
2222 /* @func ajSysExecOutnameAppendS **********************************************
2223 **
2224 ** Exec a command line as if from the C shell with standard output redirected
2225 ** and appended to a named file
2226 **
2227 ** The exec'd program is passed a new argv array in argptr
2228 **
2229 ** @param [r] cmdline [const AjPStr] The command line
2230 ** @param [r] outfname [const AjPStr] The output file name
2231 ** @return [ajint] Exit status
2232 **
2233 ** @release 6.3.0
2234 ** @@
2235 ******************************************************************************/
2236
ajSysExecOutnameAppendS(const AjPStr cmdline,const AjPStr outfname)2237 ajint ajSysExecOutnameAppendS(const AjPStr cmdline, const AjPStr outfname)
2238 {
2239 return ajSysExecOutnameAppendC(MAJSTRGETPTR(cmdline),
2240 MAJSTRGETPTR(outfname));
2241 }
2242
2243
2244
2245
2246 /* @func ajSysExecOutnameErrC *************************************************
2247 **
2248 ** Exec a command line as if from the C shell with standard output and
2249 ** standard error redirected to and overwriting a named file
2250 **
2251 ** The exec'd program is passed a new argv array in argptr
2252 **
2253 ** @param [r] cmdlinetxt [const char*] The command line
2254 ** @param [r] outfnametxt [const char*] The output file name
2255 ** @return [ajint] Exit status
2256 **
2257 ** @release 6.3.0
2258 ** @@
2259 ******************************************************************************/
2260
ajSysExecOutnameErrC(const char * cmdlinetxt,const char * outfnametxt)2261 ajint ajSysExecOutnameErrC(const char* cmdlinetxt, const char* outfnametxt)
2262 {
2263 #ifndef WIN32
2264 pid_t pid;
2265 pid_t retval;
2266 ajint status;
2267 char *pgm;
2268 char **argptr;
2269 ajint i;
2270 ajint id;
2271
2272 AjPStr pname = NULL;
2273
2274 if(!ajSysArglistBuildC(cmdlinetxt, &pgm, &argptr))
2275 return -1;
2276
2277 pname = ajStrNew();
2278
2279 ajStrAssignC(&pname, pgm);
2280
2281 if(!ajSysFileWhich(&pname))
2282 ajFatal("cannot find program '%S'", pname);
2283
2284 fflush(stdout);
2285 fflush(stderr);
2286
2287 pid=fork();
2288
2289 if(pid==-1)
2290 ajFatal("System fork failed");
2291
2292 if(pid)
2293 {
2294 while((retval=waitpid(pid,&status,0))!=pid)
2295 {
2296 if(retval == -1)
2297 if(errno != EINTR)
2298 break;
2299 }
2300 }
2301 else
2302 {
2303 /* this is the child process */
2304
2305 if(!freopen(outfnametxt, "wb", stdout))
2306 ajErr("Failed to redirect standard output to '%s'", outfnametxt);
2307 close(STDERR_FILENO);
2308 id = dup(fileno(stdout));
2309 if(id < 0)
2310 ajErr("Failed to duplicate file descriptor stdout, error:%d %s",
2311 errno, strerror(errno));
2312 execv(ajStrGetPtr(pname), argptr);
2313 ajExitAbort(); /* just in case */
2314 }
2315
2316 ajStrDel(&pname);
2317
2318 i = 0;
2319 while(argptr[i])
2320 {
2321 AJFREE(argptr[i]);
2322 ++i;
2323 }
2324 AJFREE(argptr);
2325
2326 AJFREE(pgm);
2327
2328 #else
2329
2330 PROCESS_INFORMATION pinf;
2331 STARTUPINFO si;
2332 HANDLE fp;
2333 SECURITY_ATTRIBUTES sa;
2334 ajint status = 0;
2335
2336 ajDebug ("Launching process '%s'\n", cmdlinetxt);
2337
2338 fflush(stdout);
2339 fflush(stderr);
2340
2341 ZeroMemory(&si, sizeof(si));
2342 si.cb = sizeof(si);
2343 si.dwFlags |= STARTF_USESTDHANDLES;
2344
2345
2346 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
2347 sa.bInheritHandle = TRUE;
2348 sa.lpSecurityDescriptor = NULL;
2349
2350 fp = CreateFile(TEXT(outfnametxt), GENERIC_WRITE, 0 , &sa,
2351 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2352
2353 if(fp == INVALID_HANDLE_VALUE)
2354 ajFatal("Cannot open file %s\n",outfnametxt);
2355
2356
2357 si.hStdOutput = fp;
2358 si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
2359 si.hStdError = fp;
2360
2361
2362 if(!CreateProcess(NULL, (char *) cmdlinetxt, NULL, NULL, TRUE,
2363 CREATE_NO_WINDOW, NULL, NULL, &si, &pinf))
2364 {
2365 ajFatal("CreateProcess failed: %s", cmdlinetxt);
2366 }
2367
2368 if(!WaitForSingleObject(pinf.hProcess, INFINITE))
2369 status = 0;
2370 else
2371 status = -1;
2372
2373 CloseHandle(pinf.hProcess);
2374 CloseHandle(pinf.hThread);
2375 #endif
2376
2377 return status;
2378 }
2379
2380
2381
2382
2383 /* @func ajSysExecOutnameErrS *************************************************
2384 **
2385 ** Exec a command line as if from the C shell with standard output and
2386 ** standard error redirected to and overwriting a named file
2387 **
2388 ** The exec'd program is passed a new argv array in argptr
2389 **
2390 ** @param [r] cmdline [const AjPStr] The command line
2391 ** @param [r] outfname [const AjPStr] The output file name
2392 ** @return [ajint] Exit status
2393 **
2394 ** @release 6.3.0
2395 ** @@
2396 ******************************************************************************/
2397
ajSysExecOutnameErrS(const AjPStr cmdline,const AjPStr outfname)2398 ajint ajSysExecOutnameErrS(const AjPStr cmdline, const AjPStr outfname)
2399 {
2400 return ajSysExecOutnameErrC(MAJSTRGETPTR(cmdline), MAJSTRGETPTR(outfname));
2401 }
2402
2403
2404
2405
2406 /* @func ajSysExecOutnameErrAppendC *******************************************
2407 **
2408 ** Exec a command line as if from the C shell with standard output and
2409 ** standard error redirected and appended to a named file
2410 **
2411 ** The exec'd program is passed a new argv array in argptr
2412 **
2413 ** @param [r] cmdlinetxt [const char*] The command line
2414 ** @param [r] outfnametxt [const char*] The output file name
2415 ** @return [ajint] Exit status
2416 **
2417 ** @release 6.3.0
2418 ** @@
2419 ******************************************************************************/
2420
ajSysExecOutnameErrAppendC(const char * cmdlinetxt,const char * outfnametxt)2421 ajint ajSysExecOutnameErrAppendC(const char* cmdlinetxt,
2422 const char* outfnametxt)
2423 {
2424 #ifndef WIN32
2425 pid_t pid;
2426 pid_t retval;
2427 ajint status = 0;
2428 char *pgm;
2429 char **argptr;
2430 ajint i;
2431 int id;
2432
2433 AjPStr pname = NULL;
2434
2435 if(!ajSysArglistBuildC(cmdlinetxt, &pgm, &argptr))
2436 return -1;
2437
2438 pname = ajStrNew();
2439
2440 ajStrAssignC(&pname, pgm);
2441
2442 if(!ajSysFileWhich(&pname))
2443 ajFatal("cannot find program '%S'", pname);
2444
2445 fflush(stdout);
2446
2447 pid=fork();
2448
2449 if(pid==-1)
2450 ajFatal("System fork failed");
2451
2452 if(pid)
2453 {
2454 while((retval=waitpid(pid,&status,0))!=pid)
2455 {
2456 if(retval == -1)
2457 if(errno != EINTR)
2458 break;
2459 }
2460 }
2461 else
2462 {
2463 /* this is the child process */
2464
2465 if(!freopen(outfnametxt, "ab", stdout))
2466 ajErr("Failed to redirect standard output and error to '%s'",
2467 outfnametxt);
2468 close(STDERR_FILENO);
2469 id = dup(fileno(stdout));
2470 if(id < 0)
2471 ajErr("Failed to duplicate file descriptor stdout, error:%d %s",
2472 errno, strerror(errno));
2473 execv(ajStrGetPtr(pname), argptr);
2474 ajExitAbort(); /* just in case */
2475 }
2476
2477 ajStrDel(&pname);
2478
2479 i = 0;
2480 while(argptr[i])
2481 {
2482 AJFREE(argptr[i]);
2483 ++i;
2484 }
2485 AJFREE(argptr);
2486
2487 AJFREE(pgm);
2488
2489 #else
2490
2491 PROCESS_INFORMATION pinf;
2492 STARTUPINFO si;
2493 HANDLE fp;
2494 SECURITY_ATTRIBUTES sa;
2495 ajint status = -1;
2496
2497 ajDebug ("Launching process '%s'\n", cmdlinetxt);
2498
2499 ZeroMemory(&si, sizeof(si));
2500 si.cb = sizeof(si);
2501 si.dwFlags |= STARTF_USESTDHANDLES;
2502
2503
2504 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
2505 sa.bInheritHandle = TRUE;
2506 sa.lpSecurityDescriptor = NULL;
2507
2508 fp = CreateFile(TEXT(outfnametxt), GENERIC_WRITE, 0 , &sa,
2509 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
2510
2511 if(fp == INVALID_HANDLE_VALUE)
2512 ajFatal("Cannot open file %s\n",outfnametxt);
2513
2514 SetFilePointer(fp, 0, NULL, FILE_END);
2515
2516 si.hStdOutput = fp;
2517 si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
2518 si.hStdError = fp;
2519
2520
2521 if(!CreateProcess(NULL, (char *) cmdlinetxt, NULL, NULL, TRUE,
2522 CREATE_NO_WINDOW, NULL, NULL, &si, &pinf))
2523 {
2524 ajFatal("CreateProcess failed: %s", cmdlinetxt);
2525 }
2526
2527 if(!WaitForSingleObject(pinf.hProcess, INFINITE))
2528 status = 0;
2529 else
2530 status = -1;
2531
2532 CloseHandle(pinf.hProcess);
2533 CloseHandle(pinf.hThread);
2534 #endif
2535
2536 return status;
2537 }
2538
2539
2540
2541
2542 /* @func ajSysExecOutnameErrAppendS *******************************************
2543 **
2544 ** Exec a command line as if from the C shell with standard output and
2545 ** standard error redirected and appended to a named file
2546 **
2547 ** The exec'd program is passed a new argv array in argptr
2548 **
2549 ** @param [r] cmdline [const AjPStr] The command line
2550 ** @param [r] outfname [const AjPStr] The output file name
2551 ** @return [ajint] Exit status
2552 **
2553 ** @release 6.3.0
2554 ** @@
2555 ******************************************************************************/
2556
ajSysExecOutnameErrAppendS(const AjPStr cmdline,const AjPStr outfname)2557 ajint ajSysExecOutnameErrAppendS(const AjPStr cmdline, const AjPStr outfname)
2558 {
2559 return ajSysExecOutnameErrAppendC(MAJSTRGETPTR(cmdline),
2560 MAJSTRGETPTR(outfname));
2561 }
2562
2563
2564
2565
2566 /* @func ajSysExecPathC *******************************************************
2567 **
2568 ** Exec a command line with a test for the program name in the current path
2569 **
2570 ** The exec'd program is passed a new argv array in argptr
2571 **
2572 ** @param [r] cmdlinetxt [const char*] The command line
2573 ** @return [ajint] Exit status
2574 **
2575 ** @release 6.3.0
2576 ** @@
2577 ******************************************************************************/
2578
ajSysExecPathC(const char * cmdlinetxt)2579 ajint ajSysExecPathC(const char* cmdlinetxt)
2580 {
2581 #ifndef WIN32
2582 pid_t pid;
2583 pid_t retval;
2584 ajint status = 0;
2585 char *pgm;
2586 char **argptr;
2587 ajint i;
2588
2589 AjPStr pname = NULL;
2590
2591 ajDebug("ajSysExecPathS '%s'\n", cmdlinetxt);
2592
2593 if(!ajSysArglistBuildC(cmdlinetxt, &pgm, &argptr))
2594 return -1;
2595
2596 pname = ajStrNewC(pgm);
2597
2598 pid=fork();
2599
2600 if(pid==-1)
2601 ajFatal("System fork failed");
2602
2603 if(pid)
2604 {
2605 while((retval=waitpid(pid,&status,0))!=pid)
2606 {
2607 if(retval == -1)
2608 if(errno != EINTR)
2609 break;
2610 }
2611 }
2612 else
2613 {
2614 execvp(ajStrGetPtr(pname), argptr);
2615 ajExitAbort(); /* just in case */
2616 }
2617
2618 ajStrDel(&pname);
2619
2620 i = 0;
2621 while(argptr[i])
2622 {
2623 AJFREE(argptr[i]);
2624 ++i;
2625 }
2626 AJFREE(argptr);
2627
2628 AJFREE(pgm);
2629
2630 #else
2631 PROCESS_INFORMATION procInfo;
2632 STARTUPINFO startInfo;
2633 ajint status = 0;
2634
2635 ajDebug ("Launching process '%s'\n", cmdlinetxt);
2636
2637 ZeroMemory(&startInfo, sizeof(startInfo));
2638 startInfo.cb = sizeof(startInfo);
2639
2640 if (!CreateProcess(NULL, (char *)cmdlinetxt, NULL, NULL, FALSE,
2641 CREATE_NO_WINDOW, NULL, NULL, &startInfo, &procInfo))
2642 ajFatal("CreateProcess failed: %s", cmdlinetxt);
2643
2644 if(!WaitForSingleObject(procInfo.hProcess, INFINITE))
2645 status = 0;
2646 else
2647 status = -1;
2648
2649 #endif
2650
2651 return status;
2652 }
2653
2654
2655
2656
2657 /* @func ajSysExecPathS *******************************************************
2658 **
2659 ** Exec a command line with a test for the program name in the current path
2660 **
2661 ** The exec'd program is passed a new argv array in argptr
2662 **
2663 ** @param [r] cmdline [const AjPStr] The command line
2664 ** @return [ajint] Exit status
2665 **
2666 ** @release 6.3.0
2667 ** @@
2668 ******************************************************************************/
2669
ajSysExecPathS(const AjPStr cmdline)2670 ajint ajSysExecPathS(const AjPStr cmdline)
2671 {
2672 return ajSysExecPathC(MAJSTRGETPTR(cmdline));
2673 }
2674
2675
2676
2677
2678 /* @func ajSysExecRedirectC ***************************************************
2679 **
2680 ** Execute an application redirecting its stdin/out to pipe fds
2681 **
2682 ** @param [r] cmdlinetxt [const char*] Command string.
2683 ** The string may end with a trailing pipe character.
2684 ** @param [w] pipeto [int**] pipes to the process
2685 ** @param [w] pipefrom [int**] pipes from the process
2686 ** @return [AjBool] True on success
2687 **
2688 ** @release 6.3.0
2689 ** @@
2690 ******************************************************************************/
2691
ajSysExecRedirectC(const char * cmdlinetxt,int ** pipeto,int ** pipefrom)2692 AjBool ajSysExecRedirectC(const char *cmdlinetxt, int **pipeto, int **pipefrom)
2693 {
2694 int *pipeout = NULL;
2695 int *pipein = NULL;
2696 #ifndef WIN32
2697 pid_t pid;
2698 char *pgm = NULL;
2699 char **argptr = NULL;
2700 ajint i;
2701 #else
2702 HANDLE cstdinr;
2703 HANDLE cstdinw;
2704 HANDLE cstdoutr;
2705 HANDLE cstdoutw;
2706 HANDLE svstdin;
2707 HANDLE svstdout;
2708 BOOL ret;
2709
2710 HANDLE cstdinwdup;
2711 HANDLE cstdoutrdup;
2712
2713 SECURITY_ATTRIBUTES sa;
2714
2715 PROCESS_INFORMATION pinf;
2716 STARTUPINFO sinf;
2717 #endif
2718
2719 if(!pipeto || !pipefrom)
2720 return ajFalse;
2721
2722 if(!*pipeto || !*pipefrom)
2723 return ajFalse;
2724
2725 pipeout = *pipeto;
2726 pipein = *pipefrom;
2727
2728 #ifndef WIN32
2729
2730 if(!ajSysArglistBuildC(cmdlinetxt, &pgm, &argptr))
2731 {
2732 ajDebug("ajSysExecWithRedirect: Cannot parse command line");
2733 return ajFalse;
2734 }
2735
2736
2737 if(pipe(pipeout))
2738 {
2739 ajDebug("ajSysExecRedirectC: Cannot open pipeout");
2740 return ajFalse;
2741 }
2742
2743 if(pipe(pipein))
2744 {
2745 ajDebug("ajSysExecRedirectC: Cannot open pipein");
2746 return ajFalse;
2747 }
2748
2749 pid = fork();
2750 if(pid < 0)
2751 {
2752 ajDebug("ajSysExecRedirectC: fork failure");
2753 return ajFalse;
2754 }
2755 else if(!pid)
2756 {
2757 /*
2758 ** CHILD PROCESS
2759 ** dup pipe read/write to stdin/stdout
2760 */
2761 dup2(pipeout[0], fileno(stdin));
2762 dup2(pipein[1], fileno(stdout));
2763
2764 /* close unnecessary pipe descriptors */
2765 close(pipeout[0]);
2766 close(pipeout[1]);
2767 close(pipein[0]);
2768 close(pipein[1]);
2769
2770 execv(pgm, argptr);
2771
2772 ajDebug("ajSysExecRedirectC: Problem executing application");
2773 return ajFalse;
2774 }
2775
2776 /*
2777 ** PARENT PROCESS
2778 ** Close unused pipe ends. This is especially important for the
2779 ** pipein[1] write descriptor, otherwise reading will never
2780 ** give an EOF.
2781 */
2782
2783 ajDebug("ajSysExecRedirectC: Within the PARENT process");
2784
2785 close(pipeout[0]);
2786 close(pipein[1]);
2787
2788 i = 0;
2789
2790 while(argptr[i])
2791 {
2792 AJFREE(argptr[i]);
2793 ++i;
2794 }
2795
2796 AJFREE(argptr);
2797 AJFREE(pgm);
2798
2799 #else /* WIN32 */
2800
2801
2802 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
2803 sa.bInheritHandle = TRUE;
2804 sa.lpSecurityDescriptor = NULL;
2805
2806 /*
2807 ** Redirect stdout by
2808 ** Save stdout for later restoration
2809 ** Create anonymous pipe as stdout for the child
2810 ** Set stdout of parent to be write handle to the pipe thereby
2811 ** making it inherited by the child
2812 ** Create non-inheritable duplicate of the read handle and close
2813 ** the inheritable read handle
2814 */
2815
2816 svstdout = GetStdHandle(STD_OUTPUT_HANDLE);
2817
2818 if (!CreatePipe(&cstdoutr, &cstdoutw, &sa, 0))
2819 {
2820 ajDebug("ajSysExecRedirectC: Couldn't open input pipe" );
2821 return ajFalse;
2822 }
2823
2824 SetHandleInformation(cstdoutr,HANDLE_FLAG_INHERIT,0);
2825
2826 if (!SetStdHandle(STD_OUTPUT_HANDLE, cstdoutw))
2827 {
2828 ajDebug("ajSysExecRedirectC: failure redirecting stdout");
2829 return ajFalse;
2830 }
2831
2832 ret = DuplicateHandle(GetCurrentProcess(),
2833 cstdoutr,
2834 GetCurrentProcess(),
2835 &cstdoutrdup , 0,
2836 FALSE,
2837 DUPLICATE_SAME_ACCESS);
2838 if(!ret)
2839 {
2840 ajDebug("ajSysExecRedirectC: DuplicateHandle failed");
2841 return ajFalse;
2842 }
2843
2844 CloseHandle(cstdoutr);
2845
2846 /*
2847 ** Redirect stdin by
2848 ** Save stdin for later restoration
2849 ** Create anonymous pipe as stdin for the child
2850 ** Set stdin of parent to be read handle of the pipe thereby
2851 ** making it inherited by the child
2852 ** Create non-inheritable duplicate of the write handle and close
2853 ** the inheritable write handle
2854 */
2855
2856 svstdin = GetStdHandle(STD_INPUT_HANDLE);
2857
2858 if(!CreatePipe(&cstdinr, &cstdinw, &sa, 0))
2859 {
2860 ajDebug("ajSysExecRedirectC: Cannot open pipeout");
2861 return ajFalse;
2862 }
2863
2864 if (!SetStdHandle(STD_INPUT_HANDLE, cstdinr))
2865 {
2866 ajDebug("ajSysExecRedirectC: Cannot redirect stdin");
2867 return ajFalse;
2868 }
2869
2870 ret = DuplicateHandle(GetCurrentProcess(),
2871 cstdinw,
2872 GetCurrentProcess(),
2873 &cstdinwdup, 0,
2874 FALSE,
2875 DUPLICATE_SAME_ACCESS);
2876 if(!ret)
2877 {
2878 ajDebug("ajSysExecRedirectC: DuplicateHandle failure");
2879 return ajFalse;
2880 }
2881
2882 CloseHandle(cstdinw);
2883
2884 ZeroMemory(&pinf, sizeof(PROCESS_INFORMATION));
2885 ZeroMemory(&sinf, sizeof(STARTUPINFO));
2886 sinf.cb = sizeof(STARTUPINFO);
2887
2888 ret = CreateProcess(NULL, (char *)cmdlinetxt, NULL, NULL, TRUE, 0,
2889 NULL, NULL, &sinf, &pinf);
2890
2891 if(ret == 0)
2892 {
2893 ajDebug("ajSysExecRedirectC: Cannot execute application: %s",
2894 cmdlinetxt);
2895 return ajFalse;
2896 }
2897
2898 CloseHandle(pinf.hProcess);
2899 CloseHandle(pinf.hThread);
2900
2901
2902 if(!SetStdHandle(STD_INPUT_HANDLE, svstdin))
2903 {
2904 ajDebug("ajSysExecRedirectC: Error restoring stdin");
2905 return ajFalse;
2906 }
2907
2908 if(!SetStdHandle(STD_OUTPUT_HANDLE, svstdout))
2909 {
2910 ajDebug("ajSysExecRedirectC: Error restoring stdout");
2911 return ajFalse;
2912 }
2913
2914 CloseHandle(cstdoutw);
2915
2916 pipeout[1] = _open_osfhandle((intptr_t) cstdinwdup,
2917 _O_APPEND);
2918
2919 pipein[0] = _open_osfhandle((intptr_t) cstdoutrdup,
2920 _O_RDONLY);
2921 #endif
2922
2923 return ajTrue;
2924 }
2925
2926
2927
2928
2929 /* @section executing programs ************************************************
2930 **
2931 ** Functions for executing programs
2932 **
2933 ** @fdata [none]
2934 ** @fcategory misc
2935 **
2936 ** @nam3rule Execprog Execute a progfam
2937 ** @suffix Nowait No parent wait
2938 ** @suffix C Accept C character string parameters
2939 ** @suffix S Accept string object parameters
2940 **
2941 ** @argrule C prog [const char*] The program name
2942 ** @argrule S progstr [const AjPStr] The program name
2943 ** @argrule * arg [char* const[]] Argument list
2944 ** @argrule * env [char* const[]] An environment list
2945 **
2946 ** @valrule Execprog [ajint] Exit status
2947 **
2948 ******************************************************************************/
2949
2950
2951
2952
2953 /* @func ajSysExecprogNowaitC *************************************************
2954 **
2955 ** Exec a command line with no parent wait
2956 **
2957 ** This routine must be passed a program, an argument list and an environment.
2958 ** The wait handling is performed by user-supplied parent process code and
2959 ** is therefore used by the Java Native Interface software.
2960 **
2961 ** @param [r] prog[const char*] The command line
2962 ** @param [r] arg [char* const[]] Argument list
2963 ** @param [r] env [char* const[]] An environment
2964 ** @return [ajint] Exit status
2965 **
2966 ** @release 6.4.0
2967 ** @@
2968 ******************************************************************************/
2969
ajSysExecprogNowaitC(const char * prog,char * const arg[],char * const env[])2970 ajint ajSysExecprogNowaitC(const char *prog, char * const arg[],
2971 char * const env[])
2972 {
2973 #ifndef WIN32
2974 if(execve(prog,arg,env) == -1)
2975 ajFatal("ajSysExecProgArgEnvNowaitC: Cannot exec application %s",
2976 prog);
2977 #endif
2978
2979 return 0;
2980 }
2981
2982
2983
2984
2985 /* @func ajSysExecprogNowaitS *************************************************
2986 **
2987 ** Exec a command line with no parent wait
2988 **
2989 ** This routine must be passed a program, an argument list and an environment.
2990 ** The wait handling is performed by user-supplied parent process code and
2991 ** is therefore used by the Java Native Interface software.
2992 **
2993 ** @param [r] progstr [const AjPStr] The command line
2994 ** @param [r] arg [char* const[]] Argument list
2995 ** @param [r] env [char* const[]] An environment
2996 ** @return [ajint] Exit status
2997 **
2998 ** @release 6.4.0
2999 ** @@
3000 ******************************************************************************/
3001
ajSysExecprogNowaitS(const AjPStr progstr,char * const arg[],char * const env[])3002 ajint ajSysExecprogNowaitS(const AjPStr progstr, char * const arg[],
3003 char * const env[])
3004 {
3005 return ajSysExecprogNowaitC(MAJSTRGETPTR(progstr), arg, env);
3006 }
3007
3008
3009
3010
3011 /* @section Miscellaneous system functions ************************************
3012 **
3013 ** Miscellaneous system functions
3014 **
3015 ** @fdata [none]
3016 ** @fcategory misc
3017 **
3018 ** @nam3rule Canon Sets or unsets TTY canonical mode
3019 ** @nam3rule Socketclose Closes a UNIX or WIN32 socket
3020 ** @nam3rule Fd Gets file descriptor
3021 ** @nam4rule FdFrom Gets file descriptor from object
3022 ** @nam5rule FdFromSocket Gets file descriptor from open socket
3023 ** @nam3rule Exit Cleans up system internals memory
3024 ** @nam3rule Timeout Control alarm abort timeouts
3025 ** @nam4rule TimeoutSet Set a timeout
3026 ** @nam4rule TimeoutUnset Unset a timeout
3027 **
3028 ** @argrule Canon state [AjBool] Canonical mode set if true
3029 ** @argrule FdFromSocket sock [const AjOSysSocket] AJAX socket structure
3030 ** @argrule FdFromSocket mode [const char*] Opening mode ("r" or "a")
3031 ** @argrule Socketclose sock [AjOSysSocket] AJAX socket structure
3032 ** @argrule Timeout ts [AjPSysTimeout] AJAX timeout structure
3033 **
3034 ** @valrule * [void]
3035 ** @valrule *FdFromSocket [FILE*] File descriptor
3036 ** @valrule *Timeout [int] Exit code (-1 for error, 0 =for success)
3037 **
3038 ******************************************************************************/
3039
3040
3041
3042
3043 /* @func ajSysCanon **********************************************************
3044 **
3045 ** Sets or unsets TTY canonical mode
3046 **
3047 ** @param [r] state [AjBool] state=true sets canon state=false sets noncanon
3048 ** @return [void]
3049 **
3050 ** @release 1.0.0
3051 ** @@
3052 ******************************************************************************/
3053
ajSysCanon(AjBool state)3054 void ajSysCanon(AjBool state)
3055 {
3056 #ifndef WIN32
3057 #ifndef __VMS
3058 static struct termios tty;
3059
3060
3061 tcgetattr(1, &tty);
3062 tty.c_cc[VMIN] = '\1';
3063 tty.c_cc[VTIME] = '\0';
3064 tcsetattr(1,TCSANOW,&tty);
3065
3066 if(state)
3067 tty.c_lflag |= ICANON;
3068 else
3069 tty.c_lflag &= ~(ICANON);
3070
3071 tcsetattr(1, TCSANOW, &tty);
3072 #endif
3073 #endif
3074 return;
3075 }
3076
3077
3078
3079
3080 /* @func ajSysFdFromSocket ***************************************************
3081 **
3082 ** Return a file descriptor from a UNIX of Windows socket
3083 **
3084 ** @param [r] sock [const AjOSysSocket] AJAX socket structure
3085 ** @param [r] mode [const char*] Opening mode ("r" or "a")
3086 ** @return [FILE*] File descriptor
3087 **
3088 ** @release 6.3.0
3089 ** @@
3090 ******************************************************************************/
3091
ajSysFdFromSocket(const AjOSysSocket sock,const char * mode)3092 FILE* ajSysFdFromSocket(const AjOSysSocket sock, const char *mode)
3093 {
3094 FILE *ret;
3095 #ifdef WIN32
3096 int fd;
3097 int flags = 0;
3098 char c;
3099
3100 #endif
3101
3102 if(!mode)
3103 return NULL;
3104
3105 #ifndef WIN32
3106 ret = ajSysFuncFdopen(sock.sock,mode);
3107 #else
3108 c = *mode;
3109
3110 switch(c)
3111 {
3112 case 'r':
3113 flags = _O_RDONLY;
3114 break;
3115 case 'a':
3116 flags = _O_APPEND;
3117 break;
3118 default:
3119 ajErr("ajSysFdFromSocket: Illegal mode [%c]",c);
3120 break;
3121 }
3122
3123 fd = _open_osfhandle(sock.sock, _O_RDONLY);
3124 ret = ajSysFuncFdopen(fd,mode);
3125 #endif
3126
3127 return ret;
3128 }
3129
3130
3131
3132
3133 /* @func ajSysSocketclose ****************************************************
3134 **
3135 ** Closes a UNIX or WIN32 socket
3136 **
3137 ** @param [u] sock [AjOSysSocket] AJAX socket structure
3138 ** @return [void]
3139 **
3140 ** @release 6.3.0
3141 ** @@
3142 ******************************************************************************/
3143
ajSysSocketclose(AjOSysSocket sock)3144 void ajSysSocketclose(AjOSysSocket sock)
3145 {
3146 #ifndef WIN32
3147 close(sock.sock);
3148 #else
3149 closesocket(sock.sock);
3150 #endif
3151
3152 return;
3153 }
3154
3155
3156
3157
3158 /* @func ajSysTimeoutSet ******************************************************
3159 **
3160 ** Sets an alarm abort timeout for UNIX and Windows
3161 **
3162 ** @param [u] ts [AjPSysTimeout] AJAX timeout structure
3163 ** @return [int] 0 = success -1 = error
3164 **
3165 ** @release 6.3.0
3166 ** @@
3167 ******************************************************************************/
3168
ajSysTimeoutSet(AjPSysTimeout ts)3169 int ajSysTimeoutSet(AjPSysTimeout ts)
3170 {
3171 int ret = 0;
3172
3173 #ifndef WIN32
3174 sigemptyset( &ts->sa.sa_mask );
3175 ts->sa.sa_flags = 0;
3176 ts->sa.sa_handler = sysTimeoutAbort;
3177 ret = sigaction( SIGALRM, &ts->sa, NULL );
3178
3179 alarm(ts->seconds);
3180 #else
3181 PTIMERAPCROUTINE ptim = NULL;
3182
3183 ts->wtime.QuadPart = -10000000LL;
3184 ts->wtime.QuadPart *= ts->seconds;
3185
3186 ts->thandle = CreateWaitableTimer(NULL, TRUE, NULL);
3187 if(!ts->thandle)
3188 return -1;
3189
3190 ptim = (PTIMERAPCROUTINE) sysTimeoutAbort;
3191
3192 if (!SetWaitableTimer(ts->thandle, &ts->wtime, 0, ptim, NULL, 0))
3193 ret = -1;
3194
3195 #endif
3196
3197 return ret;
3198 }
3199
3200
3201
3202
3203 /* @func ajSysTimeoutUnset ****************************************************
3204 **
3205 ** Unsets an alarm abort timeout for UNIX and Windows
3206 **
3207 ** @param [u] ts [AjPSysTimeout] AJAX timeout structure
3208 ** @return [int] 0 = success -1 = error
3209 **
3210 ** @release 6.3.0
3211 ** @@
3212 ******************************************************************************/
3213
ajSysTimeoutUnset(AjPSysTimeout ts)3214 int ajSysTimeoutUnset(AjPSysTimeout ts)
3215 {
3216 int ret = 0;
3217
3218 #ifndef WIN32
3219 ret = sigemptyset(&ts->sa.sa_mask);
3220
3221 alarm(0);
3222 #else
3223 if(!CancelWaitableTimer(ts->thandle))
3224 return -1;
3225
3226 if(!CloseHandle(ts->thandle))
3227 ret = -1;
3228 #endif
3229
3230 return ret;
3231 }
3232
3233
3234
3235
3236 #ifndef WIN32
3237 /* @funcstatic sysTimeoutAbort ************************************************
3238 **
3239 ** Fatal error if a socket read hangs
3240 **
3241 ** @param [r] sig [int] Signal code - always SIGALRM but required by the
3242 ** signal call
3243 ** @return [void]
3244 **
3245 ** @release 6.3.0
3246 ** @@
3247 ******************************************************************************/
sysTimeoutAbort(int sig)3248 static void sysTimeoutAbort(int sig)
3249 {
3250 (void) sig;
3251
3252 ajDie("Alarm timeout");
3253
3254 return;
3255 }
3256 #else
sysTimeoutAbort(LPVOID arg,DWORD low,DWORD high)3257 static void CALLBACK sysTimeoutAbort(LPVOID arg, DWORD low, DWORD high)
3258 {
3259 (void) arg;
3260 (void) low;
3261 (void) high;
3262
3263 ajDie("Timer timeout");
3264
3265 return;
3266 }
3267 #endif
3268
3269
3270
3271
3272 /* @section piped commands ****************************************************
3273 **
3274 ** system command lines piped to a file
3275 **
3276 ** @fdata [none]
3277 ** @fcategory misc
3278 **
3279 ** @nam3rule Create Create a new input
3280 ** @nam4rule Inpipe Create a new input
3281 **
3282 ** @suffix C C character string arguments
3283 ** @suffix S String object arguments
3284 **
3285 ** @argrule C cmdlinetxt [const char*] Command line
3286 ** @argrule S command [const AjPStr] Command line
3287 ** @valrule *Inpipe [AjPFile]
3288 **
3289 ******************************************************************************/
3290
3291
3292
3293
3294 /* @func ajSysCreateInpipeC ***************************************************
3295 **
3296 ** Return a new file object from which to read the output from a command.
3297 **
3298 ** @param [r] cmdlinetxt [const char*] Command string.
3299 ** The string may end with a trailing pipe character.
3300 ** @return [AjPFile] New file object.
3301 **
3302 ** @release 6.3.0
3303 ** @@
3304 ******************************************************************************/
3305
ajSysCreateInpipeC(const char * cmdlinetxt)3306 AjPFile ajSysCreateInpipeC(const char* cmdlinetxt)
3307 {
3308 AjPFile thys;
3309 AjPStr cmdstr = NULL;
3310
3311 #ifndef WIN32
3312 ajint pipefds[2]; /* file descriptors for a pipe */
3313 char** arglist = NULL;
3314 char* pgm;
3315 #else
3316 HANDLE cstdinr = NULL;
3317 HANDLE cstdinw = NULL;
3318 HANDLE cstdoutr = NULL;
3319 HANDLE cstdoutw = NULL;
3320 HANDLE svstdout = NULL;
3321 HANDLE cstdoutrdup = NULL;
3322
3323 SECURITY_ATTRIBUTES sa;
3324
3325 PROCESS_INFORMATION pinf;
3326 STARTUPINFO sinf;
3327
3328 BOOL ret = FALSE;
3329
3330 int fd;
3331 #endif
3332
3333 cmdstr = ajStrNew();
3334
3335 AJNEW0(thys);
3336 ajStrAssignC(&cmdstr, cmdlinetxt);
3337
3338 ajDebug("ajSysCreateInpipeC: '%s'\n", cmdlinetxt);
3339
3340 /* pipe character at end */
3341 if(ajStrGetCharLast(cmdstr) == '|')
3342 ajStrCutEnd(&cmdstr, 1);
3343
3344
3345 #ifndef WIN32
3346
3347 if(pipe(pipefds) < 0)
3348 ajFatal("ajSysCreateInpipeC: pipe create failed");
3349
3350 /* negative return indicates failure */
3351 thys->Pid = fork();
3352
3353 if(thys->Pid < 0)
3354 ajFatal("ajSysCreateInpipeC: fork create failed");
3355
3356 /* pid is zero in the child, but is the child PID in the parent */
3357
3358 if(!thys->Pid)
3359 {
3360 /* this is the child process */
3361 close(pipefds[0]);
3362
3363 dup2(pipefds[1], 1);
3364 close(pipefds[1]);
3365 ajSysArglistBuildS(cmdstr, &pgm, &arglist);
3366 ajDebug("ajSysCreateInpipeC: execvp ('%S', NULL)\n", cmdstr);
3367 execvp(pgm, arglist);
3368 ajErr("ajSysCreateInpipeC: execvp ('%S', NULL) failed: '%s'\n",
3369 cmdstr, strerror(errno));
3370 ajExitAbort();
3371 }
3372
3373 ajDebug("ajSysCreateInpipeC: pid %d, pipe '%d', '%d'\n",
3374 thys->Pid, pipefds[0], pipefds[1]);
3375
3376 /* fp is what we read from the pipe */
3377 thys->fp = ajSysFuncFdopen(pipefds[0], "r");
3378 close(pipefds[1]);
3379
3380 #else
3381
3382 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
3383 sa.bInheritHandle = TRUE;
3384 sa.lpSecurityDescriptor = NULL;
3385
3386 svstdout = GetStdHandle(STD_OUTPUT_HANDLE);
3387
3388 if(!CreatePipe(&cstdoutr, &cstdoutw, &sa, 0))
3389 ajFatal("ajSysCreateInpipeC: pipe create failed");
3390
3391 if(!SetHandleInformation(cstdoutr, HANDLE_FLAG_INHERIT, 0))
3392 ajFatal("ajSysCreateInpipeC: Can't set no-inherit on child stdout "
3393 "read handle");
3394
3395
3396 if(!SetStdHandle(STD_OUTPUT_HANDLE, cstdoutw))
3397 ajFatal("ajSysCreateInpipeC: redirecting of STDOUT failed");
3398
3399 ret = DuplicateHandle(GetCurrentProcess(),
3400 cstdoutr,
3401 GetCurrentProcess(),
3402 &cstdoutrdup , 0,
3403 FALSE,
3404 DUPLICATE_SAME_ACCESS);
3405 if(!ret)
3406 ajFatal("ajSysCreateInpipeC: Could not duplicate stdout read handle");
3407
3408 CloseHandle(cstdoutr);
3409
3410 /* Create Process here */
3411
3412 ZeroMemory(&pinf, sizeof(PROCESS_INFORMATION));
3413 ZeroMemory(&sinf, sizeof(STARTUPINFO));
3414 sinf.cb = sizeof(STARTUPINFO);
3415
3416 ret = CreateProcess(NULL, (char *)ajStrGetPtr(cmdstr), NULL, NULL, TRUE, 0,
3417 NULL, NULL, &sinf, &pinf);
3418
3419 if(!ret)
3420 ajFatal("ajSysCreateInpipeC: CreateProcess failed: %S", cmdstr);
3421
3422 thys->Process = pinf.hProcess;
3423 thys->Thread = pinf.hThread;
3424
3425 if(!SetStdHandle(STD_OUTPUT_HANDLE, svstdout))
3426 ajFatal("restoring stdout failed\n");
3427
3428 CloseHandle(cstdoutw);
3429
3430 fd = _open_osfhandle((intptr_t) cstdoutrdup, _O_RDONLY);
3431 thys->fp = ajSysFuncFdopen(fd, "r");
3432 #endif
3433
3434 ajStrDel(&cmdstr);
3435
3436 if(!thys->fp)
3437 {
3438 thys->Handle = 0;
3439 ajFileClose(&thys);
3440
3441 return NULL;
3442 }
3443
3444 return thys;
3445 }
3446
3447
3448
3449
3450 /* @func ajSysCreateInpipeS ***************************************************
3451 **
3452 ** Return a new file object from which to read the output from a command.
3453 **
3454 ** @param [r] command [const AjPStr] Command string.
3455 ** The string may end with a trailing pipe character.
3456 ** @return [AjPFile] New file object.
3457 **
3458 ** @release 6.3.0
3459 ** @@
3460 ******************************************************************************/
3461
ajSysCreateInpipeS(const AjPStr command)3462 AjPFile ajSysCreateInpipeS(const AjPStr command)
3463 {
3464 return ajSysCreateInpipeC(MAJSTRGETPTR(command));
3465 }
3466
3467
3468
3469
3470 /* @section exit **************************************************************
3471 **
3472 ** Functions called on exit from the program by ajExit to do
3473 ** any necessary cleanup and to report internal statistics to the debug file
3474 **
3475 ** @fdata [none]
3476 ** @fnote general exit functions, no arguments
3477 **
3478 ** @nam3rule Exit Cleanup and report on exit
3479 **
3480 ** @valrule * [void]
3481 **
3482 ** @fcategory misc
3483 */
3484
3485
3486
3487
3488 /* @func ajSysExit ************************************************************
3489 **
3490 ** Cleans up system internals memory
3491 **
3492 ** @return [void]
3493 **
3494 ** @release 4.0.0
3495 ** @@
3496 ******************************************************************************/
3497
ajSysExit(void)3498 void ajSysExit(void)
3499 {
3500 ajStrDel(&sysFname);
3501 ajStrDel(&sysTname);
3502 ajStrDel(&sysTokSou);
3503 ajStrDel(&sysTokRets);
3504 ajStrDel(&sysUserPath);
3505
3506 return;
3507 }
3508
3509
3510
3511
3512 #ifdef AJ_COMPILE_DEPRECATED_BOOK
3513 #endif
3514
3515
3516
3517
3518 #ifdef AJ_COMPILE_DEPRECATED
3519 /* @obsolete ajSysArglistBuild
3520 ** @rename ajSysArglistBuildS
3521 */
3522
ajSysArglistBuild(const AjPStr cmdline,char ** Pname,char *** PParglist)3523 __deprecated AjBool ajSysArglistBuild(const AjPStr cmdline,
3524 char** Pname, char*** PParglist)
3525 {
3526 return ajSysArglistBuildS(cmdline, Pname, PParglist);
3527 }
3528
3529
3530
3531
3532 /* @obsolete ajSysArglist
3533 ** @rename ajSysArglistBuildS
3534 */
3535
ajSysArglist(const AjPStr cmdline,char ** Pname,char *** PParglist)3536 __deprecated AjBool ajSysArglist(const AjPStr cmdline,
3537 char** Pname, char*** PParglist)
3538 {
3539 return ajSysArglistBuildS(cmdline, Pname, PParglist);
3540 }
3541
3542
3543
3544
3545 /* @obsolete ajSysArgListFree
3546 ** @rename ajSysArglistFree
3547 */
3548
ajSysArgListFree(char *** PParglist)3549 __deprecated void ajSysArgListFree(char*** PParglist)
3550 {
3551 ajSysArglistFree(PParglist);
3552 return;
3553 }
3554
3555
3556
3557
3558 /* @obsolete ajSysItoC
3559 ** @rename ajSysCastItoC
3560 */
3561
ajSysItoC(ajint v)3562 __deprecated char ajSysItoC(ajint v)
3563 {
3564 return ajSysCastItoc(v);
3565 }
3566
3567
3568
3569
3570 /* @obsolete ajSysItoUC
3571 ** @rename ajSysCastItouc
3572 */
3573
ajSysItoUC(ajint v)3574 __deprecated unsigned char ajSysItoUC(ajint v)
3575 {
3576 return ajSysCastItouc(v);
3577 }
3578
3579
3580
3581
3582 /* @obsolete ajSysFileUnlink
3583 ** @rename ajSysFileUnlinkS
3584 */
3585
ajSysFileUnlink(const AjPStr s)3586 __deprecated AjBool ajSysFileUnlink(const AjPStr s)
3587 {
3588 return ajSysFileUnlinkS(s);
3589 }
3590
3591
3592
3593
3594 /* @obsolete ajSysUnlink
3595 ** @rename ajSysFileUnlinkS
3596 */
3597
ajSysUnlink(const AjPStr s)3598 __deprecated AjBool ajSysUnlink(const AjPStr s)
3599 {
3600 return ajSysFileUnlinkS(s);
3601 }
3602
3603
3604
3605
3606 /* @obsolete ajSysWhich
3607 ** @rename ajSysFileWhich
3608 */
3609
ajSysWhich(AjPStr * s)3610 __deprecated AjBool ajSysWhich(AjPStr *s)
3611 {
3612 return ajSysFileWhich(s);
3613 }
3614
3615
3616
3617
3618 /* @obsolete ajSysWhichEnv
3619 ** @rename ajSysFileWhichEnv
3620 */
3621
ajSysWhichEnv(AjPStr * Pfilename,char * const env[])3622 __deprecated AjBool ajSysWhichEnv(AjPStr *Pfilename, char * const env[])
3623 {
3624 return ajSysFileWhichEnv(Pfilename, env);
3625 }
3626
3627
3628
3629
3630 /* @obsolete ajSysFdopen
3631 ** @rename ajSysFuncFdopen
3632 */
3633
ajSysFdopen(ajint filedes,const char * mode)3634 __deprecated FILE* ajSysFdopen(ajint filedes, const char *mode)
3635 {
3636 return ajSysFuncFdopen(filedes, mode);
3637 }
3638
3639
3640
3641
3642 /* @obsolete ajSysFgets
3643 ** @rename ajSysFuncFgets
3644 */
3645
ajSysFgets(char * buf,int size,FILE * fp)3646 __deprecated char* ajSysFgets(char *buf, int size, FILE *fp)
3647 {
3648 return ajSysFuncFgets(buf, size, fp);
3649 }
3650
3651
3652
3653
3654 /* @obsolete ajSysFopen
3655 ** @rename ajSysFuncFopen
3656 */
3657
ajSysFopen(const char * name,const char * flags)3658 __deprecated FILE* ajSysFopen(const char *name, const char *flags)
3659 {
3660 return ajSysFuncFopen(name, flags);
3661 }
3662
3663
3664
3665
3666 /* @obsolete ajSysStrdup
3667 ** @rename ajSysFuncStrdup
3668 */
ajSysStrdup(const char * s)3669 __deprecated char* ajSysStrdup(const char *s)
3670 {
3671 return ajSysFuncStrdup(s);
3672 }
3673
3674
3675
3676
3677 /* @obsolete ajSysStrtok
3678 ** @rename ajSysFuncStrtok
3679 */
3680
ajSysStrtok(const char * s,const char * t)3681 __deprecated char* ajSysStrtok(const char *s, const char *t)
3682 {
3683 return ajSysFuncStrtok(s, t);
3684 }
3685
3686
3687
3688
3689 /* @obsolete ajSysStrtokR
3690 ** @rename ajSysFuncStrtokR
3691 */
3692
3693
ajSysStrtokR(const char * s,const char * t,const char ** ptrptr,AjPStr * buf)3694 __deprecated char* ajSysStrtokR(const char *s, const char *t,
3695 const char **ptrptr,
3696 AjPStr *buf)
3697 {
3698 return ajSysFuncStrtokR(s, t, ptrptr, buf);
3699 }
3700
3701
3702
3703
3704 /* @obsolete ajSystemEnv
3705 ** @rename ajSysExecEnvS
3706 */
3707
ajSystemEnv(const AjPStr cl,char * const env[])3708 __deprecated void ajSystemEnv(const AjPStr cl, char * const env[])
3709 {
3710 ajSysExecEnvS(cl, env);
3711 return;
3712 }
3713
3714
3715
3716
3717 /* @obsolete ajSysSystemEnv
3718 ** @rename ajSysExecEnvS
3719 */
3720
ajSysSystemEnv(const AjPStr cmdline,char * const env[])3721 __deprecated void ajSysSystemEnv(const AjPStr cmdline, char * const env[])
3722 {
3723 ajSysExecEnvS(cmdline, env);
3724
3725 return;
3726 }
3727
3728
3729
3730
3731 /* @obsolete ajSystemOut
3732 ** @rename ajSysExecOutnameS
3733 */
3734
ajSystemOut(const AjPStr cl,const AjPStr outfname)3735 __deprecated void ajSystemOut(const AjPStr cl, const AjPStr outfname)
3736 {
3737 ajSysExecOutnameS(cl, outfname);
3738 return;
3739 }
3740
3741
3742
3743
3744 /* @obsolete ajSysSystemOut
3745 ** @rename ajSysExecOutnameS
3746 */
3747
ajSysSystemOut(const AjPStr cmdline,const AjPStr outfname)3748 __deprecated void ajSysSystemOut(const AjPStr cmdline, const AjPStr outfname)
3749 {
3750 ajSysExecOutnameS(cmdline, outfname);
3751 return;
3752 }
3753
3754
3755
3756
3757 /* @obsolete ajSystem
3758 ** @rename ajSysSystem
3759 */
3760
ajSystem(const AjPStr cl)3761 __deprecated void ajSystem(const AjPStr cl)
3762 {
3763 ajSysExecS(cl);
3764 return;
3765 }
3766
3767
3768
3769
3770 /* @obsolete ajSysSystem
3771 ** @rename ajSysExecS
3772 */
3773
ajSysSystem(const AjPStr cmdline)3774 __deprecated void ajSysSystem(const AjPStr cmdline)
3775 {
3776 ajSysExecS(cmdline);
3777 return;
3778 }
3779
3780
3781
3782
3783 /* @obsolete ajSysExecProgArgEnvNowaitC
3784 ** @rename ajSysExecProgArgEnvNowaitC
3785 */
ajSysExecProgArgEnvNowaitC(const char * prog,char * const arg[],char * const env[])3786 __deprecated ajint ajSysExecProgArgEnvNowaitC(const char *prog,
3787 char * const arg[],
3788 char * const env[])
3789 {
3790 return ajSysExecprogNowaitC(prog, arg, env);
3791 }
3792
3793
3794
3795
3796 /* @obsolete ajSysExecProgArgEnvNowaitS
3797 ** @rename ajSysExecProgArgEnvNowaitS
3798 */
ajSysExecProgArgEnvNowaitS(const AjPStr progstr,char * const arg[],char * const env[])3799 __deprecated ajint ajSysExecProgArgEnvNowaitS(const AjPStr progstr,
3800 char * const arg[],
3801 char * const env[])
3802 {
3803 return ajSysExecprogNowaitC(MAJSTRGETPTR(progstr), arg, env);
3804 }
3805
3806
3807
3808
3809 /* @obsolete ajSysBasename
3810 ** @rename ajFilenameTrimPath
3811 */
3812
ajSysBasename(AjPStr * s)3813 __deprecated void ajSysBasename(AjPStr *s)
3814 {
3815 ajFilenameTrimPath(s);
3816
3817 return;
3818 }
3819
3820
3821
3822
3823 /* @obsolete ajSysIsDirectory
3824 ** @remove use ajFileDir instead
3825 */
3826
ajSysIsDirectory(const char * s)3827 __deprecated AjBool ajSysIsDirectory(const char *s)
3828 {
3829 AjBool ret;
3830 AjPStr tmpstr = NULL;
3831 tmpstr = ajStrNewC(s);
3832
3833 ret = ajDirnameFixExists(&tmpstr);
3834 ajStrDel(&tmpstr);
3835
3836 return ret;
3837 }
3838
3839
3840
3841
3842 /* @obsolete ajSysIsRegular
3843 ** @remove use ajFileNameValid instead
3844 */
3845
ajSysIsRegular(const char * s)3846 __deprecated AjBool ajSysIsRegular(const char *s)
3847 {
3848 AjBool ret;
3849 AjPStr tmpstr;
3850
3851 tmpstr = ajStrNewC(s);
3852
3853 ret = ajFilenameExistsRead(tmpstr);
3854 ajStrDel(&tmpstr);
3855
3856 return ret;
3857 }
3858 #endif
3859