1 #include "apricot.h"
2 #include "Utils.h"
3 #include <Utils.inc>
4 
5 #ifdef __cplusplus
6 extern "C" {
7 #endif
8 
9 
Utils_query_drives_map(char * firstDrive)10 SV *Utils_query_drives_map( char *firstDrive)
11 {
12 	char map[ 256];
13 	apc_query_drives_map( firstDrive, map, sizeof( map));
14 	return newSVpv( map, 0);
15 }
16 
17 int
Utils_get_os(void)18 Utils_get_os(void)
19 {
20 	return apc_application_get_os_info( NULL, 0, NULL, 0, NULL, 0, NULL, 0);
21 }
22 
23 int
Utils_get_gui(void)24 Utils_get_gui(void)
25 {
26 	return apc_application_get_gui_info( NULL, 0, NULL, 0);
27 }
28 
Utils_ceil(double x)29 long Utils_ceil( double x)
30 {
31 	return ceil( x);
32 }
33 
Utils_floor(double x)34 long Utils_floor( double x)
35 {
36 	return floor( x);
37 }
38 
39 static Bool
is_valid_utf8(unsigned char * str)40 is_valid_utf8( unsigned char * str )
41 {
42 	int len = 0, hi8 = 0;
43 	unsigned char * c = str;
44 	while (*c) {
45 		len++;
46 		if ( *c > 0x7f ) hi8 = 1;
47 		c++;
48 	}
49 	if ( !hi8 ) return false;
50 #if PERL_PATCHLEVEL >= 22
51 	while ( str < c ) {
52 		unsigned char * end = utf8_hop( str, 1 );
53 		if ( end > c ) return false;
54 		if ( !isUTF8_CHAR(str, end))
55 			return false;
56 		str = end;
57 	}
58 #endif
59 	return true;
60 }
61 
XS(Utils_getdir_FROMPERL)62 XS(Utils_getdir_FROMPERL) {
63 	dXSARGS;
64 	Bool wantarray = ( GIMME_V == G_ARRAY);
65 	char *dirname;
66 	PList dirlist;
67 	int i;
68 
69 	if ( items >= 2) {
70 		croak( "invalid usage of Prima::Utils::getdir");
71 	}
72 	dirname = SvPV_nolen( ST( 0));
73 	dirlist = apc_getdir( dirname, prima_is_utf8_sv(ST(0)));
74 	SPAGAIN;
75 	SP -= items;
76 	if ( wantarray) {
77 		if ( dirlist) {
78 			EXTEND( sp, dirlist-> count);
79 			for ( i = 0; i < dirlist-> count; i++) {
80 				char * entry = ( char *)dirlist-> items[i];
81 				SV * sv      = newSVpv(entry, 0);
82 				if (is_valid_utf8((unsigned char*) entry))
83 					SvUTF8_on(sv);
84 				PUSHs( sv_2mortal(sv));
85 				free(( char *)dirlist-> items[i]);
86 			}
87 			plist_destroy( dirlist);
88 		}
89 	} else {
90 		if ( dirlist) {
91 			XPUSHs( sv_2mortal( newSViv( dirlist-> count / 2)));
92 			for ( i = 0; i < dirlist-> count; i++) {
93 				free(( char *)dirlist-> items[i]);
94 			}
95 			plist_destroy( dirlist);
96 		} else {
97 			XPUSHs( &PL_sv_undef);
98 		}
99 	}
100 	PUTBACK;
101 	return;
102 }
103 
104 int
Utils_access(SV * path,int mode,Bool effective)105 Utils_access( SV* path, int mode, Bool effective )
106 {
107 	return apc_fs_access( SvPV_nolen(path), prima_is_utf8_sv(path), mode, effective);
108 }
109 
110 Bool
Utils_chdir(SV * path)111 Utils_chdir( SV* path )
112 {
113 	return apc_fs_chdir( SvPV_nolen(path), prima_is_utf8_sv(path));
114 }
115 
116 Bool
Utils_chmod(SV * path,int mode)117 Utils_chmod( SV* path, int mode)
118 {
119 	return apc_fs_chmod( SvPV_nolen(path), prima_is_utf8_sv(path), mode);
120 }
121 
122 static PDirHandleRec
get_dh(const char * method,SV * sv)123 get_dh(const char * method, SV * sv)
124 {
125 	PDirHandleRec d;
126 	if ( !SvROK(sv) || SvTYPE( SvRV( sv)) != SVt_PVMG)
127 		goto WARN;
128 	if ( !sv_isa( sv, "Prima::Utils::DIRHANDLE" ))
129 		goto WARN;
130 	d = (PDirHandleRec) prima_array_get_storage(SvRV(sv));
131 	if (!d-> is_active) {
132 		errno = EBADF;
133 		return false;
134 	}
135 	return d;
136 
137 WARN:
138 	warn("Prima::Utils::%s: invalid dirhandle", method);
139 	errno = EBADF;
140 	return false;
141 }
142 
143 Bool
Utils_closedir(SV * dh)144 Utils_closedir(SV * dh)
145 {
146 	PDirHandleRec d;
147 	if (( d = get_dh("closedir", dh)) == NULL )
148 		return false;
149 	d-> is_active = false;
150 	return apc_fs_closedir(d);
151 }
152 
153 SV*
Utils_getcwd()154 Utils_getcwd()
155 {
156 	SV * ret;
157 	char *cwd;
158 
159 	if (( cwd = apc_fs_getcwd()) == NULL )
160 		return NULL_SV;
161 	ret = newSVpv( cwd, 0 );
162 	if ( is_valid_utf8((unsigned char*) cwd))
163 		SvUTF8_on(ret);
164 	free(cwd);
165 	return ret;
166 }
167 
168 SV*
Utils_getenv(SV * varname)169 Utils_getenv(SV * varname)
170 {
171 	SV * ret;
172 	char *val;
173 	Bool is_utf8, do_free = false;
174 
175 	is_utf8 = prima_is_utf8_sv(varname);
176 	if (( val = apc_fs_getenv(SvPV_nolen(varname), is_utf8, &do_free)) == NULL )
177 		return NULL_SV;
178 	ret = newSVpv( val, 0 );
179 	if ( is_valid_utf8((unsigned char*) val))
180 		SvUTF8_on(ret);
181 	if ( do_free ) free(val);
182 	return ret;
183 }
184 
185 SV *
Utils_last_error()186 Utils_last_error()
187 {
188 	SV * ret = NULL_SV;
189 	char * p = apc_last_error();
190 	if ( p ) {
191 		ret = newSVpv( p, 0);
192 		free(p);
193 	}
194 	return ret;
195 }
196 
197 Bool
Utils_link(SV * oldname,SV * newname)198 Utils_link( SV* oldname, SV * newname )
199 {
200 	return apc_fs_link(
201 		SvPV_nolen(oldname), prima_is_utf8_sv(oldname),
202 		SvPV_nolen(newname), prima_is_utf8_sv(newname)
203 	);
204 }
205 
206 SV *
Utils_local2sv(SV * text)207 Utils_local2sv(SV * text)
208 {
209 	SV * ret;
210 	char * buf, *src;
211 	STRLEN xlen;
212 	int len;
213 	if ( prima_is_utf8_sv(text) )
214 		return newSVsv( text );
215 	src = SvPV(text, xlen);
216 	len = xlen;
217 	if ( !( buf = apc_fs_from_local(src, &len)))
218 		return NULL_SV;
219 	if ( buf == src ) {
220 		ret = newSVsv( text );
221 		if ( is_valid_utf8((unsigned char*) src))
222 			SvUTF8_on(ret);
223 		return ret;
224 	}
225 
226 	ret = newSVpv( buf, len );
227 	if ( is_valid_utf8((unsigned char*) buf))
228 		SvUTF8_on(ret);
229 	free(buf);
230 
231 	return ret;
232 }
233 
234 
235 Bool
Utils_mkdir(SV * path,int mode)236 Utils_mkdir( SV* path, int mode)
237 {
238 	return apc_fs_mkdir( SvPV_nolen(path), prima_is_utf8_sv(path), mode);
239 }
240 
241 SV *
Utils_open_dir(SV * path)242 Utils_open_dir(SV * path)
243 {
244 	SV * ret = NULL_SV;
245 	PDirHandleRec dh;
246 	SV * dhsv;
247 
248 	if (( dhsv = prima_array_new(sizeof(DirHandleRec))) == NULL) {
249 		errno = ENOMEM;
250 		return NULL_SV;
251 	}
252 	if (( dh = (PDirHandleRec) prima_array_get_storage(dhsv)) == NULL) {
253 		errno = ENOMEM;
254 		return NULL_SV;
255 	}
256 	bzero(dh, sizeof(DirHandleRec));
257 	dh-> is_utf8 = prima_is_utf8_sv(path);
258 	if ( !apc_fs_opendir( SvPV_nolen(path), dh)) {
259 		sv_free(dhsv);
260 		return NULL_SV;
261 	}
262 	dh-> is_active = true;
263 
264 	ret = newRV_noinc(dhsv);
265 	sv_bless(ret, gv_stashpv("Prima::Utils::DIRHANDLE", GV_ADD));
266 
267 
268 	return ret;
269 }
270 
271 int
Utils_open_file(SV * path,int mode,int perms)272 Utils_open_file( SV* path, int mode, int perms)
273 {
274 	return apc_fs_open_file( SvPV_nolen(path), prima_is_utf8_sv(path), mode, perms);
275 }
276 
277 SV*
Utils_read_dir(SV * dh)278 Utils_read_dir(SV * dh)
279 {
280 	PDirHandleRec d;
281 	char buf[PATH_MAX_UTF8];
282 	SV * ret;
283 	if (( d = get_dh("read_dir", dh)) == NULL ) {
284 		errno = EBADF;
285 		warn("Prima::Utils::read_dir: invalid dirhandle");
286 		return NULL_SV;
287 	}
288 	if (!d-> is_active) {
289 		errno = EBADF;
290 		return NULL_SV;
291 	}
292 
293 	if ( !apc_fs_readdir(d, buf)) return NULL_SV;
294 
295 	ret = newSVpv(buf, 0);
296 	if (is_valid_utf8((unsigned char*) buf))
297 		SvUTF8_on(ret);
298 
299 	return ret;
300 }
301 
302 Bool
Utils_rename(SV * oldpath,SV * newpath)303 Utils_rename( SV* oldpath, SV * newpath )
304 {
305 	return apc_fs_rename(
306 		SvPV_nolen(oldpath), prima_is_utf8_sv(oldpath),
307 		SvPV_nolen(newpath), prima_is_utf8_sv(newpath)
308 	);
309 }
310 
311 Bool
Utils_rewinddir(SV * dh)312 Utils_rewinddir( SV * dh )
313 {
314 	PDirHandleRec d;
315 	if (( d = get_dh("rewinddir", dh)) == NULL )
316 		return false;
317 	return apc_fs_rewinddir(d);
318 }
319 
320 Bool
Utils_rmdir(SV * path)321 Utils_rmdir( SV* path )
322 {
323 	return apc_fs_rmdir( SvPV_nolen(path), prima_is_utf8_sv(path));
324 }
325 
326 Bool
Utils_seekdir(SV * dh,long position)327 Utils_seekdir( SV * dh, long position )
328 {
329 	PDirHandleRec d;
330 	if (( d = get_dh("seekdir", dh)) == NULL )
331 		return false;
332 	return apc_fs_seekdir(d, position);
333 }
334 
335 Bool
Utils_setenv(SV * varname,SV * value)336 Utils_setenv(SV * varname, SV * value)
337 {
338 	return apc_fs_setenv(
339 		SvPV_nolen(varname), prima_is_utf8_sv(varname),
340 		(SvTYPE(value) != SVt_NULL) ? SvPV_nolen(value) : NULL,
341 		(SvTYPE(value) != SVt_NULL) ? prima_is_utf8_sv(value) : false
342 	);
343 }
344 
XS(Utils_stat_FROMPERL)345 XS(Utils_stat_FROMPERL) {
346 	dXSARGS;
347 	char *name;
348 	StatRec stats;
349 	int ok;
350 	Bool link = false;
351 	U8 gimme;
352 
353 	if ( items > 2)
354 		croak( "invalid usage of Prima::Utils::stat");
355 	if ( items > 1 )
356 		link = SvBOOL(ST(1));
357 
358 	name = SvPV_nolen( ST( 0));
359 	ok = apc_fs_stat( name, prima_is_utf8_sv(ST(0)), link, &stats);
360 	SPAGAIN;
361 	SP -= items;
362 	gimme = GIMME_V;
363 	if ( gimme != G_ARRAY ) {
364 		if ( gimme != G_VOID )
365 			XPUSHs(newSViv(ok));
366 	} else if ( ok) {
367 		EXTEND( sp, 11 );
368 		PUSHs( sv_2mortal(newSVuv( stats. dev    )));
369 		PUSHs( sv_2mortal(newSVuv( stats. ino    )));
370 		PUSHs( sv_2mortal(newSVuv( stats. mode   )));
371 		PUSHs( sv_2mortal(newSVuv( stats. nlink  )));
372 		PUSHs( sv_2mortal(newSVuv( stats. uid    )));
373 		PUSHs( sv_2mortal(newSVuv( stats. gid    )));
374 		PUSHs( sv_2mortal(newSVuv( stats. rdev   )));
375 		PUSHs( sv_2mortal(newSVuv( stats. size   )));
376 		PUSHs( sv_2mortal(newSVnv( stats. atim   )));
377 		PUSHs( sv_2mortal(newSVnv( stats. mtim   )));
378 		PUSHs( sv_2mortal(newSVnv( stats. ctim   )));
379 		if (stats. blksize >= 0 )
380 			XPUSHs( sv_2mortal(newSVuv( stats. blksize)));
381 		if (stats. blocks  >= 0 )
382 			XPUSHs( sv_2mortal(newSVuv( stats. blocks )));
383 	}
384 	PUTBACK;
385 	return;
386 }
387 
388 static int
utf8len(const char * utf8,int maxlen)389 utf8len( const char * utf8, int maxlen)
390 {
391 	int ulen = 0;
392 	while ( maxlen > 0 ) {
393 		const char *u = (char*) utf8_hop(( U8*) utf8, 1);
394 		ulen++;
395 		maxlen -= u - utf8;
396 		utf8 = u;
397 	}
398 	return ulen;
399 }
400 
401 long
Utils_telldir(SV * dh)402 Utils_telldir( SV * dh )
403 {
404 	PDirHandleRec d;
405 	if (( d = get_dh("telldir", dh)) == NULL )
406 		return false;
407 	return apc_fs_telldir(d);
408 }
409 
410 SV *
Utils_sv2local(SV * text,Bool fail_if_cannot)411 Utils_sv2local(SV * text, Bool fail_if_cannot)
412 {
413 	SV * ret;
414 	char * buf, * src;
415 	STRLEN xlen;
416 	int len;
417 	if ( !prima_is_utf8_sv(text) )
418 		return newSVsv( text );
419 	src = SvPV(text, xlen);
420 	len = utf8len( src, xlen );
421 	if ( !( buf = apc_fs_to_local(src, fail_if_cannot, &len)))
422 		return NULL_SV;
423 	if ( buf == src ) {
424 		ret = newSVsv( text );
425 		SvUTF8_off(ret);
426 		return ret;
427 	}
428 	ret = newSVpv( buf, len );
429 	free(buf);
430 
431 	return ret;
432 }
433 
434 
435 Bool
Utils_unlink(SV * path)436 Utils_unlink( SV* path )
437 {
438 	return apc_fs_unlink( SvPV_nolen(path), prima_is_utf8_sv(path));
439 }
440 
441 Bool
Utils_utime(double atime,double mtime,SV * path)442 Utils_utime( double atime, double mtime, SV* path )
443 {
444 	return apc_fs_utime( atime, mtime, SvPV_nolen(path), prima_is_utf8_sv(path));
445 }
446 
447 #ifdef __cplusplus
448 }
449 #endif
450