wd
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
dir_list.c
Go to the documentation of this file.
1 /*
2  Copyright 2013 John Bailey
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16 
17 #include "dir_list.h"
18 #include "cmdln.h"
19 #if defined WIN32
20 #include <windows.h>
21 #endif
22 
23 #define FILE_HEADER_DESC_STRING "# WD directory list file"
24 #define FILE_HEADER_VER_STRING "# File format: version 1"
25 
26 #define USE_FAVOURITES_FILE_STR "USE_FAVOURITES"
27 
28 #define TIME_FORMAT_STRING "%Y/%m/%d %H:%M:%S"
29 #define TIME_SSCAN_STRING "%04u/%02u/%02u %02u:%02u:%02u"
30 #define TIME_STRING_BUFFER_SIZE (30U)
31 
32 #define ANSI_COLOUR_RED "\x1b[31m"
33 #define ANSI_COLOUR_GREEN "\x1b[32m"
34 #define ANSI_COLOUR_GREY "\x1b[37;2m"
35 #define ANSI_COLOUR_RESET "\x1b[0m"
36 
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <assert.h>
40 #include <string.h>
41 #include <errno.h>
42 #include <sys/param.h>
43 #include <sys/stat.h>
44 #include <time.h>
45 
46 #define MIN_DIR_SIZE 100
47 
48 /* TODO: Since chage #6, we support files as well as directories, so all of the
49  "dir" references in this file are a little misleading */
50 
52 {
53  char* dir_name;
55  time_t time_added;
56  time_t time_accessed;
58  /* TODO: Other data here? Time last usedc
59  Meta-data such as whether it exists? Shortcut name? */
60 };
61 
62 #define DLI_SIZE (sizeof( struct dir_list_item ))
63 
64 struct dir_list_s
65 {
66  size_t dir_count;
68  int dir_size;
69 
70  /* TODO: Is it the best thing to store the config here? config contains
71  things that this class doesn't care about */
73 };
74 
75 static wd_entity_t get_type( const char* const p_path );
76 static dir_list_t load_dir_list_from_file( const config_container_t* const p_config,
77  const char* const p_fn );
78 static dir_list_t load_dir_list_from_favourites( const config_container_t* const p_config,
79  const char* const p_fn );
80 
81 
82 static void increase_dir_alloc( dir_list_t p_list )
83 {
84  struct dir_list_item* new_mem;
85  p_list->dir_size += MIN_DIR_SIZE;
86 
87  new_mem =
88  (struct dir_list_item*) realloc( p_list->dir_list,
89  p_list->dir_size * DLI_SIZE );
90  if( new_mem != NULL )
91  {
92  p_list->dir_list = new_mem;
93  }
94 }
95 
96 int add_dir( dir_list_t p_list,
97  const char* const p_dir,
98  const char* const p_name,
99  const time_t p_t_added,
100  const time_t p_t_accessed,
101  const wd_entity_t p_type )
102 {
103  /* TODO: Check that item is of type p_list->cfg->wd_entity_type? */
104  int ret_val = 0;
105  char* dest = NULL;
106  const size_t idx = p_list->dir_count;
107 
108  if( idx == p_list->dir_size )
109  {
110  DEBUG_OUT("list does not have space, increasing allocation");
111  increase_dir_alloc( p_list );
112  DEBUG_OUT("increased allocation");
113  }
114 
115  /* Check to see if there's space now - it's possible that an attempt to
116  increase the allocation (above) actually failed */
117  if( idx < p_list->dir_size )
118  {
119  dest = (char*)malloc( strlen( p_dir ) + 1);
120  if( dest != NULL ) {
121  strcpy( dest, p_dir );
122  p_list->dir_list[ idx ].dir_name = dest;
123 
124  if( p_name != NULL )
125  {
126  dest = (char*)malloc( strlen( p_name ) + 1);
127  if( dest != NULL ) {
128  strcpy( dest, p_name );
129  p_list->dir_list[ idx ].bookmark_name = dest;
130  ret_val = 1;
131  } else {
132  p_list->dir_list[ idx ].bookmark_name = NULL;
133  }
134  } else {
135  p_list->dir_list[ idx ].bookmark_name = NULL;
136  ret_val = 1;
137  }
138 
139  if( ret_val ) {
140  p_list->dir_list[ idx ].time_added = p_t_added;
141  p_list->dir_list[ idx ].time_accessed = p_t_accessed;
142  if( p_type == WD_ENTITY_UNKNOWN ) {
143  p_list->dir_list[ idx ].type = get_type( dest );
144  } else {
145  p_list->dir_list[ idx ].type = p_type;
146  }
147 
148  p_list->dir_count++;
149  }
150  }
151  }
152 
153  return( ret_val );
154 }
155 
157 {
158  dir_list_t ret_val = (dir_list_t)malloc( sizeof( struct dir_list_s ) );
159 
160  if( ret_val != NULL ) {
161  ret_val->dir_count = 0;
162  ret_val->dir_list = NULL;
163  ret_val->dir_size = 0;
164 
165  /* Allocate some initial memory for the directory list - this saves us
166  having to deal with dir_list being NULL in the general case */
167  increase_dir_alloc( ret_val );
168  }
169 
170  return( ret_val );
171 }
172 
173 static time_t sscan_time( const char* const p_str )
174 {
175  time_t ret_val;
176  struct tm tm;
177  tm.tm_isdst = -1;
178  tm.tm_yday = -1;
179  tm.tm_wday = -1;
180  sscanf(p_str, TIME_SSCAN_STRING,
181  &tm.tm_year,
182  &tm.tm_mon,
183  &tm.tm_mday,
184  &tm.tm_hour,
185  &tm.tm_min,
186  &tm.tm_sec);
187 
188  /* tm's year is baselined at 1900 */
189  tm.tm_year -= 1900;
190  /* tm's month is the count of months since Jan */
191  tm.tm_mon -= 1;
192 
193  /* This call will ensure that tm_yday is calculated - we need that for the
194  conversion below */
195  mktime( &tm );
196 
197  /* The time in the file is already UTC, so using
198  mktime is the wrong thing to do, as this assumes that
199  the contents of tm is in local time
200  see http://pubs.opengroup.org/onlinepubs/007904975/basedefs/xbd_chap04.html#tag_04_14 */
201  ret_val = tm.tm_sec +
202  tm.tm_min*60 +
203  tm.tm_hour*3600 +
204  tm.tm_yday*86400 +
205  (tm.tm_year-70)*31536000 +
206  ((tm.tm_year-69)/4)*86400 -
207  ((tm.tm_year-1)/100)*86400 +
208  ((tm.tm_year+299)/400)*86400;
209 
210  return ret_val;
211 }
212 
213 dir_list_t load_dir_list( const config_container_t* const p_config, const char* const p_fn )
214 {
215  dir_list_t ret_val = NULL;
216 #if defined _WIN32
217  if( 0 == strcmp( p_fn, USE_FAVOURITES_FILE_STR )) {
218  ret_val = load_dir_list_from_favourites( p_config, p_fn );
219  } else {
220 #endif
221  ret_val = load_dir_list_from_file( p_config, p_fn );
222 #if defined _WIN32
223  }
224 #endif
225  return ret_val;
226 }
227 
228 #if defined _WIN32
229 #include <shlobj.h>
230 #include <dirent.h>
231 static dir_list_t load_dir_list_from_favourites( const config_container_t* const p_config, const char* const p_fn )
232 {
233  dir_list_t ret_val = NULL;
234  TCHAR path[MAX_PATH];
235  HRESULT hr = SHGetFolderPath(0, CSIDL_FAVORITES, 0, 0, path);
236 
237  if (SUCCEEDED(hr)) {
238  DIR* FD;
239  DEBUG_OUT("got favourites drectory: %s", path);
240  /* TODO: recurse sub-directories */
241  if (NULL != (FD = opendir (path)))
242  {
243  struct dirent* in_file;
244  DEBUG_OUT("opened favourites drectory: %s", path);
245  ret_val = new_dir_list();
246  ret_val->cfg = p_config;
247  while ((in_file = readdir(FD)))
248  {
249  if((0 != strcmp (in_file->d_name, ".")) &&
250  (0 != strcmp (in_file->d_name, "..")))
251  {
252  size_t len = strlen( in_file->d_name );
253  if(( len > 4 ) &&
254  ( 0 == stricmp( &(in_file->d_name[len-4]), ".ini" ))) {
255  char path[ MAXPATHLEN ];
256  char name[ MAXPATHLEN ];
257  time_t added;
258  time_t accessed;
259  wd_entity_t ent_type;
260 
261  DEBUG_OUT("found file: %s",in_file->d_name);
262 
263  strncpy( name, in_file->d_name, len-4 );
264 
265 
266  /* TODO */
267  path[0] = 0;
268  added = -1;
269  accessed = -1;
270  ent_type = WD_ENTITY_UNKNOWN;
271 
272 
273  add_dir( ret_val, path, name, added, accessed,
274  ent_type );
275 
276  DEBUG_OUT("created new bookmark");
277  }
278  }
279  }
280  }
281  }
282  return ret_val;
283 }
284 #endif
285 
286 static dir_list_t load_dir_list_from_file( const config_container_t* const p_config, const char* const p_fn )
287 {
288  FILE* file = fopen( p_fn, "rt" );
289  dir_list_t ret_val = NULL;
290 
291  if( file != NULL ) {
292  DEBUG_OUT("opened bookmark file");
293  ret_val = new_dir_list();
294  ret_val->cfg = p_config;
295 
296  if( ret_val != NULL ) {
297  char path[ MAXPATHLEN ];
298  char read[ MAXPATHLEN ];
299  char name[ MAXPATHLEN ];
300  time_t added;
301  time_t accessed;
302  char* fstr;
303  int one_last_go = 1;
304  wd_entity_t ent_type;
305 
306  path[0] = 0;
307  name[0] = 0;
308  added = -1;
309  accessed = -1;
310  ent_type = WD_ENTITY_UNKNOWN;
311  DEBUG_OUT("generated empty bookmark list");
312 
313  while(( fstr = fgets( read, MAXPATHLEN, file ) ) ||
314  one_last_go ) {
315  DEBUG_OUT("read from file: %s",read);
316  /* Didn't get anything from the file? Set the read string to
317  indicate that it's a new bookmark so that we flush out
318  any previous bookmark data and flag that we don't need to go
319  round again ( one_last_go ) */
320  if( fstr == NULL ) {
321  read[0] = ':';
322  read[1] = 0;
323  one_last_go = 0;
324  }
325 
326  /* Check that it wasn't a comment line */
327  if( read[0] != '#' ) {
328  size_t len = strlen( read );
329 
330  /* Trim off line endings */
331  size_t trimmer;
332  for( trimmer = len - 1;
333  trimmer > 0;
334  trimmer-- ) {
335  if(( read[ trimmer ] == '\r' ) ||
336  ( read[ trimmer ] == '\n' )) {
337  read[ trimmer ] = 0;
338  } else {
339  break;
340  }
341  }
342 
343  /* Is this the start of a new bookmark? */
344  if( read[0] == ':' ) {
345  /* Already read some bookmark details? */
346  if ( path[0] != '\0' ) {
347 
348  DEBUG_OUT("creating new bookmark: %s",path);
349 
350  /* Create the new bookmark and reset attributes */
351  add_dir( ret_val, path, name, added, accessed,
352  ent_type );
353 
354  DEBUG_OUT("created new bookmark");
355 
356  path[0] = 0;
357  name[0] = 0;
358  added = -1;
359  accessed = -1;
360  ent_type = WD_ENTITY_UNKNOWN;
361  }
362  strcpy( path, &(read[1]) );
363  } else if(( read[0] == 'N' ) &&
364  ( read[1] == ':' )) {
365  strcpy( name, &(read[2]) );
366  } else if(( read[0] == 'A' ) &&
367  ( read[1] == ':' )) {
368  added = sscan_time(&(read[2]));
369  } else if(( read[0] == 'C' ) &&
370  ( read[1] == ':' )) {
371  accessed = sscan_time(&(read[2]));
372  } else if(( read[0] == 'T' ) &&
373  ( read[1] == ':' )) {
374  switch(read[2]) {
375  case 'D':
376  ent_type = WD_ENTITY_DIR;
377  break;
378  case 'F':
379  ent_type = WD_ENTITY_FILE;
380  break;
381  default:
382  ent_type = WD_ENTITY_UNKNOWN;
383  break;
384  }
385  } else {
386  fprintf(stderr,
387  "Unrecognised content in bookmarks file: %s\n",
388  read);
389  }
390  }
391  }
392  }
393  fclose( file );
394  }
395 
396  return( ret_val );
397 }
398 
399 int bookmark_in_list( dir_list_t p_list, const char* const p_name )
400 {
401  int ret_val = 0;
402  size_t dir_loop;
403  struct dir_list_item* current_item = p_list->dir_list;
404 
405  for( dir_loop = 0; dir_loop < p_list->dir_count; dir_loop++, current_item++ )
406  {
407  if((current_item->bookmark_name != NULL ) &&
408  (0 == strcmp( p_name, current_item->bookmark_name ))) {
409  ret_val = 1;
410  break;
411  }
412  }
413 
414  return( ret_val );
415 }
416 
417 static int find_dir_location( dir_list_t p_list, const char* const p_dir, size_t* p_loc )
418 {
419  int ret_val = 0;
420  size_t dir_loop;
421  struct dir_list_item* current_item = p_list->dir_list;
422 
423  for( dir_loop = 0; dir_loop < p_list->dir_count; dir_loop++, current_item++ )
424  {
425  if( 0 == strcmp( p_dir, current_item->dir_name )) {
426  ret_val = 1;
427  if( p_loc != NULL ) {
428  *p_loc = dir_loop;
429  }
430  break;
431  }
432  }
433 
434  return( ret_val );
435 }
436 
437 int remove_dir_by_index( dir_list_t p_list, const size_t p_dir )
438 {
439  int ret_val = 0;
440 
441  if( p_dir < p_list->dir_count ) {
442  p_list->dir_count--;
443 
444  /* Must use memmove here not memcpy as regions overlap */
445  memmove(&(p_list->dir_list[p_dir]),
446  &(p_list->dir_list[p_dir+1]),
447  (p_list->dir_count - p_dir) * DLI_SIZE );
448 
449  ret_val = 1;
450  }
451 
452  return( ret_val );
453 }
454 
455 int remove_dir( dir_list_t p_list, const char* const p_dir )
456 {
457  int ret_val = 0;
458  size_t location;
459 
460  if( find_dir_location( p_list, p_dir, &location )) {
461  ret_val = remove_dir_by_index( p_list, location );
462  }
463 
464  return( ret_val );
465 }
466 
467 int dir_in_list( dir_list_t p_list, const char* const p_dir )
468 {
469  return( find_dir_location( p_list, p_dir, NULL ) );
470 }
471 
472 #define CYGDRIVE_PREFIX "/cygdrive/"
473 
474 char* format_dir( wd_dir_format_t p_fmt, char* p_dir ) {
475  char* ret_val = NULL;
476 
477  switch( p_fmt ) {
478  case WD_DIRFORM_NONE:
479  ret_val = p_dir;
480  break;
481  case WD_DIRFORM_CYGWIN: {
482  char* dest;
483  char* src = p_dir;
484  ret_val = (char*)malloc( strlen( p_dir ) + 14 );
485  dest = ret_val;
486  if(((( src[0] >= 'a' ) && (src[0] <= 'z' )) ||
487  (( src[0] >= 'A' ) && (src[0] <= 'Z' ))) &&
488  ( src[1] == ':' ) &&
489  (( src[2] == '\\') ||
490  ( src[2] == '/' )))
491  {
492  strcpy( ret_val, CYGDRIVE_PREFIX );
493  dest += strlen( CYGDRIVE_PREFIX );
494  *dest = *src;
495  dest++;
496  src += 2;
497  }
498  for( ;
499  *src != '\0';
500  dest++, src++ ) {
501  if( *src == '\\' ) {
502  *dest = '/';
503  } else {
504  *dest = *src;
505  }
506  }
507  *dest = 0;
508  }
509  break;
510  case WD_DIRFORM_WINDOWS: {
511  char* dest;
512  char* src;
513  ret_val = (char*)malloc( strlen( p_dir ) + 1 );
514  src = p_dir;
515  dest = ret_val;
516  if( strncmp( src, CYGDRIVE_PREFIX, strlen( CYGDRIVE_PREFIX )) == 0 )
517  {
518  src += strlen( CYGDRIVE_PREFIX );
519  *dest = *src;
520  dest++;
521  *dest = ':';
522  dest++;
523  src += 1;
524  }
525  for( ;
526  *src != '\0';
527  dest++, src++ ) {
528  if( *src == '/' ) {
529  *dest = '\\';
530  } else {
531  *dest = *src;
532  }
533  }
534  *dest = 0;
535  }
536  break;
537 
538  default:
539  fprintf(stderr,"Unhandled directory format\n");
540  ret_val = p_dir;
541  break;
542  }
543 
544  return( ret_val );
545 }
546 
547 int dump_dir_if_exists( const dir_list_t p_list, const char* const p_dir )
548 {
549  size_t dir_loop;
550  struct dir_list_item* current_item;
551  int found = 0;
552 
553  for( dir_loop = 0, current_item = p_list->dir_list;
554  dir_loop < p_list->dir_count;
555  dir_loop++, current_item++ )
556  {
557  /* TODO: Case insensitive on Windows? Case insensitive switch? */
558  if(( current_item->bookmark_name != NULL ) &&
559  ( 0 == strcmp( p_dir, current_item->dir_name ))) {
560 
561  char* dir_formatted = format_dir( p_list->cfg->wd_dir_form,
562  current_item->dir_name );
563  fprintf( stdout, "%s", dir_formatted );
564 
565  if( current_item->dir_name != dir_formatted ) {
566  free( dir_formatted );
567  }
568 
569  if( p_list->cfg->wd_store_access ) {
570  current_item->time_accessed = p_list->cfg->wd_now_time;
571  }
572 
573  found = 1;
574  break;
575  }
576  }
577  return( found );
578 }
579 
580 int dump_dir_with_name( const dir_list_t p_list, const char* const p_name )
581 {
582  size_t dir_loop;
583  struct dir_list_item* current_item;
584  int found = 0;
585 
586  for( dir_loop = 0, current_item = p_list->dir_list;
587  dir_loop < p_list->dir_count;
588  dir_loop++, current_item++ )
589  {
590  if(( current_item->bookmark_name != NULL ) &&
591  ( 0 == strcmp( p_name, current_item->bookmark_name ))) {
592 
593  char* dir_formatted = format_dir( p_list->cfg->wd_dir_form,
594  current_item->dir_name );
595  fprintf( stdout, "%s", dir_formatted );
596 
597  if( current_item->dir_name != dir_formatted ) {
598  free( dir_formatted );
599  }
600 
601  if( p_list->cfg->wd_store_access ) {
602  current_item->time_accessed = p_list->cfg->wd_now_time;
603  }
604 
605  found = 1;
606  break;
607  }
608  }
609 
610  return( found );
611 }
612 
613 static wd_entity_t get_type( const char* const p_path )
614 {
615  wd_entity_t ret_val = WD_ENTITY_UNKNOWN;
616  struct stat s;
617  int err = stat( p_path , &s);
618 
619  if( err == -1 )
620  {
621  if(ENOENT == errno) {
622  ret_val = WD_ENTITY_NONEXISTANT;
623  }
624  } else {
625  if( S_ISDIR(s.st_mode) ) {
626  ret_val = WD_ENTITY_DIR;
627  } else if( S_ISREG( s.st_mode )) {
628  ret_val = WD_ENTITY_FILE;
629  }
630  }
631 
632  return ret_val;
633 }
634 
635 void list_dirs( const dir_list_t p_list )
636 {
637  if( p_list == NULL )
638  {
639  fprintf( stdout, "Empty dirlist structure\n" );
640  } else {
641  size_t dir_loop;
642  struct dir_list_item* current_item;
643  int valid;
644 
645  for( dir_loop = 0, current_item = p_list->dir_list;
646  dir_loop < p_list->dir_count;
647  dir_loop++, current_item++ )
648  {
649  char* dir = current_item->dir_name;
650  valid = 1;
651 
652  /* TODO: Update current_item->type here? */
653 
654  /* TODO: take notice of wd_output_all here */
655 
656  /* Check to see if this item matches the filter */
657  if((p_list->cfg->wd_entity_type != WD_ENTITY_ANY) &&
658  (p_list->cfg->wd_entity_type != current_item->type )) {
659  /* No, don't output */
660  valid = 0;
661  } else if( 0 == p_list->cfg->wd_output_all ) {
662  /* TODO: Update current_item->type here? */
663  wd_entity_t type = get_type( dir );
664 
665  /* Check to see if it's other than a file or directory (ie. a valid
666  entity */
667  if(( type != WD_ENTITY_DIR ) &&
668  ( type != WD_ENTITY_FILE ))
669  {
670  valid = 0;
671  }
672  }
673 
674  if( valid ) {
675  char* dir_formatted = format_dir( p_list->cfg->wd_dir_form,
676  dir );
677  fprintf( stdout, "%s\n", dir_formatted );
678  if( current_item->bookmark_name != NULL ) {
679  fprintf( stdout, "%s\n", current_item->bookmark_name );
680  }
681  if( dir != dir_formatted ) {
682  free( dir_formatted );
683  }
684  }
685  }
686  }
687 }
688 
690 {
691  int ret_val = 0;
692  char* term = getenv("TERM");
693 
694  if( term != NULL ) {
695  if(( strcmp( term, "vt100" ) == 0 ) ||
696  ( strcmp( term, "xterm" ) == 0 )) {
697  ret_val = 1;
698  }
699  }
700 
701  return ret_val;
702 }
703 
704 #if defined WIN32
705 WORD TextColour(WORD fontcolor)
706 {
707  HANDLE h = GetStdHandle ( STD_OUTPUT_HANDLE );
708  CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
709  WORD wOldColorAttrs;
710 
711  GetConsoleScreenBufferInfo(h, &csbiInfo);
712  wOldColorAttrs = csbiInfo.wAttributes;
713 
714  /* Seems to return 0 (i.e. fail) from Mintty, but otherwise no adverse
715  side-effects */
716  SetConsoleTextAttribute(h,fontcolor);
717 
718  return wOldColorAttrs;
719 }
720 #endif
721 
722 static void dump_time( const char* const p_header, const time_t* const p_time )
723 {
724  char buffer[ TIME_STRING_BUFFER_SIZE ];
725 
726  strftime( buffer, sizeof( buffer ), "%c %Z",
727  gmtime( p_time ));
728 
729  fprintf( stdout, "\n - %s: %s",
730  p_header,
731  buffer );
732 }
733 
734 void dump_dir_list( const dir_list_t p_list )
735 {
736  if( p_list == NULL )
737  {
738  fprintf( stdout, "Empty dirlist structure\n" );
739  } else {
740  size_t dir_loop;
741  struct dir_list_item* current_item;
742  int term_is_ansi = determine_if_term_is_ansi();
743 
744  fprintf( stdout, "Dirlist has %d entries of %d used\n",
745  p_list->dir_count, p_list->dir_size );
746 
747  for( dir_loop = 0, current_item = p_list->dir_list;
748  dir_loop < p_list->dir_count;
749  dir_loop++, current_item++ )
750  {
751 #if defined WIN32
752  int wcol = -1;
753  WORD wOldColorAttrs;
754 #endif
755  char* col = ANSI_COLOUR_RESET;
756  char* dir = current_item->dir_name;
757  char* dir_formatted;
758 
759  current_item->type = get_type( dir );
760 
761  if( current_item->type == WD_ENTITY_NONEXISTANT ) {
762 #if defined WIN32
763  wcol = FOREGROUND_INTENSITY;
764 #endif
765  col = ANSI_COLOUR_GREY;
766  } else if((p_list->cfg->wd_entity_type != WD_ENTITY_ANY) &&
767  (p_list->cfg->wd_entity_type != current_item->type )) {
768 #if defined WIN32
769  wcol = FOREGROUND_RED;
770 #endif
771  col = ANSI_COLOUR_RED;
772  } else {
773 #if defined WIN32
774  wcol = FOREGROUND_GREEN;
775 #endif
776  col = ANSI_COLOUR_GREEN;
777  }
778 
779  fprintf( stdout, "[%3d] ", dir_loop);
780 #if defined WIN32
781  if( wcol != -1 ) {
782  wOldColorAttrs = TextColour(wcol);
783  }
784 #endif
785  if( term_is_ansi ) {
786  fprintf( stdout, "%s", col );
787  }
788 
789  dir_formatted = format_dir( p_list->cfg->wd_dir_form, dir );
790  fprintf( stdout, "%s", dir_formatted );
791 
792  if( current_item->dir_name != dir_formatted ) {
793  fprintf( stdout, "\n - Unconverted: %s",
794  dir);
795  free( dir_formatted );
796  }
797 
798  if(( current_item->bookmark_name != NULL ) &&
799  ( current_item->bookmark_name[0] != 0 )) {
800  fprintf( stdout, "\n - Shorthand: %s",
801  current_item->bookmark_name);
802  }
803  if( current_item->time_added != -1 ) {
804  dump_time( "Added", &( current_item->time_added ) );
805  }
806  if( current_item->time_accessed != -1 ) {
807  dump_time( "Accessed", &( current_item->time_accessed ) );
808  }
809 #if defined WIN32
810  if( wcol != -1 ) {
811  TextColour(wOldColorAttrs);
812  }
813 #endif
814  if( term_is_ansi ) {
815  fprintf( stdout, "%s", ANSI_COLOUR_RESET );
816  }
817  printf("\n");
818  }
819  }
820 }
821 
822 int save_dir_list( const dir_list_t p_list, const char* p_fn ) {
823  int ret_val = 0;
824  FILE* file;
825 
826  assert( p_fn != NULL );
827  assert( p_list != NULL );
828 
829  file = fopen( p_fn, "wt" );
830  /* TODO: File locking here? flock? lockf? */
831 
832  if( file != NULL ) {
833  size_t dir_loop;
834  fprintf( file, "%s\n%s\n", FILE_HEADER_DESC_STRING,
836 
837  for( dir_loop = 0; dir_loop < p_list->dir_count; dir_loop++ )
838  {
839  struct dir_list_item* this_item = &(p_list->dir_list[ dir_loop ]);
840  char* type_string;
841  fprintf( file, ":%s\n",
842  this_item->dir_name );
843  if(( this_item->bookmark_name != NULL ) &&
844  ( this_item->bookmark_name[0] != 0 )) {
845  fprintf( file, "N:%s\n",
846  this_item->bookmark_name );
847  }
848  if( this_item->time_added != -1 ) {
849  char buff[ TIME_STRING_BUFFER_SIZE ];
850 
851  if (strftime(buff, sizeof( buff ), TIME_FORMAT_STRING,
852  gmtime( &(this_item->time_added) ))) {
853  fprintf( file, "A:%s\n",buff);
854  }
855  }
856  if( this_item->time_accessed != -1 ) {
857  char buff[ TIME_STRING_BUFFER_SIZE ];
858 
859  if (strftime(buff, sizeof( buff ), TIME_FORMAT_STRING,
860  gmtime( &(this_item->time_accessed) ))) {
861  fprintf( file, "C:%s\n",buff);
862  }
863  }
864 
865  /* Refresh the type.
866  TODO: This may be over-zealous if it has already been done */
867  this_item->type = get_type( this_item->dir_name );
868 
869  switch( this_item->type )
870  {
871  case WD_ENTITY_DIR:
872  type_string = "D";
873  break;
874  case WD_ENTITY_FILE:
875  type_string = "F";
876  break;
877  default:
878  type_string = "U";
879  break;
880  }
881  fprintf( file, "T:%s\n",type_string);
882  }
883 
884  fclose( file );
885  ret_val = 1;
886  }
887 
888  return( ret_val );
889 }
int dir_in_list(dir_list_t p_list, const char *const p_dir)
Definition: dir_list.c:467
char * format_dir(wd_dir_format_t p_fmt, char *p_dir)
Definition: dir_list.c:474
#define FILE_HEADER_VER_STRING
Definition: dir_list.c:24
void list_dirs(const dir_list_t p_list)
Definition: dir_list.c:635
int wd_output_all
Control whether or not all items should be output regardless of whether or not they seem to point to ...
Definition: cmdln.h:73
#define DEBUG_OUT(...)
Definition: cmdln.h:86
#define DLI_SIZE
Definition: dir_list.c:62
time_t time_added
Definition: dir_list.c:55
int dump_dir_with_name(const dir_list_t p_list, const char *const p_name)
Definition: dir_list.c:580
time_t wd_now_time
Time to use as the current time when manipulating datestamps.
Definition: cmdln.h:68
#define ANSI_COLOUR_GREY
Definition: dir_list.c:34
size_t dir_count
Definition: dir_list.c:66
#define TIME_SSCAN_STRING
Definition: dir_list.c:29
struct dir_list_item * dir_list
Definition: dir_list.c:67
wd_entity_t type
Definition: dir_list.c:57
#define TIME_STRING_BUFFER_SIZE
Definition: dir_list.c:30
struct dir_list_s * dir_list_t
Structure to represent a list of directory bookmarks.
Definition: dir_list.h:34
#define FILE_HEADER_DESC_STRING
Definition: dir_list.c:23
The dir_list module provides functions to manipulate and search the list of bookmarks.
wd_entity_t
Definition: cmdln.h:32
int dump_dir_if_exists(const dir_list_t p_list, const char *const p_dir)
Definition: dir_list.c:547
char * dir_name
Definition: dir_list.c:53
dir_list_t load_dir_list(const config_container_t *const p_config, const char *const p_fn)
Load a set of bookmarks from the specified file.
Definition: dir_list.c:213
int bookmark_in_list(dir_list_t p_list, const char *const p_name)
Definition: dir_list.c:399
int determine_if_term_is_ansi()
Definition: dir_list.c:689
#define USE_FAVOURITES_FILE_STR
Definition: dir_list.c:26
time_t time_accessed
Definition: dir_list.c:56
const config_container_t * cfg
Definition: dir_list.c:72
#define TIME_FORMAT_STRING
Definition: dir_list.c:28
int save_dir_list(const dir_list_t p_list, const char *p_fn)
Definition: dir_list.c:822
#define ANSI_COLOUR_GREEN
Definition: dir_list.c:33
int dir_size
Definition: dir_list.c:68
int remove_dir_by_index(dir_list_t p_list, const size_t p_dir)
Definition: dir_list.c:437
int add_dir(dir_list_t p_list, const char *const p_dir, const char *const p_name, const time_t p_t_added, const time_t p_t_accessed, const wd_entity_t p_type)
Definition: dir_list.c:96
int wd_store_access
Indicate whether or not access times should be stored in the bookmarks.
Definition: cmdln.h:64
void dump_dir_list(const dir_list_t p_list)
Definition: dir_list.c:734
#define MIN_DIR_SIZE
Definition: dir_list.c:46
char * bookmark_name
Definition: dir_list.c:54
#define ANSI_COLOUR_RESET
Definition: dir_list.c:35
wd_dir_format_t wd_dir_form
Format in which file paths should be output.
Definition: cmdln.h:51
wd_dir_format_t
Definition: cmdln.h:40
#define CYGDRIVE_PREFIX
Definition: dir_list.c:472
#define ANSI_COLOUR_RED
Definition: dir_list.c:32
wd_entity_t wd_entity_type
Control which types of entity should be included in the output.
Definition: cmdln.h:70
int remove_dir(dir_list_t p_list, const char *const p_dir)
Definition: dir_list.c:455
dir_list_t new_dir_list(void)
Create a new directory list structure.
Definition: dir_list.c:156