1 /*===========================================================================
2 *
3 *                            PUBLIC DOMAIN NOTICE
4 *               National Center for Biotechnology Information
5 *
6 *  This software/database is a "United States Government Work" under the
7 *  terms of the United States Copyright Act.  It was written as part of
8 *  the author's official duties as a United States Government employee and
9 *  thus cannot be copyrighted.  This software/database is freely available
10 *  to the public for use. The National Library of Medicine and the U.S.
11 *  Government have not placed any restriction on its use or reproduction.
12 *
13 *  Although all reasonable efforts have been taken to ensure the accuracy
14 *  and reliability of the software and data, the NLM and the U.S.
15 *  Government do not and cannot warrant the performance or results that
16 *  may be obtained by using this software or data. The NLM and the U.S.
17 *  Government disclaim all warranties, express or implied, including
18 *  warranties of performance, merchantability or fitness for any particular
19 *  purpose.
20 *
21 *  Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26 
27 #include <tui/extern.h>
28 
29 #include <klib/rc.h>
30 #include <klib/text.h>
31 #include <klib/printf.h>
32 #include <kfs/directory.h>
33 #include <kfs/filetools.h>
34 
35 #include <vfs/manager.h>
36 #include <vfs/path.h>
37 
38 #include <tui/tui_dlg.h>
39 
40 #include <sysalloc.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <stdlib.h>
44 
45 
native_to_internal(VFSManager * vfs_mgr,const char * native,char * buffer,uint32_t buffer_size,size_t * written)46 rc_t native_to_internal( VFSManager * vfs_mgr, const char * native, char * buffer, uint32_t buffer_size, size_t * written )
47 {
48     VPath * temp_v_path;
49     rc_t rc = VFSManagerMakeSysPath ( vfs_mgr, &temp_v_path, native );
50     if ( rc == 0 )
51     {
52         rc = VPathReadPath ( temp_v_path, buffer, buffer_size, written );
53         VPathRelease ( temp_v_path );
54     }
55     return rc;
56 }
57 
58 
internal_to_native(VFSManager * vfs_mgr,const char * internal,char * buffer,uint32_t buffer_size,size_t * written)59 rc_t internal_to_native( VFSManager * vfs_mgr, const char * internal, char * buffer, uint32_t buffer_size, size_t * written )
60 {
61 	rc_t rc = 0;
62 	if ( internal[ 0 ] == '/' && internal[ 1 ] == 0 )
63 	{
64 		buffer[ 0 ] = '/'; buffer[ 1 ] = 0; *written = 1;
65 	}
66 	else
67 	{
68 		VPath * temp_v_path;
69 		rc = VFSManagerMakePath ( vfs_mgr, &temp_v_path, "%s", internal );
70 		if ( rc == 0 )
71 		{
72 			rc = VPathReadSysPath ( temp_v_path, buffer, buffer_size, written );
73 			VPathRelease ( temp_v_path );
74 		}
75 	}
76     return rc;
77 }
78 
79 
set_native_caption(struct KTUIDlg * dlg,VFSManager * vfs_mgr,uint32_t id,const char * internal_path)80 rc_t set_native_caption( struct KTUIDlg * dlg, VFSManager * vfs_mgr, uint32_t id, const char * internal_path )
81 {
82 	tui_rect r;
83 	rc_t rc = KTUIDlgGetWidgetRect ( dlg, id, &r );
84 	if ( rc == 0 )
85 	{
86 		size_t written = 0;
87 		char native[ 4096 ] = "";
88 		rc = internal_to_native( vfs_mgr, internal_path, native, sizeof native, &written );
89 		if ( rc == 0 )
90 		{
91 			if ( written <= ( r.w - 2 ) )
92 				rc = KTUIDlgSetWidgetCaption ( dlg, id, native );
93 			else
94 			{
95 				size_t written_2;
96 				char temp[ 4096 ];
97 				uint32_t part = ( r.w - 3 ) / 2;
98 				rc = string_printf ( temp, sizeof temp, &written_2,
99 						"%.*s ... %s", part, native, &native[ ( written - part ) - 1 ] );
100 				if ( rc == 0 )
101 					rc = KTUIDlgSetWidgetCaption ( dlg, id, temp );
102 			}
103 		}
104 	}
105 	return rc;
106 }
107 
108 
109 typedef struct dir_callback_ctx
110 {
111 	struct KTUIDlg * dlg;
112 	const char * str_to_focus;
113 	uint32_t widget_id;
114 	uint32_t string_id;
115 	uint32_t to_focus;
116     bool in_root;
117 } dir_callback_ctx;
118 
119 
add_str_to_listbox(dir_callback_ctx * dctx,const char * name)120 static rc_t add_str_to_listbox( dir_callback_ctx * dctx, const char * name )
121 {
122     rc_t rc = 0;
123     if ( dctx->in_root )
124     {
125 #ifdef WINDOWS
126         size_t written;
127         char buffer[ 16 ];
128         rc = string_printf( buffer, sizeof buffer, &written, "%s:\\", name );
129         if ( rc == 0 && written > 0 )
130             rc = KTUIDlgAddWidgetString ( dctx->dlg, dctx->widget_id, buffer );
131 #else
132         rc = KTUIDlgAddWidgetString ( dctx->dlg, dctx->widget_id, name );
133 #endif
134     }
135     else
136         rc = KTUIDlgAddWidgetString ( dctx->dlg, dctx->widget_id, name );
137     return rc;
138 }
139 
adjust_path(KDirectory * dir,const char * path_in,char * buffer,size_t buffer_size,const char ** path_ptr)140 static rc_t adjust_path( KDirectory * dir, const char * path_in,
141                          char * buffer, size_t buffer_size, const char ** path_ptr )
142 {
143     rc_t rc = 0;
144     uint32_t pt = KDirectoryPathType( dir, "%s", path_in );
145     if ( pt != kptDir )
146     {
147         if ( pt == kptFile )
148         {
149             size_t l = string_size( path_in );
150             if ( l >= buffer_size )
151             {
152                 rc = RC( rcFS, rcFile, rcValidating, rcParam, rcInvalid );
153             }
154             else
155             {
156                 char * p = string_rchr ( path_in, l, '/' );
157                 if ( p == NULL )
158                 {
159                     rc = RC( rcFS, rcFile, rcValidating, rcParam, rcInvalid );
160                 }
161                 else
162                 {
163                     size_t pp = ( p - path_in );
164                     string_copy ( buffer, buffer_size, path_in, l );
165                     buffer[ pp ] = 0;
166                     *path_ptr = buffer;
167                 }
168             }
169         }
170         else
171         {
172             rc = RC( rcFS, rcFile, rcValidating, rcParam, rcInvalid );
173         }
174     }
175     else
176     {
177         *path_ptr = path_in;
178     }
179     return rc;
180 }
181 
fill_widget_with_dirs(struct KTUIDlg * dlg,KDirectory * dir,uint32_t id,const char * path,const char * to_focus,bool clear)182 rc_t fill_widget_with_dirs( struct KTUIDlg * dlg, KDirectory * dir, uint32_t id,
183                             const char * path, const char * to_focus, bool clear )
184 {
185     rc_t rc = 0;
186     char buffer[ 4096 ];
187     const char *path_ptr;
188 
189     dir_callback_ctx dctx;
190     dctx.string_id = 0;
191     dctx.to_focus = 0;
192     dctx.str_to_focus = to_focus;
193     dctx.in_root = ( ( path[ 0 ] == '/' )&&( path[ 1 ] == 0 ) );
194     dctx.dlg = dlg;
195     dctx.widget_id = id;
196 
197     if ( clear )
198     {
199         rc = KTUIDlgRemoveAllWidgetStrings ( dlg, id );
200         if ( rc == 0 )
201         {
202             if ( !dctx.in_root )
203             {
204                 rc = KTUIDlgAddWidgetString ( dlg, id, "[ .. ]" );
205                 dctx.string_id++;
206             }
207         }
208     }
209 
210     if ( rc == 0 )
211     {
212         /* check if path is actually a file-path, if not look if it is a file-name,
213            in this case extract the path... */
214         rc = adjust_path( dir, path, buffer, sizeof buffer, &path_ptr );
215     }
216 
217     if ( rc == 0 )
218     {
219         VNamelist * dir_list;
220         rc = ReadDirEntriesIntoToNamelist( &dir_list, dir, true, false, true, path_ptr );
221         if ( rc == 0 )
222         {
223             uint32_t idx, count;
224             rc = VNameListCount( dir_list, &count );
225             for ( idx = 0; rc == 0 && idx < count; ++idx )
226             {
227                 const char * name = NULL;
228                 rc = VNameListGet( dir_list, idx, &name );
229                 if ( rc == 0 && name != NULL )
230                 {
231                     rc = add_str_to_listbox( &dctx, name );
232                     if ( rc == 0 )
233                     {
234                         if ( dctx.str_to_focus != NULL )
235                         {
236                             int cmp = string_cmp ( name, string_size( name ),
237                                                    dctx.str_to_focus, string_size( dctx.str_to_focus ), 4096 );
238                             if ( cmp == 0 )
239                                 dctx.to_focus = dctx.string_id;
240                         }
241                         dctx.string_id++;
242                     }
243                 }
244             }
245             VNamelistRelease( dir_list );
246         }
247     }
248 
249     if ( rc == 0 && dctx.to_focus > 0 )
250         rc = KTUIDlgSetWidgetSelectedString ( dlg, id, dctx.to_focus );
251 
252     return rc;
253 }
254 
255 
fill_widget_with_files(struct KTUIDlg * dlg,KDirectory * dir,uint32_t id,const char * path,const char * extension,bool clear)256 rc_t fill_widget_with_files( struct KTUIDlg * dlg, KDirectory * dir, uint32_t id,
257                              const char * path, const char * extension, bool clear )
258 {
259     rc_t rc = 0;
260     char buffer[ 4096 ];
261     const char *path_ptr;
262 
263     if ( clear )
264     {
265         rc = KTUIDlgRemoveAllWidgetStrings ( dlg, id );
266     }
267 
268     if ( rc == 0 )
269     {
270         /* check if path is actually a file-path, if not look if it is a file-name,
271            in this case extract the path... */
272         rc = adjust_path( dir, path, buffer, sizeof buffer, &path_ptr );
273     }
274 
275     if ( rc == 0 )
276     {
277         VNamelist * file_list;
278         rc = ReadDirEntriesIntoToNamelist( &file_list, dir, true, true, false, path_ptr );
279         if ( rc == 0 )
280         {
281             uint32_t idx, count;
282             rc = VNameListCount( file_list, &count );
283             for ( idx = 0; rc == 0 && idx < count; ++idx )
284             {
285                 const char * name = NULL;
286                 rc = VNameListGet( file_list, idx, &name );
287                 if ( rc == 0 && name != NULL && name[ 0 ] != 0 && name[ 0 ] != '.' )
288                 {
289                     bool add = ( extension == NULL );
290                     if ( !add )
291                     {
292                         size_t name_size = string_size ( name );
293                         size_t ext_size = string_size ( extension );
294                         if ( name_size > ext_size )
295                         {
296                             int cmp = string_cmp ( &name[ name_size - ext_size ], ext_size,
297                                                    extension, ext_size, (uint32_t)ext_size );
298                             add = ( cmp == 0 );
299                         }
300                     }
301                     if ( add )
302                         rc = KTUIDlgAddWidgetString( dlg, id, name );
303                 }
304             }
305             VNamelistRelease( file_list );
306         }
307     }
308     return rc;
309 }
310