root/trunk/orca/unix/os.c

Revision 145, 9.0 kB (checked in by krobillard, 3 years ago)

orReadDir() now holds new block.

Line 
1/*============================================================================
2    ORCA Interpreter
3    Copyright (C) 2005-2006  Karl Robillard
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18===========================================================================*/
19
20
21#include <sys/types.h>
22#include <sys/wait.h>
23#include <sys/time.h>
24#include <sys/stat.h>
25#include <errno.h>
26#include <dirent.h>
27#include <unistd.h>
28#include <signal.h>
29#include <time.h>
30#include "os.h"
31#include "ovalue.h"
32
33
34unsigned long randomSeed()
35{
36    unsigned long seed;
37    seed  = time(NULL);
38    seed += clock();
39    return seed;
40}
41
42
43/**
44  Returns -1 if not present.
45*/
46int orFileSize( const char* path )
47{
48    struct stat buf;
49    if( stat( path, &buf ) == -1 )
50        return -1;
51    return buf.st_size;
52}
53
54
55/**
56  Returns 1 if directory, 0 if file or -1 if error.
57*/
58int orIsDir( const char* path )
59{
60    struct stat buf;
61    if( stat( path, &buf ) == -1 )
62        return -1;
63    return S_ISDIR(buf.st_mode) ? 1 : 0;
64}
65
66
67/**
68  Returns 0 if result set to file modification time or -1 if error.
69*/
70int orFileModified( const char* path, OValue* res )
71{
72    struct stat buf;
73    if( stat( path, &buf ) == -1 )
74        return -1;
75
76    orSetTF( res, OT_TIME );
77    orSeconds(res) = buf.st_mtime;
78    return 0;
79}
80
81
82/*
83   change-dir
84*/
85OR_NATIVE_PUB(orChangeDirNative )
86{
87    int logic = 0;
88    OString* str = orSTRING(a1);
89    orTermCStr(str);
90    if( chdir( str->charArray ) == 0 )
91        logic = 1;
92    orResult( OT_LOGIC, logic );
93}
94
95
96/*
97   what-dir
98*/
99OR_NATIVE_PUB( orWhatDirNative )
100{
101    if( getcwd( orTmp, OR_TMP_SIZE ) )
102    {
103        int len;
104        OString* str;
105       
106        len = strLen( orTmp );
107        if( len > 0 )
108        {
109            str = orMakeString( len + OR_CTERM_LEN );
110            str->used = len;
111            memCpy( str->charArray, orTmp, len );
112            orResultFILE( orStringN(str) );
113            return;
114        }
115    }
116    orResultFALSE;
117}
118
119
120/**
121  No error if directory exists.
122*/
123OR_NATIVE_PUB( orMakeDirNative )
124{
125    int err;
126    OString* str = orSTRING(a1);
127    orTermCStr(str);
128    err = mkdir( str->charArray, 0755 );
129    if( err )
130    {
131        if( (errno != EEXIST) || (orIsDir(str->charArray) != 1) )
132        {
133            orErrorT( OR_ERROR_ACCESS, strerror/*_r*/(errno) );
134        }
135    }
136}
137
138
139#define REF_TIME    a1
140
141OR_NATIVE_PUB( orNowNative )
142{
143    struct timeval tp;
144
145    gettimeofday( &tp, 0 );
146
147    //printf( "sizeof(timeval.tv_sec) %d %d\n",
148    //        sizeof(tp.tv_sec), sizeof(tp.tv_usec) );
149
150    if( orRefineSet( REF_TIME ) )
151        orSetTF( a1, OT_TIME );
152    else
153        orSetTF( a1, OT_DATE );
154
155    orSeconds(a1) = tp.tv_sec + (tp.tv_usec * 0.000001);
156}
157
158
159/**
160  Sets result.
161*/
162void orReadDir( OValue* a1, const char* filename )
163{
164    DIR* dir;
165    struct dirent* entry;
166
167    dir = opendir( filename );
168    if( dir )
169    {
170        OIndex hold;
171        OIndex blkN;
172        OBlock* blk = orMakeBlock( 0 );
173
174        blkN = orBlockN(blk);
175        hold = orHold( OT_BLOCK, blkN );
176
177        while( (entry = readdir( dir )) )
178        {
179            const char* cp = entry->d_name;
180            if( cp[0] == '.' && (cp[1] == '.' || cp[1] == '\0') )
181                continue;
182            orAppendFile( blk, orMakeCString(cp, -1) );
183        }
184
185        closedir( dir );
186
187        orRelease( hold );
188        orResultBLOCK( blkN );
189    }
190    else
191    {
192        orResultFALSE;
193    }
194}
195
196
197#ifdef OR_CONFIG_OS_CALL
198static void argumentList( OString* str, int sindex, char** argv, int maxArg )
199{
200    char* cp;
201    int prevWhite;
202    int argc;
203
204    orTermCStr( str );
205    cp = str->charArray + sindex;
206
207    argc = 0;
208    prevWhite = 1;
209    while( *cp != '\0' )
210    {
211        if( *cp == ' ' || *cp == '\t' || *cp == '\n' )
212        {
213            *cp = '\0';
214            prevWhite = 1;
215        }
216        else if( prevWhite )
217        {
218            prevWhite = 0;
219            argv[ argc ] = cp;
220            ++argc;
221            if( argc == maxArg )
222                goto term;
223        }
224        ++cp;
225    }
226
227term:
228    argv[ argc ] = 0;
229}
230
231
232#define REF_CALL_OUTPUT     a1+1
233#define REF_CALL_OUT        a1+2
234#define REF_CALL_WAIT       a1+3
235
236
237static void callOutput( OValue* a1 )
238{
239#define BUFSIZE     256
240    int pid;
241    int pfd[2];
242
243    if( pipe(pfd) == -1 )
244    {
245        orError( "pipe failed" );
246        return;
247    }
248
249    pid = fork();
250    if( pid == 0 )
251    {
252        // In child process; invoke command.
253
254        // What is the overhead of creating the arg list between fork/exec?
255        char* argv[10];
256        argumentList( orSTRING(a1), a1->series.it, argv, 9 );
257
258        close( pfd[0] );
259        dup2( pfd[1], 1 );
260        close( pfd[1] );
261
262        if( execvp( argv[0], argv ) == -1 )
263        {
264            perror( "orCallNative" );
265            _exit( 255 );
266        }
267    }
268    else if( pid > 0 )
269    {
270        // In parent process.
271
272        int n;
273        int status;
274        OString* str;
275
276        str = orSTRING(REF_CALL_OUT);
277        str->used = 0;
278        orArrayReserve( str, 1, BUFSIZE );
279
280        close( pfd[1] );
281        while( (n = read( pfd[0], str->charArray + str->used, BUFSIZE )) > 0 )
282        {
283            str->used += n;
284            orArrayReserve( str, 1, str->used + BUFSIZE );
285        }
286        close( pfd[0] );
287
288        waitpid( pid, &status, 0 );
289        if( WIFEXITED(status) )
290        {
291            orResult( OT_INTEGER, WEXITSTATUS(status) );
292            return;
293        }
294        orResultNONE;
295    }
296    else
297    {
298        // fork failed.
299        close( pfd[0] );
300        close( pfd[1] );
301        orError( "fork failed" );
302    }
303}
304
305
306static int _asyncProcCount = 0;
307
308static void callSimple( OValue* a1 )
309{
310    int pid;
311    int status;
312    int waitRef;
313
314    waitRef = orRefineSet(REF_CALL_WAIT);
315    if( ! waitRef )
316    {
317        // Need to call wait() when SIGCHLD is received to avoid zombies.
318        /*
319         FIXME: Using _asyncProcCount may cause the signal handler to get
320         the status if call/wait is called while an asynchronous process is
321         still running.
322        */
323        _asyncProcCount++;
324    }
325
326    pid = fork();
327    if( pid == 0 )
328    {
329        // In child process; invoke command.
330
331        // What is the overhead of creating the arg list between fork/exec?
332        char* argv[10];
333        argumentList( orSTRING(a1), a1->series.it, argv, 9 );
334
335        if( execvp( argv[0], argv ) == -1 )
336        {
337            perror( "orCallNative" );
338            _exit( 255 );
339        }
340    }
341    else if( pid > 0 )
342    {
343        // In parent process.
344
345        if( waitRef )
346        {
347            waitpid( pid, &status, 0 );
348            if( WIFEXITED(status) )
349            {
350                orResult( OT_INTEGER, WEXITSTATUS(status) );
351                return;
352            }
353        }
354        orResultNONE;
355    }
356    else
357    {
358        // fork failed.
359        orError( "fork failed" );
360        if( ! waitRef )
361            --_asyncProcCount;
362    }
363}
364
365
366/*
367  command /output out /wait
368*/
369OR_NATIVE_PUB( orCallNative )
370{
371    if( a1->type != OT_STRING )
372    {
373        orResultFALSE;
374        return;
375    }
376
377    if( orRefineSet( REF_CALL_OUTPUT ) )
378    {
379        callOutput( a1 );
380    }
381    else
382    {
383        callSimple( a1 );
384    }
385}
386#endif
387
388
389#ifdef OR_CONFIG_OS_CALL
390/* Cleans up after callSimple() */
391static void child_handler( int sig )
392{
393    (void) sig;
394
395    if( _asyncProcCount )
396    {
397        int status;
398        wait( &status );
399        --_asyncProcCount;
400    }
401}
402#endif
403
404#if 0
405void kill_handler( int sig )
406{
407    (void) sig;
408    printf( "User Abort\n" );
409}
410
411void fpe_handler( int sig )
412{
413    (void) sig;
414    printf( "Math Error\n" );
415    exit(-1);
416}
417#endif
418
419
420void orInstallExceptionHandlers()
421{
422#ifdef OR_CONFIG_OS_CALL
423    /* NOTE: Cannot use this if using Qt's QProcess (it uses SIGCHLD) */
424    struct sigaction childSA;
425
426    childSA.sa_handler = child_handler;
427    childSA.sa_flags   = SA_NOCLDSTOP;
428    sigemptyset( &childSA.sa_mask );
429
430    sigaction( SIGCHLD, &childSA, NULL );
431#endif
432
433#if 0
434    struct sigaction action;
435    struct sigaction faction;
436
437    action.sa_handler = kill_handler;
438    action.sa_flags   = 0;
439    sigemptyset( &action.sa_mask );
440
441    sigaction( SIGTERM, &action, NULL );    // kill
442    sigaction( SIGINT,  &action, NULL );    // Ctrl-C
443
444    faction.sa_handler = fpe_handler;
445    faction.sa_flags   = 0;
446    sigemptyset( &faction.sa_mask );
447
448    sigaction( SIGFPE,  &faction, NULL );
449#endif
450
451#if 0
452    //double f = 0.0;
453    //printf( "%g\n", 2.0 / f );
454    int n = 0;
455    printf( "%d\n", 2 / n );
456#endif
457}
458
459
460/*EOF*/
Note: See TracBrowser for help on using the browser.