Source
...
Target
Commits (7)
  • Rik Griffin's avatar
    Redesigned window to show more of path. · 84527cc0
    Rik Griffin authored
    Added progress bar.
    Performance improvements, especially in 'slower' mode.
    Fixed 'count summary' bug.
    Fixed various compiler warnings.
    
    Version 0.49. Tagged as 'FilerAct-0_49'
    84527cc0
  • Rik Griffin's avatar
    Fixed progress bar bug in Filer Action. · 3d773e26
    Rik Griffin authored
    Progress bar was wrong during a CopyMove operation that required more
    memory than the available wimp slot.
    
    Version 0.50. Tagged as 'FilerAct-0_50'
    3d773e26
  • Robert Sprowson's avatar
    Didn't compile with PROGRESS_BAR turned off. · 62c87e72
    Robert Sprowson authored
    Rationalised all the switches a bit.
    Not tagged.
    62c87e72
  • Robert Sprowson's avatar
    Fix display of bytes-to-go when there are > 2G left. · b5fe2ebd
    Robert Sprowson authored
    Was doing a widening cast of a signed number to 64 bits, so showed 16 trillion bytes remaining.
    Fix templates to not say "stuff" by default in the name, as this was left on screen if an error occured before processing began.
    Things that read from clock() now use clock_t.
    Uncurled some "} else {" to match all the other files.
    Deleted the USE_LONG_LONG switch, it's been needed ever since harddiscs got bigger than 4G anyway.
    Anything assigned 'Yes' or 'No' changed to type BOOL.
    Variable 'source_of_finished_file' was signalling that a directory had been copied by setting the length to a -ve number. This has been refactored to use a BOOL instead, so files can have top bit set sizes.
    Fix bug in stack grab in count_objects_in_dir(), was grabbing an array of 2048 pointers (=8k) not 2048 bytes.
    Functions bytes_left_to_read() and bytes_left_to_write() reprototyped to return uint32_t not signed numbers.
    Still falls over copying files > 2G, but at least it gets the display right!
    
    Version 0.51. Tagged as 'FilerAct-0_51'
    b5fe2ebd
  • Robert Sprowson's avatar
    More BOOLs and things changed to C99 types. · 161f0f24
    Robert Sprowson authored
    Basically the same as version 0.51 otherwise.
    
    Version 0.52. Tagged as 'FilerAct-0_52'
    161f0f24
  • Robert Sprowson's avatar
    Swap magic constants for defines from headers. · 4b9400d5
    Robert Sprowson authored
    OS_FSControl, OS_File, OS_GBPB, OS_Args, OS_Find now use HighFSI.h.
    Indentation made more consistent.
    Variety of DEBUG macros changed to allow them to be enabled and disabled on a per-file basis.
    Put USE_RED_ERROR box switch into options.h (undefined though).
    Functionally equivalent to 0.52, but lots of diffs.
    
    Version 0.53. Tagged as 'FilerAct-0_53'
    4b9400d5
  • Robert Sprowson's avatar
    Fix to work with files > 2G. · 743fa9c2
    Robert Sprowson authored
    A good rake over the code to change filesizes to be uint32_t not ints.
    Change makefile to use StdTools.
    Shuffle icon clipping in the templates to allow for maximal numbers by moving the text a bit to the right, still fits even in system font.
    A couple more ints swapped for BOOLs.
    The memmanage code is largely unchanged and makes extensive use of signed numbers, partly because the wimpslot setting API does. This will all fall over in a big mess if the wimpslot ever gets >2G, but then the API would need changing for that to happen anyway.
    Function count_objects_in_dir swapped to use os_gbpb.
    Structure search_nest_level gains a 'counted' flag rather than signalling counting is needed by setting the filesize to -1.
    Should now be good for up to 4 billion files each of 4 billion bytes.
    
    Version 0.54. Tagged as 'FilerAct-0_54'
    743fa9c2
...@@ -30,17 +30,11 @@ EXP_HDR = <export$dir> ...@@ -30,17 +30,11 @@ EXP_HDR = <export$dir>
# #
# Generic options: # Generic options:
# #
MKDIR = cdir include StdTools
AS = objasm
CC = cc #DFLAGS = -Ddebugfile="\"RAM::0.$.out\""
CP = copy
LD = link
RM = remove
WIPE = -wipe
DFLAGS =
AFLAGS = -depend !Depend -Stamp -quit AFLAGS = -depend !Depend -Stamp -quit
CFLAGS = -c -depend !Depend -ffah ${INCLUDES} ${DFLAGS} CFLAGS = -c -throwback -depend !Depend -ffah ${INCLUDES} ${DFLAGS}
CPFLAGS = ~cfr~v CPFLAGS = ~cfr~v
WFLAGS = ~c~v WFLAGS = ~c~v
...@@ -130,12 +124,12 @@ install_rom: ${TARGET} ...@@ -130,12 +124,12 @@ install_rom: ${TARGET}
@echo ${COMPONENT}: rom module installed @echo ${COMPONENT}: rom module installed
clean: clean:
${WIPE} o.* ${WFLAGS} ${XWIPE} o.* ${WFLAGS}
${WIPE} oa.* ${WFLAGS} ${XWIPE} oa.* ${WFLAGS}
${WIPE} app.* ${WFLAGS} ${XWIPE} app.* ${WFLAGS}
${WIPE} rm.* ${WFLAGS} ${XWIPE} rm.* ${WFLAGS}
${WIPE} linked.* ${WFLAGS} ${XWIPE} linked.* ${WFLAGS}
${WIPE} map.* ${WFLAGS} ${XWIPE} map.* ${WFLAGS}
${RM} ${TARGET} ${RM} ${TARGET}
${RM} s.ModuleWrap ${RM} s.ModuleWrap
@echo ${COMPONENT}: cleaned @echo ${COMPONENT}: cleaned
......
No preview for this file type
...@@ -82,13 +82,16 @@ S:Slower ...@@ -82,13 +82,16 @@ S:Slower
77:Stamp 77:Stamp
78:Check 78:Check
79:continue the operation 79:continue the operation
80:Paused
80a32/80a36/80a41/80a46/80a51/80a56/80a62/80a67/80a82:Paused %c%s 80a32/80a36/80a41/80a46/80a51/80a56/80a62/80a67/80a82:Paused %c%s
81:There is a %s operation in progress. 81:There is a %s operation in progress.
82:Writing 82:Writing
84:Found 84:Found
85:Finished 85:Finished
86:%d locked item(s) not deleted 86:%d locked item(s) not deleted
87:Disc full
87a32/87a36/87a41/87a46/87a51/87a56/87a62/87a67/87a82:Disc full when %c%s 87a32/87a36/87a41/87a46/87a51/87a56/87a62/87a67/87a82:Disc full when %c%s
88:Error
88a32/88a36/88a41/88a46/88a51/88a56/88a62/88a67/88a82:Error when %c%s 88a32/88a36/88a41/88a46/88a51/88a56/88a62/88a67/88a82:Error when %c%s
89:Filer Action Window 89:Filer Action Window
90:Options 90:Options
......
No preview for this file type
...@@ -14,3 +14,4 @@ ...@@ -14,3 +14,4 @@
| |
Set FilerAct$Path Resources:Resources.FilerAct. Set FilerAct$Path Resources:Resources.FilerAct.
UnSet Alias$Filer_Action UnSet Alias$Filer_Action
UnSet Alias$Filer_Action2
...@@ -13,4 +13,5 @@ ...@@ -13,4 +13,5 @@
| limitations under the License. | limitations under the License.
| |
Set FilerAct$Path <Obey$Dir>.^.Resources.<Locale>. Set FilerAct$Path <Obey$Dir>.^.Resources.<Locale>.
Set Alias$Filer_Action2 <Obey$Dir>.^.app.FilerAct %%*0
Set Alias$Filer_Action <Obey$Dir>.^.app.FilerAct %%*0 Set Alias$Filer_Action <Obey$Dir>.^.app.FilerAct %%*0
...@@ -11,13 +11,13 @@ ...@@ -11,13 +11,13 @@
GBLS Module_HelpVersion GBLS Module_HelpVersion
GBLS Module_ComponentName GBLS Module_ComponentName
GBLS Module_ComponentPath GBLS Module_ComponentPath
Module_MajorVersion SETS "0.48" Module_MajorVersion SETS "0.54"
Module_Version SETA 48 Module_Version SETA 54
Module_MinorVersion SETS "" Module_MinorVersion SETS ""
Module_Date SETS "11 Jun 2009" Module_Date SETS "23 Oct 2011"
Module_ApplicationDate SETS "11-Jun-09" Module_ApplicationDate SETS "23-Oct-11"
Module_ComponentName SETS "FilerAct" Module_ComponentName SETS "FilerAct"
Module_ComponentPath SETS "castle/RiscOS/Sources/Desktop/FilerAct" Module_ComponentPath SETS "castle/RiscOS/Sources/Desktop/FilerAct"
Module_FullVersion SETS "0.48" Module_FullVersion SETS "0.54"
Module_HelpVersion SETS "0.48 (11 Jun 2009)" Module_HelpVersion SETS "0.54 (23 Oct 2011)"
END END
/* (0.48) /* (0.54)
* *
* This file is automatically maintained by srccommit, do not edit manually. * This file is automatically maintained by srccommit, do not edit manually.
* Last processed by srccommit version: 1.1. * Last processed by srccommit version: 1.1.
* *
*/ */
#define Module_MajorVersion_CMHG 0.48 #define Module_MajorVersion_CMHG 0.54
#define Module_MinorVersion_CMHG #define Module_MinorVersion_CMHG
#define Module_Date_CMHG 11 Jun 2009 #define Module_Date_CMHG 23 Oct 2011
#define Module_MajorVersion "0.48" #define Module_MajorVersion "0.54"
#define Module_Version 48 #define Module_Version 54
#define Module_MinorVersion "" #define Module_MinorVersion ""
#define Module_Date "11 Jun 2009" #define Module_Date "23 Oct 2011"
#define Module_ApplicationDate "11-Jun-09" #define Module_ApplicationDate "23-Oct-11"
#define Module_ComponentName "FilerAct" #define Module_ComponentName "FilerAct"
#define Module_ComponentPath "castle/RiscOS/Sources/Desktop/FilerAct" #define Module_ComponentPath "castle/RiscOS/Sources/Desktop/FilerAct"
#define Module_FullVersion "0.48" #define Module_FullVersion "0.54"
#define Module_HelpVersion "0.48 (11 Jun 2009)" #define Module_HelpVersion "0.54 (23 Oct 2011)"
#define Module_LibraryVersionInfo "0:48" #define Module_LibraryVersionInfo "0:54"
...@@ -12,8 +12,11 @@ ...@@ -12,8 +12,11 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#if 0 #if 0
#define debugbut #define debugbut(k) dprintf k
#else
#define debugbut(k) /* Disabled */
#endif #endif
#include <stdio.h> #include <stdio.h>
...@@ -21,6 +24,7 @@ ...@@ -21,6 +24,7 @@
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
#include <ctype.h> #include <ctype.h>
#include <time.h>
#include "os.h" #include "os.h"
#include "wimp.h" #include "wimp.h"
...@@ -45,7 +49,7 @@ ...@@ -45,7 +49,7 @@
static void null_activity( action_environment * ); static void null_activity( action_environment * );
static void pause_operation( action_environment * ); static void pause_operation( action_environment * );
static void continue_operation( action_environment * ); static void continue_operation( action_environment * );
#ifdef UseFasterButton #ifdef USE_FASTER_BUTTON
static void faster_operation( action_environment * ); static void faster_operation( action_environment * );
#endif #endif
static void skip_file( action_environment * ); static void skip_file( action_environment * );
...@@ -65,7 +69,7 @@ const button_set abort_pause_buttons = ...@@ -65,7 +69,7 @@ const button_set abort_pause_buttons =
null_activity, null_activity,
null_activity, null_activity,
pause_operation, pause_operation,
#ifdef UseFasterButton #ifdef USE_FASTER_BUTTON
faster_operation, faster_operation,
#else #else
null_activity, null_activity,
...@@ -75,7 +79,7 @@ const button_set abort_pause_buttons = ...@@ -75,7 +79,7 @@ const button_set abort_pause_buttons =
"", "",
"", "",
"4", "4",
#ifdef UseFasterButton #ifdef USE_FASTER_BUTTON
"FS" "FS"
#else #else
"" ""
...@@ -87,7 +91,7 @@ const button_set abort_pause_buttons = ...@@ -87,7 +91,7 @@ const button_set abort_pause_buttons =
NULL, NULL,
NULL, NULL,
"6", "6",
#ifdef UseFasterButton #ifdef USE_FASTER_BUTTON
"F" "F"
#else #else
NULL NULL
...@@ -280,146 +284,148 @@ const button_set open_buttons = ...@@ -280,146 +284,148 @@ const button_set open_buttons =
static void set_button( action_environment *env, int button, const char *text ) static void set_button( action_environment *env, int button, const char *text )
{ {
int dbox_handle = dbox_syshandle( env->status_box ); int dbox_handle = dbox_syshandle( env->status_box );
if ( text != NULL ) if ( text != NULL )
{ {
/* /*
Ensure button exists before setting field Ensure button exists before setting field
*/ */
wimp_set_icon_state( dbox_handle, button, 0, wimp_IDELETED | wimp_IREDRAW ); wimp_iconflags flags = (wimp_iconflags) 0;
dbox_setfield( env->status_box, button, msgs_lookup((char *)text) ); wimp_iconflags mask = (wimp_iconflags) (wimp_IDELETED | wimp_IREDRAW);
} wimp_set_icon_state( dbox_handle, button, flags, mask );
else dbox_setfield( env->status_box, button, msgs_lookup((char *)text) );
{ }
wimp_redrawstr r; else
wimp_icon icondata; {
os_error *err; wimp_redrawstr r;
wimp_icon icondata;
os_error *err;
/* /*
delete button delete button
*/ */
err = wimp_get_icon_info( dbox_handle, button, &icondata ); err = wimp_get_icon_info( dbox_handle, button, &icondata );
if ( !err ) if ( !err )
{ {
wimp_set_icon_state( dbox_handle, button, wimp_IDELETED | wimp_IREDRAW, wimp_IDELETED | wimp_IREDRAW ); wimp_iconflags flags = (wimp_iconflags) (wimp_IDELETED | wimp_IREDRAW);
wimp_iconflags mask = flags;
wimp_set_icon_state( dbox_handle, button, flags, mask );
r.w = dbox_handle; r.w = dbox_handle;
r.box = icondata.box; r.box = icondata.box;
wimp_force_redraw( &r ); wimp_force_redraw( &r );
}
} }
}
} }
static void set_all_buttons( action_environment *env, const button_texts *texts ) static void set_all_buttons( action_environment *env, const button_texts *texts )
{ {
set_button( env, Abort_Button, texts->abort_text ); set_button( env, Abort_Button, texts->abort_text );
set_button( env, No_Skip_Button, texts->no_skip_text ); set_button( env, No_Skip_Button, texts->no_skip_text );
set_button( env, Yes_Retry_Button, texts->yes_retry_text ); set_button( env, Yes_Retry_Button, texts->yes_retry_text );
set_button( env, Misc_Button, texts->misc_text ); set_button( env, Misc_Button, texts->misc_text );
set_button( env, Skip_Button, texts->skip_text ); set_button( env, Skip_Button, texts->skip_text );
} }
void switch_buttons( action_environment *env, const button_set *new_buttons ) void switch_buttons( action_environment *env, const button_set *new_buttons )
{ {
env->button_actions = new_buttons->actions; env->button_actions = new_buttons->actions;
set_all_buttons( env, &new_buttons->texts ); set_all_buttons( env, &new_buttons->texts );
if ( new_buttons->actions.requires_interaction ) if ( new_buttons->actions.requires_interaction )
{ {
/* /*
Pop up the dialogue box and turn off NULL events Pop up the dialogue box and turn off NULL events
*/ */
dbox_showstatic( env->status_box ); dbox_showstatic( env->status_box );
show_faster_stuff( env ); show_faster_stuff( env );
event_setmask( wimp_EMNULL | wimp_EMPTRLEAVE | wimp_EMPTRENTER | wimp_EMUSERDRAG ); wimp_emask mask = (wimp_emask) (wimp_EMNULL | wimp_EMPTRLEAVE | wimp_EMPTRENTER | wimp_EMUSERDRAG);
}
else event_setmask( mask );
}
else
{
if ( !env->verbose )
{ {
if ( !env->verbose ) switch_dbox_on_off( env, -1, Remove_Delay );
{ }
switch_dbox_on_off( env, -1, Remove_Delay );
}
/* /*
Things might have changed, so update ourselves Things might have changed, so update ourselves
*/ */
read_next_node_parameters( env->test_search ); read_next_node_parameters( env->test_search );
event_setmask( wimp_EMPTRLEAVE | wimp_EMPTRENTER | wimp_EMUSERDRAG ); wimp_emask mask = (wimp_emask) (wimp_EMPTRLEAVE | wimp_EMPTRENTER | wimp_EMUSERDRAG);
}
#ifdef UseFasterButton event_setmask( mask );
/* Ensure we get the buttons we really need */ }
if ( new_buttons == &abort_pause_buttons )
{ #ifdef USE_FASTER_BUTTON
set_faster_state( env ); /* Ensure we get the buttons we really need */
} if ( new_buttons == &abort_pause_buttons )
#endif {
set_faster_state( env );
}
#endif
} }
void abort_operation( action_environment *env ) void abort_operation( action_environment *env )
{ {
dispose_search_context( env->test_search ); dispose_search_context( env->test_search );
exit( 0 ); exit( 0 );
} }
static void pause_operation( action_environment *env ) static void pause_operation( action_environment *env )
{ {
char info_buffer[ Info_Field_Length + 10 ]; set_button( env, Misc_Button, "26" );
set_button( env, Misc_Button, "26" ); env->button_actions.button_helps[ Misc_Button - Abort_Button ] = "79";
env->button_actions.button_helps[ Misc_Button - Abort_Button ] = "79"; env->button_actions.misc_action = continue_operation;
env->button_actions.misc_action = continue_operation; set_top_info_field_with_current_info(env, "80a", "80");
strcpy(info_buffer, "80a"); dbox_showstatic( env->status_box );
strcat(info_buffer, env->current_info_token);
sprintf(info_buffer, msgs_lookup(info_buffer), tolower(env->current_info[0]), &env->current_info[1]);
dbox_setfield( env->status_box, Top_Info_Field, info_buffer ); wimp_emask mask = (wimp_emask) (wimp_EMNULL | wimp_EMPTRLEAVE | wimp_EMPTRENTER | wimp_EMUSERDRAG );
last_top_info_field = info_buffer; event_setmask( mask );
dbox_showstatic( env->status_box );
event_setmask( wimp_EMNULL | wimp_EMPTRLEAVE | wimp_EMPTRENTER | wimp_EMUSERDRAG );
} }
#ifdef UseFasterButton #ifdef USE_FASTER_BUTTON
/* JRF: Calls the same thing as the menu option */ /* JRF: Calls the same thing as the menu option */
static void faster_operation( action_environment *env ) static void faster_operation( action_environment *env )
{ {
toggle_faster( env ); toggle_faster( env );
} }
void set_faster_state( action_environment *env ) void set_faster_state( action_environment *env )
{ {
if ( !env->button_actions.requires_interaction ) if ( !env->button_actions.requires_interaction )
{ {
if ( env->faster ) if ( env->faster )
set_button( env, Skip_Button, "S" ); set_button( env, Skip_Button, "S" );
else else
set_button( env, Skip_Button, "F" ); set_button( env, Skip_Button, "F" );
} }
} }
#endif #endif
static void continue_operation( action_environment *env ) static void continue_operation( action_environment *env )
{ {
switch_buttons( env, &abort_pause_buttons ); switch_buttons( env, &abort_pause_buttons );
} }
static void null_activity( action_environment *env ) static void null_activity( action_environment *env )
{ {
env = env; /* keep the compiler quiet */ IGNORE(env);
} }
/* /*
...@@ -427,7 +433,7 @@ static void null_activity( action_environment *env ) ...@@ -427,7 +433,7 @@ static void null_activity( action_environment *env )
*/ */
static void operate_on_file( action_environment *env ) static void operate_on_file( action_environment *env )
{ {
switch_buttons( env, &abort_pause_buttons ); switch_buttons( env, &abort_pause_buttons );
} }
/* /*
...@@ -435,9 +441,9 @@ static void operate_on_file( action_environment *env ) ...@@ -435,9 +441,9 @@ static void operate_on_file( action_environment *env )
*/ */
static void to_end_of_list( action_environment *env ) static void to_end_of_list( action_environment *env )
{ {
switch_buttons( env, &abort_pause_buttons ); switch_buttons( env, &abort_pause_buttons );
env->confirm = No; env->confirm = No;
} }
/* /*
...@@ -445,11 +451,11 @@ static void to_end_of_list( action_environment *env ) ...@@ -445,11 +451,11 @@ static void to_end_of_list( action_environment *env )
*/ */
static void skip_file( action_environment *env ) static void skip_file( action_environment *env )
{ {
env->action = Next_File; env->action = Next_File;
skip_list_file( env->test_search ); skip_list_file( env->test_search );
switch_buttons( env, &abort_pause_buttons ); switch_buttons( env, &abort_pause_buttons );
} }
/* /*
...@@ -457,109 +463,109 @@ static void skip_file( action_environment *env ) ...@@ -457,109 +463,109 @@ static void skip_file( action_environment *env )
*/ */
static void skip_operation( action_environment *env ) static void skip_operation( action_environment *env )
{ {
if ( env->action == Next_File ) if ( env->action == Next_File )
{
skip_failed_selection( env->test_search );
}
else
{
switch ( env->operation )
{ {
skip_failed_selection( env->test_search ); case Action_Copying:
} case Action_CopyMoving:
else case Action_CopyLocal:
{ if ( env->action == Check_Full_Reading )
switch ( env->operation ) {
{ skip_file_read();
case Action_Copying: switch_to_reading( env );
case Action_CopyMoving: }
case Action_CopyLocal: else if ( env->action == Check_Empty_Writing )
if ( env->action == Check_Full_Reading ) {
{ skip_file_write();
skip_file_read(); switch_to_writing( env );
switch_to_reading( env ); }
} else
else if ( env->action == Check_Empty_Writing ) {
{ env->action = Next_File;
skip_file_write(); }
switch_to_writing( env ); break;
}
else case Action_Moving:
{ case Action_Deleting:
env->action = Next_File; case Action_Setting_Access:
} case Action_Setting_Type:
break; case Action_Counting:
case Action_Stamping:
case Action_Moving: case Action_Finding:
case Action_Deleting: env->action = Next_File;
case Action_Setting_Access: break;
case Action_Setting_Type:
case Action_Counting:
case Action_Stamping:
case Action_Finding:
env->action = Next_File;
break;
}
} }
}
switch_buttons( env, &abort_pause_buttons ); switch_buttons( env, &abort_pause_buttons );
} }
static void run_object( action_environment *env ) static void run_object( action_environment *env )
{ {
char *filename; char *filename;
char *command; char *command;
os_error *err; os_error *err;
err = next_nodename( env->test_search, &filename ); err = next_nodename( env->test_search, &filename );
if ( err ) if ( err )
{ {
wimpt_complain( err ); wimpt_complain( err );
return; return;
} }
command = overflowing_malloc( strlen( "Filer_Run " ) + strlen( filename ) + 1 ); command = overflowing_malloc( strlen( "Filer_Run " ) + strlen( filename ) + 1 );
if ( !command ) if ( !command )
{ {
wimpt_complain( error( mb_malloc_failed ) ); wimpt_complain( error( mb_malloc_failed ) );
return; return;
} }
sprintf( command, "Filer_Run %s", filename ); sprintf( command, "Filer_Run %s", filename );
overflowing_free( filename ); overflowing_free( filename );
wimpt_complain( os_cli( command )); wimpt_complain( os_cli( command ));
overflowing_free( command ); overflowing_free( command );
} }
static void view_object( action_environment *env ) static void view_object( action_environment *env )
{ {
wimp_msgstr m; wimp_msgstr m;
char *filename; char *filename;
os_error *err; os_error *err;
err = next_nodename( env->test_search, &filename ); err = next_nodename( env->test_search, &filename );
if ( err ) if ( err )
{ {
wimpt_complain( err ); wimpt_complain( err );
return; return;
} }
/* /*
strrchr is guaranteed to work correctly due to the nature of the strrchr is guaranteed to work correctly due to the nature of the
filename. filename.
*/ */
*strrchr( filename, '.' ) = '\0'; *strrchr( filename, '.' ) = '\0';
m.hdr.size = 256; m.hdr.size = 256;
m.hdr.your_ref = 0; m.hdr.your_ref = 0;
m.hdr.action = wimp_FilerOpenDir; m.hdr.action = wimp_FilerOpenDir;
m.data.words[ 0 ] = 0; m.data.words[ 0 ] = 0;
m.data.words[ 1 ] = 0; m.data.words[ 1 ] = 0;
strcpy( (char *)&m.data.words[2], filename ); strcpy( (char *)&m.data.words[2], filename );
overflowing_free( filename ); overflowing_free( filename );
wimpt_complain( wimp_sendmessage( wimp_ESEND, &m, 0 )); wimpt_complain( wimp_sendmessage( wimp_ESEND, &m, 0 ));
} }
/* /*
...@@ -567,16 +573,14 @@ static void view_object( action_environment *env ) ...@@ -567,16 +573,14 @@ static void view_object( action_environment *env )
*/ */
static void restart_operation( action_environment *env ) static void restart_operation( action_environment *env )
{ {
#ifdef debugbut debugbut(( "restart_operation: env=&%8X\n", (int)env ));
dprintf( "restart_operation: env=&%8X\n", (int)env ); if ( env->action == Check_Full_Reading )
#endif restart_file_read();
if ( env->action == Check_Full_Reading )
restart_file_read();
if ( env->action == Check_Empty_Writing ) if ( env->action == Check_Empty_Writing )
restart_file_write(); restart_file_write();
switch_buttons( env, &abort_pause_buttons ); switch_buttons( env, &abort_pause_buttons );
} }
/* /*
...@@ -584,7 +588,7 @@ static void restart_operation( action_environment *env ) ...@@ -584,7 +588,7 @@ static void restart_operation( action_environment *env )
*/ */
static void retry_operation( action_environment *env ) static void retry_operation( action_environment *env )
{ {
switch_buttons( env, &abort_pause_buttons ); switch_buttons( env, &abort_pause_buttons );
} }
/* /*
...@@ -592,34 +596,34 @@ static void retry_operation( action_environment *env ) ...@@ -592,34 +596,34 @@ static void retry_operation( action_environment *env )
*/ */
void button_event_handler( dbox db, void *handle ) void button_event_handler( dbox db, void *handle )
{ {
action_environment *env = handle; action_environment *env = handle;
db = db; /* keep the compiler quiet */ IGNORE(db);
switch( dbox_get( env->status_box )) switch( dbox_get( env->status_box ))
{ {
case Abort_Button: case Abort_Button:
env->button_actions.abort_action( env ); env->button_actions.abort_action( env );
break; break;
case No_Skip_Button: case No_Skip_Button:
env->button_actions.no_skip_action( env ); env->button_actions.no_skip_action( env );
break; break;
case Yes_Retry_Button: case Yes_Retry_Button:
env->button_actions.yes_retry_action( env ); env->button_actions.yes_retry_action( env );
break; break;
case Misc_Button: case Misc_Button:
env->button_actions.misc_action( env ); env->button_actions.misc_action( env );
break; break;
case Skip_Button: case Skip_Button:
env->button_actions.skip_action( env ); env->button_actions.skip_action( env );
break; break;
default: default:
/* do nothing on other fields */ /* do nothing on other fields */
break; break;
} }
} }
...@@ -16,16 +16,10 @@ ...@@ -16,16 +16,10 @@
Chain manipulation routines. Chain manipulation routines.
*/ */
#if 0
#define debugchain
#endif
#include <stdio.h> #include <stdio.h>
#include "debug.h" #include "debug.h"
#ifndef __chains_h
#include "chains.h" #include "chains.h"
#endif
void chain_remove_link( chain_link *link ) void chain_remove_link( chain_link *link )
{ {
......
...@@ -12,14 +12,18 @@ ...@@ -12,14 +12,18 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#if 0 #if 0
#define debuginit #define debuginit(k) dprintf k
#else
#define debuginit(k) /* Disabled */
#endif #endif
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <locale.h> #include <locale.h>
#include <time.h>
#include "os.h" #include "os.h"
#include "wimp.h" #include "wimp.h"
...@@ -33,7 +37,7 @@ ...@@ -33,7 +37,7 @@
#include "msgs.h" #include "msgs.h"
#include "menu.h" #include "menu.h"
#include "Options.h"
#include "allerrs.h" #include "allerrs.h"
#include "malloc+.h" #include "malloc+.h"
#include "listfiles.h" #include "listfiles.h"
...@@ -60,32 +64,32 @@ os_error errbuf = { 0, "" }; ...@@ -60,32 +64,32 @@ os_error errbuf = { 0, "" };
*/ */
static void remove_processor( void ) static void remove_processor( void )
{ {
win_remove_unknown_event_processor( message_event_handler, &env ); win_remove_unknown_event_processor( message_event_handler, &env );
closedown_memmanagement(); closedown_memmanagement();
} }
static void near_mouse_position_window( char *window_name ) static void near_mouse_position_window( char *window_name )
{ {
template *tplt = template_find( window_name ); template *tplt = template_find( window_name );
wimp_mousestr ptr; wimp_mousestr ptr;
os_error *err; os_error *err;
int x_offset; int x_offset;
int y_offset; int y_offset;
err = wimp_get_point_info( &ptr ); err = wimp_get_point_info( &ptr );
if ( !err ) if ( !err )
{ {
x_offset = (ptr.x - Window_Title_Height - Character_Height) - x_offset = (ptr.x - Window_Title_Height - Character_Height) -
tplt->window.box.x0; tplt->window.box.x0;
y_offset = (ptr.y - Window_Title_Height - Character_Height) - y_offset = (ptr.y - Window_Title_Height - Character_Height) -
tplt->window.box.y1; tplt->window.box.y1;
tplt->window.box.x0 += x_offset; tplt->window.box.x0 += x_offset;
tplt->window.box.x1 += x_offset; tplt->window.box.x1 += x_offset;
tplt->window.box.y0 += y_offset; tplt->window.box.y0 += y_offset;
tplt->window.box.y1 += y_offset; tplt->window.box.y1 += y_offset;
} }
} }
...@@ -105,121 +109,126 @@ static wimp_msgaction Messages[] = { ...@@ -105,121 +109,126 @@ static wimp_msgaction Messages[] = {
wimp_MFilerAddSelection, wimp_MFilerAddSelection,
wimp_MFilerAction, wimp_MFilerAction,
wimp_MFilerControlAction, wimp_MFilerControlAction,
0 wimp_MCLOSEDOWN /* list terminator (0, but with the right type) */
}; };
os_error *initialise( action_environment *env, int argc, char *argv[] ) os_error *initialise( action_environment *env, int argc, char *argv[] )
{ {
os_error *err;
IGNORE(argc); /* keep the compiler quiet */
IGNORE(argv); /* keep the compiler quiet */
overflowing_initialise();
/*
Pull in some resources
*/
res_init("FilerAct");
msgs_init();
wimpt_messages(Messages);
wimpt_init(msgs_lookup("89"));
template_init();
debuginit(( "Resources initialised\n" ));
#ifdef debug
/* Test errors. */
{
os_error *err; os_error *err;
err = error( mb_slotsize_too_small );
argc = argc; /* keep the compiler quiet */ debuginit(( "%d: %s\n", err->errnum, err->errmess ));
argv = argv; /* keep the compiler quiet */ err = error( mb_malloc_failed );
debuginit(( "%d: %s\n", err->errnum, err->errmess ));
overflowing_initialise(); err = error( mb_unexpected_state );
debuginit(( "%d: %s\n", err->errnum, err->errmess ));
/* err = error( mb_broken_templates );
Pull in some resources debuginit(( "%d: %s\n", err->errnum, err->errmess ));
*/ }
res_init("FilerAct"); #endif
msgs_init();
wimpt_messages(Messages); /*
wimpt_init(msgs_lookup("89")); Get the memmanagement onto the right footing
template_init(); */
err = init_memmanagement();
#ifdef debuginit if ( err )
/* Test errors. */ return err;
{ os_error *err;
err = error( mb_slotsize_too_small ); /*
dprintf("%d: %s\n", err->errnum, err->errmess); re-position the window near the mouse
err = error( mb_malloc_failed ); */
dprintf("%d: %s\n", err->errnum, err->errmess); near_mouse_position_window( MAIN_TEMPLATE_NAME );
err = error( mb_unexpected_state );
dprintf("%d: %s\n", err->errnum, err->errmess); /*
err = error( mb_broken_templates ); start up the dbox wimplib stuff
dprintf("%d: %s\n", err->errnum, err->errmess); */
} dbox_init();
#endif
/*
/* Add event processor here, so that deactivate_myself can cleanly
Get the memmanagement onto the right footing remove it
*/ */
err = init_memmanagement(); win_add_unknown_event_processor( message_event_handler, env );
if ( err ) atexit( remove_processor );
return err;
/*
/* create a window for ourself
re-position the window near the mouse */
*/ env->status_box = dbox_new( MAIN_TEMPLATE_NAME );
near_mouse_position_window( Main_Window ); if ( env->status_box == NULL )
return error( mb_broken_templates );
/* env->window_handle = dbox_syshandle( env->status_box );
start up the dbox wimplib stuff
*/ /*
dbox_init(); Attach the button event handler
*/
/* dbox_eventhandler( env->status_box, button_event_handler, env );
Add event processor here, so that deactivate_myself can cleanly
remove it /*
*/ Give ourself a menu
win_add_unknown_event_processor( message_event_handler, env ); */
atexit( remove_processor ); env->option_menu = menu_new( msgs_lookup( "90" ), msgs_lookup( "91" ));
if ( env->option_menu == NULL )
/* return error( mb_malloc_failed );
create a window for ourselved event_attachmenu( dbox_syshandle( env->status_box ), env->option_menu, (event_menu_proc)option_menu_handler, env );
*/
env->status_box = dbox_new( Main_Window ); /*
if ( env->status_box == NULL ) Attach idle event handler to dialogue box
return error( mb_broken_templates ); */
dbox_raw_eventhandler( env->status_box, idle_event_handler, env );
/*
Attach the button event handler /*
*/ Direct idle events at the dialogue box
dbox_eventhandler( env->status_box, button_event_handler, env ); */
win_claim_idle_events( dbox_syshandle( env->status_box ));
/*
Give ourselves a menu /*
*/ Enable only those events we're interested in
env->option_menu = menu_new( msgs_lookup( "90" ), msgs_lookup( "91" )); */
if ( env->option_menu == NULL ) event_setmask( (wimp_emask)(wimp_EMPTRLEAVE | wimp_EMPTRENTER | wimp_EMUSERDRAG) );
return error( mb_malloc_failed );
event_attachmenu( dbox_syshandle( env->status_box ), env->option_menu, (event_menu_proc)option_menu_handler, env ); /*
Initialise an empty search context and boxchange information.
/* Also initialise memory flexing state.
Attach idle event handler to dialogue box */
*/ create_search_context( &env->test_search );
dbox_raw_eventhandler( env->status_box, idle_event_handler, env ); env->boxchange_direction = 0;
env->flex_memory = No;
/* env->disable_flex = No;
Direct idle events at the dialogue box env->in_error = No;
*/ #ifdef USE_PROGRESS_BAR
win_claim_idle_events( dbox_syshandle( env->status_box )); env->progress = 0;
#endif
/*
Enable only those events we're interested in last_top_info_field = NULL;
*/
event_setmask( wimp_EMPTRLEAVE | wimp_EMPTRENTER | wimp_EMUSERDRAG ); /*
Make sure we don't go away when the window's closed
/* */
Initialise an empty search context and boxchange information. win_activeinc();
Also initialise memory flexing state.
*/ dboxquery( 0 );
create_search_context( &env->test_search );
env->boxchange_direction = 0; setlocale( LC_ALL, "" );
env->flex_memory = No;
env->disable_flex = No; return NULL;
env->in_error = No;
last_top_info_field = NULL;
/*
Make sure we don't go away when the window's closed
*/
win_activeinc();
dboxquery( 0 );
setlocale( LC_ALL, "" );
return NULL;
} }
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
/* /*
Control the Filer's action window. Control the Filer's action window.
This code compilers into a relocatable module which controls the Filer's This code compiles into a relocatable module which controls the Filer's
action window. action window.
0.00 08-May-89 JSR Copied from allfiles - a 'list all files matching 0.00 08-May-89 JSR Copied from allfiles - a 'list all files matching
...@@ -100,7 +100,9 @@ action window. ...@@ -100,7 +100,9 @@ action window.
*/ */
#if 0 #if 0
#define debugact #define debugact(k) dprintf k
#else
#define debugact(k) /* Disabled */
#endif #endif
#include <stdio.h> #include <stdio.h>
...@@ -110,10 +112,12 @@ action window. ...@@ -110,10 +112,12 @@ action window.
#include <time.h> #include <time.h>
#include <ctype.h> #include <ctype.h>
/* AMcC 22-Jul-94 include swis.h rather than arthur.h !! */ #include "Global/FSNumbers.h"
#include "Interface/HighFSI.h"
#include "swis.h" #include "swis.h"
#include "os.h" #include "os.h"
#include "akbd.h"
#include "wimp.h" #include "wimp.h"
#include "wimpt.h" #include "wimpt.h"
#include "werr.h" #include "werr.h"
...@@ -148,23 +152,18 @@ action window. ...@@ -148,23 +152,18 @@ action window.
#define Option_FilerAction_ConfirmDeletes 0x00000020 /* RML */ #define Option_FilerAction_ConfirmDeletes 0x00000020 /* RML */
#define Option_FilerAction_Faster 0x00000040 /* RML */ #define Option_FilerAction_Faster 0x00000040 /* RML */
/* AMcC: 22-Jul-94 - Shouldn't be defined here #ifdef USE_STATUS_IN_TITLE
* #define FilerAction_SendSelectedDirectory 0x88000 static char TitleString[64];
* #define FilerAction_SendSelectedFile 0x88001 #endif
* #define FilerAction_SendStartOperation 0x88002 static char PathString[ Top_Info_Field_Length + 1 ];
*/
#define FileChar_ManyAny '*' #define FileChar_ManyAny '*'
#define FileChar_Any '#' #define FileChar_Any '#'
#define FileSystemNumber_NetFS 5
#define HELP_MESSAGE_CONTROL_NOBUTTON "1" #define HELP_MESSAGE_CONTROL_NOBUTTON "1"
#define HELP_MESSAGE_CONTROL "2" #define HELP_MESSAGE_CONTROL "2"
#define QUERY_TEMPLATE_NAME "query"
/* /*
A chain link structure A chain link structure
...@@ -189,13 +188,12 @@ typedef struct ...@@ -189,13 +188,12 @@ typedef struct
*/ */
extern os_error *i_am_now_active( void ); extern os_error *i_am_now_active( void );
#define Yes 1
#define No 0 #define No 0
#define Max_Invocation_Name_Length 20 #define Yes (!No)
/* AMcC: 22-Jul-94 - defined in swis.h #define SPACE ' '
* #define OS_ExitAndDie 0x50
*/ #define Max_Invocation_Name_Length 20
/* /*
* Field masks for date stamping * Field masks for date stamping
...@@ -203,22 +201,13 @@ extern os_error *i_am_now_active( void ); ...@@ -203,22 +201,13 @@ extern os_error *i_am_now_active( void );
#define DateStamped_Mask 0xfff00000 #define DateStamped_Mask 0xfff00000
#define DateStamp_HighByte 0x000000ff #define DateStamp_HighByte 0x000000ff
#define Attribute_OwnerRead 0x00000001
#define Attribute_OwnerWrite 0x00000002
#define Attribute_Locked 0x00000008
#define Attribute_PublicRead 0x00000010
#define Attribute_PublicWrite 0x00000020
#define SPACE ' '
#define max(a,b) ((a)>(b)?(a):(b))
/* /*
Status indications Status indications
*/ */
action_environment env; action_environment env;
char *last_top_info_field; const char *last_top_info_field;
static int doings_time = (10*CLK_TCK)/100; static clock_t doings_time = (10*CLK_TCK)/100;
static int UpdatePath = 0, UpdateTop = 0, UpdateBottom = 0;
#define Number_Of_Actions 10 #define Number_Of_Actions 10
#define Number_Of_Icon_Strings 5 #define Number_Of_Icon_Strings 5
...@@ -230,20 +219,26 @@ static int doings_time = (10*CLK_TCK)/100; ...@@ -230,20 +219,26 @@ static int doings_time = (10*CLK_TCK)/100;
static char *icon_strings[ Number_Of_Actions ][ Number_Of_Icon_Strings ] = static char *icon_strings[ Number_Of_Actions ][ Number_Of_Icon_Strings ] =
{ {
/* title top progress bottom progress top info help action */ /* title top bottom top info help action */
{ "29", "30", "31", "32", "33" }, /* copying */ /* progress progress */
{ "34", "30", "35", "36", "37" }, /* moving (renaming) */ { "29", "30", "31", "32", "33" }, /* copying */
{ "38", "39", "40", "41", "42" }, /* deleting */ { "34", "30", "35", NULL/*36*/, "37" }, /* moving (renaming) */
{ "43", "44", "45", "46", "47" }, /* setting access */ { "38", "39", "40", NULL/*41*/, "42" }, /* deleting */
{ "48", "49", "50", "51", "52" }, /* settype */ { "43", "44", "45", NULL/*46*/, "47" }, /* setting access */
{ "53", "54", "55", "56", "57" }, /* count */ { "48", "49", "50", NULL/*51*/, "52" }, /* settype */
{ "34", "30", "58", "32", "37" }, /* copy/moving */ { "53", "54", "55", NULL/*56*/, "57" }, /* count */
{ "29", "30", "31", "32", "33" }, /* copy local */ { "34", "30", "58", "32", "37" }, /* copy/moving */
{ "59", "60", "61", "62", "63" }, /* stamp */ { "29", "30", "31", "32", "33" }, /* copy local */
{ "64", "65", "66", "67", "68" } /* find */ { "59", "60", "61", NULL/*62*/, "63" }, /* stamp */
{ "64", "65", "66", NULL/*67*/, "68" } /* find */
}; };
static int show_when_faster[ Number_Of_Actions ][2] =
/*
Changed this so we show everything in faster mode, except the "bytes to go"
field in a copy operation
*/
static BOOL show_when_faster[ Number_Of_Actions ][2] =
{ {
/* top progress bottom progress action */ /* top progress bottom progress action */
{ No, Yes }, /* copying */ { No, Yes }, /* copying */
...@@ -251,11 +246,11 @@ static int show_when_faster[ Number_Of_Actions ][2] = ...@@ -251,11 +246,11 @@ static int show_when_faster[ Number_Of_Actions ][2] =
{ Yes, Yes }, /* deleting */ { Yes, Yes }, /* deleting */
{ Yes, Yes }, /* setting access */ { Yes, Yes }, /* setting access */
{ Yes, Yes }, /* settype */ { Yes, Yes }, /* settype */
{ No, No }, /* count */ { Yes, Yes }, /* count */
{ No, Yes }, /* copy/moving */ { No, Yes }, /* copy/moving */
{ No, Yes }, /* copy local */ { No, Yes }, /* copy local */
{ Yes, Yes }, /* stamp */ { Yes, Yes }, /* stamp */
{ Yes, No } /* find */ { Yes, Yes } /* find */
}; };
static char *action_prompt[] = static char *action_prompt[] =
...@@ -272,6 +267,29 @@ static char *action_prompt[] = ...@@ -272,6 +267,29 @@ static char *action_prompt[] =
"78" "78"
}; };
#ifdef debug
static char *debug_operation(int op)
{
switch (op)
{
case Action_Copying : return "Action_Copying";
case Action_Moving : return "Action_Moving";
case Action_Deleting : return "Action_Deleting";
case Action_Setting_Access : return "Action_Setting_Access";
case Action_Setting_Type : return "Action_Setting_Type";
case Action_Counting : return "Action_Counting";
case Action_CopyMoving : return "Action_CopyMoving";
case Action_CopyLocal : return "Action_CopyLocal";
case Action_Stamping : return "Action_Stamping";
case Action_Finding : return "Action_Finding";
}
return "unknown";
}
#else
#define debug_operation(op) NULL
#endif
/* RML */ /* RML */
static void hide_faster_stuff( action_environment *env ); static void hide_faster_stuff( action_environment *env );
...@@ -279,7 +297,7 @@ static void hide_faster_stuff( action_environment *env ); ...@@ -279,7 +297,7 @@ static void hide_faster_stuff( action_environment *env );
Establish a delayed switch on/off for the dbox. Establish a delayed switch on/off for the dbox.
Delay is in centiseconds Delay is in centiseconds
*/ */
/*static*/ void switch_dbox_on_off( action_environment *env, int direction, int delay ) void switch_dbox_on_off( action_environment *env, int direction, int delay )
{ {
env->time_to_boxchange = clock() + (delay * CLK_TCK)/100; env->time_to_boxchange = clock() + (delay * CLK_TCK)/100;
env->boxchange_direction = direction; env->boxchange_direction = direction;
...@@ -290,172 +308,302 @@ static void hide_faster_stuff( action_environment *env ); ...@@ -290,172 +308,302 @@ static void hide_faster_stuff( action_environment *env );
*/ */
static int caseless_wildcmp( const char *a, const char *b ) static int caseless_wildcmp( const char *a, const char *b )
{ {
int last_wildrover = -1; /* first wild char after last wildcard */ int last_wildrover = -1; /* first wild char after last wildcard */
int last_realrover = -1; /* first real char after wildcard in this test sequence */ int last_realrover = -1; /* first real char after wildcard in this test sequence */
int wild_rover = 0; int wild_rover = 0;
int real_rover = 0; int real_rover = 0;
int d; int d;
while ( (a[wild_rover] || b[real_rover]) ) while ( (a[wild_rover] || b[real_rover]) )
{
switch( a[wild_rover] )
{ {
switch( a[wild_rover] ) case FileChar_ManyAny:
{ last_wildrover = ++wild_rover; /* Carry on after * in wildcard string */
case FileChar_ManyAny: last_realrover = real_rover; /* try matching from here */
last_wildrover = ++wild_rover; /* Carry on after * in wildcard string */ break;
last_realrover = real_rover; /* try matching from here */
break;
case FileChar_Any:
if ( !b[real_rover] )
return a[wild_rover];
wild_rover++;
real_rover++;
break;
default:
d = toupper( a[wild_rover] ) - toupper( b[real_rover] );
if ( d )
{
if ( last_wildrover < 0 || !b[real_rover] )
return d;
wild_rover = last_wildrover; /* Restart after * in wilcard string */ case FileChar_Any:
real_rover = ++last_realrover; /* test one character on */ if ( !b[real_rover] )
} return a[wild_rover];
else
{ wild_rover++;
wild_rover++; real_rover++;
real_rover++; break;
}
break; default:
} d = toupper( a[wild_rover] ) - toupper( b[real_rover] );
if ( d )
{
if ( last_wildrover < 0 || !b[real_rover] )
return d;
wild_rover = last_wildrover; /* Restart after * in wilcard string */
real_rover = ++last_realrover; /* test one character on */
}
else
{
wild_rover++;
real_rover++;
}
break;
} }
}
return 0;
}
/*
Set the status text displayed in the top field, or the title bar
*/
static void set_top_info_field_raw(action_environment *env, char *text)
{
#ifdef USE_STATUS_IN_TITLE
if (text != NULL)
{
char title[256];
sprintf(title, "%s - %s", TitleString, text);
win_settitle( env->window_handle, title );
}
else
{
win_settitle( env->window_handle, TitleString );
}
#else
if (text == NULL) text = "";
dbox_setfield( env->status_box, Top_Info_Field, text );
#endif
last_top_info_field = text;
}
/*
Set the status text, from a token in the messages file
*/
static void set_top_info_field(action_environment *env, char *token)
{
char *text = NULL;
if (token != NULL && token[0] != '\0')
{
text = msgs_lookup( token );
}
set_top_info_field_raw(env, text);
}
void set_top_info_field_with_current_info(action_environment *env, char *token1, char *token2)
{
if (env->current_info_token != NULL)
{
char buffer[Top_Info_Field_Length];
strcpy(buffer, token1);
strcat(buffer, env->current_info_token);
sprintf(buffer, msgs_lookup(buffer), tolower(env->current_info[0]), &env->current_info[1]);
set_top_info_field_raw(env, buffer);
}
else
{
set_top_info_field(env, token2);
}
return 0;
} }
static char newpath[ Info_Field_Length + 1 ];
static char newleaf[ 10 + 1 ];
/* /*
Set the content of the bottom info field from the file name Set the content of the path display from the file name.
We no longer split the path into two parts, as the display field has been made wider.
*/ */
static void set_bottom_info_field( action_environment *env, char *text ) static void set_bottom_info_field( action_environment *env, char *text )
{ {
char *leaf; int l;
if ( text == NULL ) IGNORE(env);
return;
/* Split text into path and leafname */ if ( text == NULL )
leaf = strrchr( text, '.' ); return;
if ( leaf != NULL ) if ((l = strlen(text)) > Top_Info_Field_Length)
{ {
leaf += 1; strncpy(PathString, text + l - Top_Info_Field_Length, Top_Info_Field_Length);
PathString[Top_Info_Field_Length] = '\0';
}
else
{
strcpy(PathString, text);
}
if ( leaf - text > Info_Field_Length ) UpdatePath = 1;
{
strncpy( newpath, leaf - Info_Field_Length, Info_Field_Length );
newpath[ Info_Field_Length ] = '\0';
}
else
{
strncpy( newpath, text, leaf - text );
newpath[ leaf - text ] = '\0';
}
}
else
{
*newpath = '\0';
leaf = text;
}
strncpy( newleaf, leaf, 10 ); }
newleaf[ 10 ] = '\0';
if ( !env->faster )
{ static void set_top_progress_field( action_environment *env, uint64_t value )
dbox_setfield( env->status_box, Bottom_Info_Path, newpath ); {
dbox_setfield( env->status_box, Bottom_Info_Leaf, newleaf ); env->top_progress = value;
} UpdateTop = 1;
} }
#ifdef USE_LONG_LONG
static void set_top_progress_field( action_environment *env, uintmax_t value ) /*
#else Add a value to top progress. Instead of directly updating the icon, we set a flag
static void set_top_progress_field( action_environment *env, unsigned value ) that causes it to be updated on the next null poll.
#endif */
static void more_top_progress( action_environment *env, uint32_t change )
{
env->top_progress += change;
UpdateTop = 1;
}
/*
Add a value to bottom progress. Instead of directly updating the icon, we set a flag
that causes it to be updated on the next null poll.
*/
static void more_bottom_progress( action_environment *env, uint32_t change )
{
env->bottom_progress += change;
UpdateBottom = 1;
}
#ifdef USE_PROGRESS_BAR
/*
Add a value to the progress indicator
*/
static void add_progress(action_environment *env, uint32_t progress, char *text)
{ {
env->top_progress = value; env->progress += progress;
if ( !env->faster || show_when_faster[ env->operation ][ 0 ] ) if (env->progress > INT32_MAX) env->progress = INT32_MAX;
dbox_setlongnumeric( env->status_box, Top_Progress_Field, value ); if (text != NULL)
{
debugact(( "%s: +%08x -> %08x\n", text, progress, env->progress ));
}
} }
/*
Show the current progress indicator. Called on null poll events.
The first time this is called, we calculate how much progress is represented by
one OS unit. The Progress_Bar icon is then resized to be a proportion of the total
size of the Progress_Bar_BBox icon.
*/
static void update_progress_bar(action_environment *env)
{
static int ppos = 0, max = 0, last = 0;
static wimp_icon i;
int w, size;
os_regset r;
w = dbox_syshandle( env->status_box );
if (ppos == 0)
{
wimp_icon b;
if (wimp_get_icon_info(w, Progress_Bar, &i) != NULL) return;
if (wimp_get_icon_info(w, Progress_Bar_BBox, &b) != NULL) return;
max = b.box.x1 - b.box.x0;
ppos = INT32_MAX / max; /* progress per os unit */
i.box = b.box;
}
size = env->progress / ppos + 2;
if (size > max) size = max;
if (size >= last && size < last + 2)
return; /* no change from last time */
i.box.x1 = i.box.x0 + size;
r.r[0] = w;
r.r[1] = Progress_Bar;
r.r[2] = i.box.x0;
r.r[3] = i.box.y0;
r.r[4] = i.box.x1;
r.r[5] = i.box.y1;
os_swix( Wimp_ResizeIcon, &r );
wimp_set_icon_state(w, Progress_Bar, (wimp_iconflags)0, (wimp_iconflags)0);
last = size;
debugact(( "update_progress_bar: %08x -> %d / %d\n", env->progress, size, max ));
}
#endif
static void switch_box_to_error( action_environment *env, os_error *err ) static void switch_box_to_error( action_environment *env, os_error *err )
{ {
wimp_openstr o; wimp_openstr o;
template *tplt = template_find( Main_Window ); template *tplt = template_find( MAIN_TEMPLATE_NAME );
int xw; int xw;
int yw; int yw;
dbox_setfield( env->status_box, Error_Field, err->errmess ); dbox_setfield( env->status_box, Error_Field, err->errmess );
o.w = dbox_syshandle( env->status_box ); o.w = dbox_syshandle( env->status_box );
o.x = -tplt->window.ex.x0; o.x = -tplt->window.ex.x0;
o.y = -tplt->window.ex.y1; o.y = -tplt->window.ex.y1;
o.box = tplt->window.ex; o.box = tplt->window.ex;
o.behind = -1; o.behind = -1;
xw = ((bbc_modevar( -1, bbc_XWindLimit ) + 1) << bbc_modevar( -1, bbc_XEigFactor )) - bbc_vduvar( bbc_OrgX ); xw = ((bbc_modevar( -1, bbc_XWindLimit ) + 1) << bbc_modevar( -1, bbc_XEigFactor )) - bbc_vduvar( bbc_OrgX );
yw = ((bbc_modevar( -1, bbc_YWindLimit ) + 1) << bbc_modevar( -1, bbc_YEigFactor )) - bbc_vduvar( bbc_OrgY ); yw = ((bbc_modevar( -1, bbc_YWindLimit ) + 1) << bbc_modevar( -1, bbc_YEigFactor )) - bbc_vduvar( bbc_OrgY );
xw = xw/2 - (o.box.x1 + o.box.x0)/2; xw = xw/2 - (o.box.x1 + o.box.x0)/2;
yw = yw/2 - (o.box.y1 + o.box.y0)/2; yw = yw/2 - (o.box.y1 + o.box.y0)/2;
o.box.x0 += xw; o.box.x0 += xw;
o.box.y0 += yw; o.box.y0 += yw;
o.box.x1 += xw; o.box.x1 += xw;
o.box.y1 += yw; o.box.y1 += yw;
wimpt_noerr( wimp_open_wind( &o )); wimpt_noerr( wimp_open_wind( &o ));
} }
static void switch_box_from_error( action_environment *env ) static void switch_box_from_error( action_environment *env )
{ {
wimp_wstate s; wimp_wstate s;
template *tplt = template_find( Main_Window ); template *tplt = template_find( MAIN_TEMPLATE_NAME );
int xw; int xw;
int yw; int yw;
wimpt_noerr( wimp_get_wind_state( dbox_syshandle( env->status_box ), &s )); wimpt_noerr( wimp_get_wind_state( dbox_syshandle( env->status_box ), &s ));
xw = (s.o.box.x0 - s.o.x) - (tplt->window.box.x0 - tplt->window.scx); xw = (s.o.box.x0 - s.o.x) - (tplt->window.box.x0 - tplt->window.scx);
yw = (s.o.box.y1 - s.o.y) - (tplt->window.box.y1 - tplt->window.scy); yw = (s.o.box.y1 - s.o.y) - (tplt->window.box.y1 - tplt->window.scy);
s.o.x = tplt->window.scx; s.o.x = tplt->window.scx;
s.o.y = tplt->window.scy; s.o.y = tplt->window.scy;
s.o.box.x0 = tplt->window.box.x0 + xw; s.o.box.x0 = tplt->window.box.x0 + xw;
s.o.box.y0 = tplt->window.box.y0 + yw; s.o.box.y0 = tplt->window.box.y0 + yw;
s.o.box.x1 = tplt->window.box.x1 + xw; s.o.box.x1 = tplt->window.box.x1 + xw;
s.o.box.y1 = tplt->window.box.y1 + yw; s.o.box.y1 = tplt->window.box.y1 + yw;
wimpt_noerr( wimp_open_wind( &s.o )); wimpt_noerr( wimp_open_wind( &s.o ));
} }
void switch_to_reading( action_environment *env ) void switch_to_reading( action_environment *env )
{ {
env->current_info = msgs_lookup( "32" ); env->current_info = msgs_lookup( "32" );
env->current_info_token = "32"; env->current_info_token = "32";
set_bottom_info_field( env, next_file_to_be_read()); set_bottom_info_field( env, next_file_to_be_read());
set_top_progress_field( env, bytes_left_to_read()); set_top_progress_field( env, bytes_left_to_read());
env->action = Check_Full_Reading; env->action = Check_Full_Reading;
} }
/* /*
Acknowledge a message Acknowledge a message
*/ */
...@@ -465,16 +613,19 @@ static os_error *ack_message( wimp_eventstr *event ) ...@@ -465,16 +613,19 @@ static os_error *ack_message( wimp_eventstr *event )
return wimp_sendmessage( wimp_EACK, &event->data.msg, event->data.msg.hdr.task ); return wimp_sendmessage( wimp_EACK, &event->data.msg, event->data.msg.hdr.task );
} }
static int menus_greyed[ 3 ][ 5 ] =
static BOOL menus_greyed[ 3 ][ 5 ] =
{ {
{ No, No, No, No, No }, { No, No, No, No, No },
{ No, No, No, No, Yes }, { No, No, No, No, Yes },
{ No, Yes, No, Yes, Yes } { No, Yes, No, Yes, Yes }
}; };
typedef enum {none, name, access, type } destination_type; typedef enum {none, name, access, type } destination_type;
typedef enum {mt_all, mt_notcopy, mt_information } menu_type; typedef enum {mt_all, mt_notcopy, mt_information } menu_type;
static struct start_up_details_str static struct start_up_details_str
{ {
int init_for_copy:1; int init_for_copy:1;
...@@ -515,207 +666,220 @@ static void reflect_menu_flags( action_environment *env ) ...@@ -515,207 +666,220 @@ static void reflect_menu_flags( action_environment *env )
*/ */
static os_error *start_operation( action_environment *env, actions_possible operation, int options, void *auxilliary_information ) static os_error *start_operation( action_environment *env, actions_possible operation, int options, void *auxilliary_information )
{ {
os_error *err; os_error *err;
env->operation = operation;
debugact(( "new operation: %s\n", debug_operation( env->operation ) ));
dbox_setfield( env->status_box, Top_Progress_Line, msgs_lookup( icon_strings[ operation ][ Top_Progress_Line_Text ] ));
dbox_setfield( env->status_box, Bottom_Progress_Line, msgs_lookup( icon_strings[ operation ][ Bottom_Progress_Line_Text ] ));
#ifdef USE_STATUS_IN_TITLE
strcpy(TitleString, msgs_lookup( icon_strings[ operation ][ Title_Text ] ));
win_settitle( env->window_handle, TitleString );
#else
win_settitle( dbox_syshandle( env->status_box ), msgs_lookup( icon_strings[ operation ][ Title_Text ] ));
#endif
env->top_progress = 0;
env->bottom_progress = 0;
dbox_setlongnumeric( env->status_box, Top_Progress_Field, env->top_progress );
dbox_setlongnumeric( env->status_box, Bottom_Progress_Field, env->bottom_progress );
#ifdef USE_PROGRESS_BAR
env->progress = 0;
update_progress_bar(env);
#endif
env->faster = No;
env->faster_stuff_hidden = No;
env->verbose = (options & Option_FilerAction_Verbose) != 0;
env->confirm = (options & Option_FilerAction_Confirm) != 0;
env->force = (options & Option_FilerAction_Force) != 0;
/* RML */
if ((options & Option_FilerAction_ConfirmDeletes) && (operation==Action_Deleting)) env->confirm = Yes;
if (options & Option_FilerAction_Faster)
{
env->faster = Yes;
doings_time = CLK_TCK; /* 1 second */
hide_faster_stuff( env );
}
env->operation = operation; env->looknewer = (options & Option_FilerAction_Newer) != 0;
dbox_setfield( env->status_box, Top_Progress_Line, msgs_lookup( icon_strings[ operation ][ Top_Progress_Line_Text ] ));
dbox_setfield( env->status_box, Bottom_Progress_Line, msgs_lookup( icon_strings[ operation ][ Bottom_Progress_Line_Text ] ));
win_settitle( dbox_syshandle( env->status_box ), msgs_lookup( icon_strings[ operation ][ Title_Text ] ));
env->top_progress = 0; env->disc_full_already = No;
env->bottom_progress = 0; env->auto_skip_cvs = (getenv("Filer_Action$Skip") != NULL) ? Yes : No;
dbox_setlongnumeric( env->status_box, Top_Progress_Field, env->top_progress );
dbox_setlongnumeric( env->status_box, Bottom_Progress_Field, env->bottom_progress );
env->faster = No; switch_buttons( env, &abort_pause_buttons );
env->faster_stuff_hidden = No; set_faster_state( env );
env->verbose = (options & Option_FilerAction_Verbose) != 0;
env->confirm = (options & Option_FilerAction_Confirm) != 0;
env->force = (options & Option_FilerAction_Force) != 0;
/* RML */ if ( env->verbose )
if ((options & Option_FilerAction_ConfirmDeletes) && (operation==Action_Deleting)) env->confirm = Yes; {
switch_dbox_on_off( env, 1, Display_Delay );
}
if (options & Option_FilerAction_Faster) env->current_info = msgs_lookup( icon_strings[ operation ][ Top_Info_Field_Text ] );
{ env->current_info_token = icon_strings[operation][Top_Info_Field_Text];
env->faster = Yes;
doings_time = CLK_TCK; /* 1 second */
hide_faster_stuff( env );
}
env->looknewer = (options & Option_FilerAction_Newer) != 0; env->action = Next_File;
env->disc_full_already = No; if ( start_up_details[ env->operation ].init_for_copy )
env->auto_skip_cvs = (getenv("Filer_Action$Skip") != NULL) ? Yes : No; {
err = init_for_copying();
if ( err )
return err;
}
switch_buttons( env, &abort_pause_buttons ); switch( start_up_details[ env->operation ].dest )
set_faster_state( env ); {
case none:
break;
if ( env->verbose ) case name:
{ /*
switch_dbox_on_off( env, 1, Display_Delay ); Store the destination directory somewhere useful
} */
env->destination_name = overflowing_malloc( strlen( auxilliary_information ) + 1 );
if ( env->destination_name == NULL )
return error( mb_malloc_failed );
strcpy( env->destination_name, auxilliary_information );
break;
env->current_info = msgs_lookup( icon_strings[ operation ][ Top_Info_Field_Text ] ); case access:
env->current_info_token = icon_strings[operation][Top_Info_Field_Text]; env->new_access = *(int *)auxilliary_information;
break;
env->action = Next_File; case type:
env->new_type = *(int *)auxilliary_information;
debugact(( "new type is %d\n", env->new_type ));
break;
if ( start_up_details[ env->operation ].init_for_copy ) default:
{ break;
err = init_for_copying(); }
if ( err )
return err;
}
switch( start_up_details[ env->operation ].dest ) return_directories_last( env->test_search, start_up_details[ env->operation ].return_dirs_last );
{ return_directories_first( env->test_search, start_up_details[ env->operation ].return_dirs_first );
case none: recurse_search_context( env->test_search, start_up_details[ env->operation ].recurse );
break; treat_partitions_as_directories( env->test_search, start_up_details[ env->operation ].partition_is_directory );
env->disable_flex = start_up_details[ env->operation ].disable_flex;
env->flex_memory = start_up_details[ env->operation ].flex_now;
case name: switch( env->operation )
/* {
Store the destination directory somewhere useful
*/
env->destination_name = overflowing_malloc( strlen( auxilliary_information ) + 1 );
if ( env->destination_name == NULL )
return error( mb_malloc_failed );
strcpy( env->destination_name, auxilliary_information );
break;
case access: case Action_Counting:
env->new_access = *(int *)auxilliary_information;
break;
case type: err = selection_summary( env->test_search, &env->selection_summary );
env->new_type = *(int *)auxilliary_information;
#ifdef debugact
dprintf( "new type is %d\n", env->new_type );
#endif
break;
default: if ( err )
break; return err;
}
/* drop through into... */
case Action_Finding:
#ifndef CONFIRM_MEANS_CONFIRM_ALL
env->confirm = No;
#endif
/* drop through into... */
case Action_Stamping:
case Action_Setting_Type:
case Action_Copying:
case Action_CopyLocal:
case Action_Moving:
break;
case Action_Deleting:
err = selection_summary( env->test_search, &env->selection_summary );
if ( err )
return err;
return_directories_last( env->test_search, start_up_details[ env->operation ].return_dirs_last ); env->locked_not_deleted = 0;
return_directories_first( env->test_search, start_up_details[ env->operation ].return_dirs_first ); break;
recurse_search_context( env->test_search, start_up_details[ env->operation ].recurse );
treat_partitions_as_directories( env->test_search, start_up_details[ env->operation ].partition_is_directory );
env->disable_flex = start_up_details[ env->operation ].disable_flex;
env->flex_memory = start_up_details[ env->operation ].flex_now;
switch( env->operation ) case Action_Setting_Access:
{ {
os_regset r;
char *first_nodename;
case Action_Counting: recurse_search_context( env->test_search, (options & Option_FilerAction_Recurse) != 0 );
err = selection_summary( env->test_search, &env->selection_summary );
if ( err )
return err;
/* drop through into... */
case Action_Finding:
#ifndef CONFIRM_MEANS_CONFIRM_ALL
env->confirm = No;
#endif
/* drop through into... */ env->directory_access_setting_mask = 0xffffffff;
case Action_Stamping:
case Action_Setting_Type:
case Action_Copying:
case Action_CopyLocal:
case Action_Moving:
break;
case Action_Deleting: err = next_nodename( env->test_search, &first_nodename );
err = selection_summary( env->test_search, &env->selection_summary );
if ( err )
return err;
env->locked_not_deleted = 0; if ( err || first_nodename == NULL )
break; break;
case Action_Setting_Access: r.r[0] = FSControl_LookupFS;
{ r.r[1] = (int) first_nodename;
os_regset r; r.r[2] = 0; /* truncate on . or : etc */
char *first_nodename;
recurse_search_context( env->test_search, (options & Option_FilerAction_Recurse) != 0 );
env->directory_access_setting_mask = 0xffffffff;
err = next_nodename( env->test_search, &first_nodename ); err = os_swix( OS_FSControl, &r );
if ( err || first_nodename == NULL ) overflowing_free( first_nodename );
break;
r.r[0] = 13; /* lookup FS */ /*
r.r[1] = (int) first_nodename; NetFS doesn't like OwnerWrite being set on directories.
r.r[2] = 0; /* truncate on . or : etc */ */
if ( !err && r.r[1] == fsnumber_net )
env->directory_access_setting_mask &= ~write_attribute;
err = os_swix( OS_FSControl, &r ); break;
overflowing_free( first_nodename );
/*
NetFS doesn't like OwnerWrite being set on directories.
*/
if ( !err && r.r[1] == FileSystemNumber_NetFS )
env->directory_access_setting_mask &= ~Attribute_OwnerWrite;
break;
}
default:
break;
} }
reflect_menu_flags( env ); default:
break;
}
reflect_menu_flags( env );
return NULL; return NULL;
} }
static void go_verbose( action_environment *env ) static void go_verbose( action_environment *env )
{ {
wimp_wstate state; wimp_wstate state;
if ( wimp_get_wind_state( dbox_syshandle( env->status_box ), &state ) ) if ( wimp_get_wind_state( dbox_syshandle( env->status_box ), &state ) )
return; return;
dbox_showstatic( env->status_box ); dbox_showstatic( env->status_box );
state.o.behind = -1; state.o.behind = -1;
if ( wimp_open_wind( &state.o ) ) if ( wimp_open_wind( &state.o ) )
return; return;
env->verbose = Yes; env->verbose = Yes;
env->boxchange_direction = 0; env->boxchange_direction = 0;
} }
/* JRF: Toggle the faster operation of the window. /* JRF: Toggle the faster operation of the window.
This is accessed from the Buttons.c source. This is accessed from the Buttons.c source.
*/ */
void toggle_faster( action_environment *env ) void toggle_faster( action_environment *env )
{ {
env->faster = !env->faster; env->faster = !env->faster;
copy_go_faster( env->faster ); copy_go_faster( env->faster );
if ( env->faster ) if ( env->faster )
{ {
doings_time = CLK_TCK; /* 1 second */ doings_time = CLK_TCK; /* 1 second */
hide_faster_stuff( env ); hide_faster_stuff( env );
} }
else else
{ {
doings_time = (10*CLK_TCK)/100; /* 1/10 second */ doings_time = (10*CLK_TCK)/100; /* 1/10 second */
show_faster_stuff( env ); show_faster_stuff( env );
} }
menu_setflags( env->option_menu, 1, env->faster, menus_greyed[ start_up_details[ env->operation ].men ][ 0 ] ); menu_setflags( env->option_menu, 1, env->faster, menus_greyed[ start_up_details[ env->operation ].men ][ 0 ] );
} }
static void go_terse( action_environment *env ) static void go_terse( action_environment *env )
{ {
env->verbose = No; env->verbose = No;
...@@ -732,330 +896,319 @@ static void go_terse( action_environment *env ) ...@@ -732,330 +896,319 @@ static void go_terse( action_environment *env )
*/ */
static void control_action( action_environment *env, wimp_eventstr *event ) static void control_action( action_environment *env, wimp_eventstr *event )
{ {
switch ( event->data.msg.data.words[0] ) switch ( event->data.msg.data.words[0] )
{ {
case 0: case 0:
/* /*
Acknowledge the message Acknowledge the message
*/ */
ack_message( event ); ack_message( event );
break; break;
case 1: /* show window and bring it to the front */ case 1: /* show window and bring it to the front */
go_verbose( env ); go_verbose( env );
break; break;
case 2: /* Turn verbose off - hide the window */ case 2: /* Turn verbose off - hide the window */
go_terse( env ); go_terse( env );
break; break;
default: default:
/* /*
Do nothing implicitely Do nothing implicitely
*/ */
break; break;
} }
} }
/* /*
Message processor Message processor
*/ */
BOOL message_event_handler( wimp_eventstr *event, void *environment ) BOOL message_event_handler( wimp_eventstr *event, void *environment )
{ {
action_environment *env = environment; action_environment *env = environment;
BOOL processed = No; BOOL processed = No;
switch( event->e )
{
case wimp_ESEND:
case wimp_ESENDWANTACK:
processed = Yes;
switch( event->e ) switch( event->data.msg.hdr.action )
{ {
case wimp_ESEND: case wimp_MPREQUIT:
case wimp_ESENDWANTACK: {
/* amg 9th August 1994. Only return a C/S/F12 */
/* if the flag word tells us that it was a shutdown */
/* or there's no flag word at all */
processed = Yes; int size_of_prequit = event->data.msg.hdr.size;
int flags_of_prequit = event->data.msg.data.words[0];
wimp_t sender = event->data.msg.hdr.task;
char query_message[ 150 ];
wimpt_noerr( ack_message( event ));
/*
Construct a context sensitive message for the query.
*/
sprintf( query_message, msgs_lookup( "81" ), msgs_lookup( icon_strings[ env->operation ][ Help_Message_Operation_Fillin ] ) );
switch( event->data.msg.hdr.action ) switch( dboxquery( query_message ) )
{ {
case wimp_MPREQUIT: case dboxquery_YES:
{ debugact(( "Discard selected\n" ));
/* amg 9th August 1994. Only return a C/S/F12 */ if (!(size_of_prequit > sizeof(wimp_msghdr) && flags_of_prequit & 1))
/* if the flag word tells us that it was a shutdown */ {
/* or there's no flag word at all */ wimp_get_caret_pos( &event->data.key.c );
event->data.key.chcode = akbd_Ctl | akbd_Sh | akbd_Fn12;
int size_of_prequit = event->data.msg.hdr.size; wimp_sendmessage( wimp_EKEY, (wimp_msgstr *)&event->data, sender );
int flags_of_prequit = event->data.msg.data.words[0]; debugact(( "sent message to &%x\n",sender ));
wimp_t sender = event->data.msg.hdr.task; }
char query_message[ 150 ]; abort_operation( env );
break;
wimpt_noerr( ack_message( event ));
case dboxquery_NO:
/* case dboxquery_CANCEL:
Construct a context sensitive message for the query. debugact(( "Cancel selected\n" ));
*/ break;
sprintf( query_message, msgs_lookup( "81" ), msgs_lookup( icon_strings[ env->operation ][ Help_Message_Operation_Fillin ] ) ); }
}
switch( dboxquery( query_message ) ) break;
{
case dboxquery_YES: case wimp_MSETSLOT:
#ifdef debugact debugact(( "Slot(%d,%d) - T=%d\n", event->data.msg.data.words[0],event->data.msg.data.words[1], wimpt_task() ));
dprintf("Discard selected\n"); if ( !env->disable_flex )
#endif {
if (!(size_of_prequit > sizeof(wimp_msghdr) && flags_of_prequit & 1)) if ( event->data.msg.data.words[1] == wimpt_task() )
{ {
wimp_get_caret_pos( &event->data.key.c ); if ( env->flex_memory &&
event->data.key.chcode = 0x1fc; /* ctrl/shft/f12 */ event->data.msg.data.words[0] >= 0 )
wimp_sendmessage( wimp_EKEY, (wimp_msgstr *)&event->data, sender ); {
#ifdef debugact action_slot( event->data.msg.data.words[0] );
dprintf("sent message to &%x\n",sender); }
#endif
}
abort_operation( env );
break;
case dboxquery_NO:
case dboxquery_CANCEL:
#ifdef debugact
dprintf("Cancel selected\n");
#endif
break;
}
}
break;
case wimp_MSETSLOT: wimpt_noerr( ack_message( event ));
#ifdef debugact }
dprintf( "Slot(%d,%d) - T=%d\n", event->data.msg.data.words[0],event->data.msg.data.words[1], wimpt_task() ); else
#endif {
if ( !env->disable_flex ) processed = No;
{ }
if ( event->data.msg.data.words[1] == wimpt_task() ) }
{ break;
if ( env->flex_memory &&
event->data.msg.data.words[0] >= 0 ) case wimp_MHELPREQUEST:
{ event->data.msg.hdr.your_ref = event->data.msg.hdr.my_ref;
action_slot( event->data.msg.data.words[0] ); event->data.msg.hdr.action = wimp_MHELPREPLY;
} event->data.msg.hdr.size = 256; /* enough for all messages */
wimpt_noerr( ack_message( event )); switch( event->data.msg.data.helprequest.m.i )
} {
else case Abort_Button:
{ case No_Skip_Button:
processed = No; case Yes_Retry_Button:
} case Misc_Button:
} case Skip_Button:
break; sprintf( event->data.msg.data.helpreply.text, msgs_lookup( HELP_MESSAGE_CONTROL ),
msgs_lookup( icon_strings[ env->operation ][ Help_Message_Operation_Fillin ] ),
msgs_lookup( env->button_actions.button_helps[ event->data.msg.data.helprequest.m.i - Abort_Button ] ));
break;
case wimp_MHELPREQUEST: default:
event->data.msg.hdr.your_ref = event->data.msg.hdr.my_ref; sprintf( event->data.msg.data.helpreply.text, msgs_lookup( HELP_MESSAGE_CONTROL_NOBUTTON ),
event->data.msg.hdr.action = wimp_MHELPREPLY; msgs_lookup( icon_strings[ env->operation ][ Help_Message_Operation_Fillin ] ));
event->data.msg.hdr.size = 256; /* enough for all messages */ break;
}
wimpt_noerr( wimp_sendmessage( wimp_ESEND, &event->data.msg, event->data.msg.hdr.task ));
break;
case wimp_MFilerSelectionDirectory:
clear_selection( env->test_search );
wimpt_noerr( set_directory( env->test_search, event->data.msg.data.chars ));
env->source_directory_name_length = strlen( event->data.msg.data.chars );
break;
#ifdef USE_LOAD_OPERATIONS
case wimp_MDATALOAD:
if ((env->operation != Action_Copying) &&
(env->operation != Action_Moving) &&
(env->operation != Action_Deleting) &&
(env->operation != Action_Setting_Access) &&
(env->operation != Action_Setting_Type) &&
(env->operation != Action_Counting) &&
(env->operation != Action_Stamping) )
{
/* Generate some kind of error for the user to see */
}
else
{
extern char *get_directory(search_handle);
char *ourdir=get_directory(env->test_search);
char *theirfile=event->data.msg.data.dataload.name;
int ourdirlen=strlen(ourdir);
processed=Yes;
if ( (strncmp(ourdir,theirfile,ourdirlen)==0) &&
(theirfile[ourdirlen]=='.') &&
(strchr(&theirfile[ourdirlen+1],'.')==NULL) )
{ /* It's something we can use - yay! */
char *file= &theirfile[ourdirlen+1];
wimpt_noerr( add_selection( env->test_search, file, strlen(file) ) );
}
}
break;
#endif
switch( event->data.msg.data.helprequest.m.i ) case wimp_MFilerAddSelection:
{ {
case Abort_Button: char *pos;
case No_Skip_Button: int wordlen;
case Yes_Retry_Button: char *wordpos;
case Misc_Button:
case Skip_Button:
sprintf( event->data.msg.data.helpreply.text, msgs_lookup( HELP_MESSAGE_CONTROL ),
msgs_lookup( icon_strings[ env->operation ][ Help_Message_Operation_Fillin ] ),
msgs_lookup( env->button_actions.button_helps[
event->data.msg.data.helprequest.m.i - Abort_Button ] ));
break;
default:
sprintf( event->data.msg.data.helpreply.text, msgs_lookup( HELP_MESSAGE_CONTROL_NOBUTTON ),
msgs_lookup( icon_strings[ env->operation ][ Help_Message_Operation_Fillin ] ));
break;
}
wimpt_noerr( wimp_sendmessage( wimp_ESEND, &event->data.msg, event->data.msg.hdr.task )); /*
break; Wander over the string of selections peeling
them off, one at a time
case wimp_MFilerSelectionDirectory: */
clear_selection( env->test_search ); for ( pos = &event->data.msg.data.chars[0];
wimpt_noerr( set_directory( env->test_search, event->data.msg.data.chars )); *pos != '\0';
env->source_directory_name_length = strlen( event->data.msg.data.chars ); pos++ )
break; {
/*
#ifdef USE_LOAD_OPERATIONS If we have a candidate word
case wimp_MDATALOAD: */
if ((env->operation != Action_Copying) && if ( *pos != SPACE )
(env->operation != Action_Moving) && {
(env->operation != Action_Deleting) && wordpos = strchr( pos, SPACE );
(env->operation != Action_Setting_Access) &&
(env->operation != Action_Setting_Type) && if ( wordpos == NULL )
(env->operation != Action_Counting) &&
(env->operation != Action_Stamping) )
{ {
/* Generate some kind of error for the user to see */ wordlen = strlen( pos );
} }
else else
{ {
extern char *get_directory(search_handle); wordlen = wordpos - pos;
char *ourdir=get_directory(env->test_search);
char *theirfile=event->data.msg.data.dataload.name;
int ourdirlen=strlen(ourdir);
processed=Yes;
if ( (strncmp(ourdir,theirfile,ourdirlen)==0) &&
(theirfile[ourdirlen]=='.') &&
(strchr(&theirfile[ourdirlen+1],'.')==NULL) )
{ /* It's something we can use - yay! */
char *file= &theirfile[ourdirlen+1];
wimpt_noerr( add_selection( env->test_search, file, strlen(file) ) );
}
} }
break;
#endif
case wimp_MFilerAddSelection: wimpt_noerr( add_selection( env->test_search, pos, wordlen ));
{
char *pos;
int wordlen;
char *wordpos;
/*
Wander over the string of selections peeling
them off, one at a time
*/
for ( pos = &event->data.msg.data.chars[0];
*pos != '\0';
pos++ )
{
/*
If we have a candidate word
*/
if ( *pos != SPACE )
{
wordpos = strchr( pos, SPACE );
if ( wordpos == NULL )
{
wordlen = strlen( pos );
}
else
{
wordlen = wordpos - pos;
}
wimpt_noerr( add_selection( env->test_search, pos, wordlen ));
/*
pos is on the last character of the word
*/
pos += wordlen - 1;
}
}
}
break;
case wimp_MFilerAction:
{
os_error *err;
actions_possible action; /*
int options; pos is on the last character of the word
void *auxilliary_information; */
pos += wordlen - 1;
}
}
}
break;
case wimp_MFilerAction:
{
os_error *err;
action = (actions_possible)event->data.msg.data.words[ 0 ]; actions_possible action;
options = event->data.msg.data.words[ 1 ]; int options;
auxilliary_information = &event->data.msg.data.words[ 2 ]; void *auxilliary_information;
err = start_operation( env, action, options, auxilliary_information ); action = (actions_possible)event->data.msg.data.words[ 0 ];
if (err) options = event->data.msg.data.words[ 1 ];
werr(TRUE, err->errmess); auxilliary_information = &event->data.msg.data.words[ 2 ];
}
break;
case wimp_MFilerControlAction: err = start_operation( env, action, options, auxilliary_information );
control_action( env, event ); if (err)
break; werr(TRUE, err->errmess);
}
break;
default: case wimp_MFilerControlAction:
processed = No; control_action( env, event );
break; break;
}
break; default:
processed = No;
break;
} }
break;
}
return processed; return processed;
} }
/*
Because the display of fields is more efficient, we don't hide everything in faster mode
*/
static void hide_faster_stuff( action_environment *env ) static void hide_faster_stuff( action_environment *env )
{ {
if ( env->faster && !env->faster_stuff_hidden ) if ( env->faster && !env->faster_stuff_hidden )
{ {
dbox_setfield( env->status_box, Bottom_Info_Path, "" ); if ( !show_when_faster[ env->operation ][ 0 ] )
dbox_setfield( env->status_box, Bottom_Info_Leaf, "" ); dbox_setfield( env->status_box, Top_Progress_Field, "-" );
if ( !show_when_faster[ env->operation ][ 0 ] ) if ( !show_when_faster[ env->operation ][ 1 ] )
dbox_setfield( env->status_box, Top_Progress_Field, "-" ); dbox_setfield( env->status_box, Bottom_Progress_Field, "-" );
if ( !show_when_faster[ env->operation ][ 1 ] )
dbox_setfield( env->status_box, Bottom_Progress_Field, "-" ); env->faster_stuff_hidden = Yes;
set_faster_state ( env );
env->faster_stuff_hidden = Yes; }
/* JRF: Make the 'Faster' button show 'Slower' now */
set_faster_state ( env );
}
} }
void show_faster_stuff( action_environment *env ) void show_faster_stuff( action_environment *env )
{ {
if ( env->faster_stuff_hidden ) if ( env->faster_stuff_hidden )
{
if ( !show_when_faster[ env->operation ][ 0 ] )
dbox_setlongnumeric( env->status_box, Top_Progress_Field, env->top_progress );
if ( !show_when_faster[ env->operation ][ 1 ] )
{ {
dbox_setfield( env->status_box, Bottom_Info_Path, newpath ); dbox_setlongnumeric( env->status_box, Bottom_Progress_Field, env->bottom_progress );
dbox_setfield( env->status_box, Bottom_Info_Leaf, newleaf ); }
if ( !show_when_faster[ env->operation ][ 0 ] )
dbox_setlongnumeric( env->status_box, Top_Progress_Field, env->top_progress );
if ( !show_when_faster[ env->operation ][ 1 ] )
{
dbox_setlongnumeric( env->status_box, Bottom_Progress_Field, env->bottom_progress );
/* char buf[20]; */
/* sprintf(buf,"%u",env->bottom_progress); */
/* dbox_setfield( env->status_box, Bottom_Progress_Field, buf ); */
}
env->faster_stuff_hidden = No; env->faster_stuff_hidden = No;
/* JRF: Make the 'Faster' button show 'Faster' now */ set_faster_state( env );
set_faster_state( env ); }
}
} }
void option_menu_handler( action_environment *env, char *hit ) void option_menu_handler( action_environment *env, char *hit )
{ {
switch( hit[0] ) switch( hit[0] )
{ {
case 1: /* faster */ case 1: /* faster */
toggle_faster( env ); /* JRF: Now a function to aid the */ toggle_faster( env ); /* JRF: Now a function to aid the */
/* button */ /* button */
break; break;
case 2: /* confirm */
env->confirm = !env->confirm;
break;
case 3: /* verbose */
if ( env->verbose )
go_terse( env );
else
go_verbose( env );
break;
case 2: /* confirm */ case 4: /* force */
env->confirm = !env->confirm; env->force = !env->force;
break; break;
case 3: /* verbose */ case 5: /* newer */
if ( env->verbose ) env->looknewer = !env->looknewer;
go_terse( env ); break;
else
go_verbose( env );
break;
case 4: /* force */ default:
env->force = !env->force; break;
break; }
case 5: /* newer */ reflect_menu_flags( env );
env->looknewer = !env->looknewer;
break;
default:
break;
}
reflect_menu_flags( env );
} }
void switch_to_writing( action_environment *env ) void switch_to_writing( action_environment *env )
{ {
env->current_info = msgs_lookup( "82" ); env->current_info = msgs_lookup( "82" );
...@@ -1073,84 +1226,81 @@ void switch_to_writing( action_environment *env ) ...@@ -1073,84 +1226,81 @@ void switch_to_writing( action_environment *env )
*/ */
static os_error *create_destination_localfile( action_environment *env, char *source, char **destination ) static os_error *create_destination_localfile( action_environment *env, char *source, char **destination )
{ {
char *sourcegunge; char *sourcegunge;
char *sourceleaf = source + env->source_directory_name_length + 1; char *sourceleaf = source + env->source_directory_name_length + 1;
char *destleaf; char *destleaf;
char *temp; char *temp;
/* /*
This takes This takes
source = <source dir><source leaf><gunge> source = <source dir><source leaf><gunge>
and and
dest = <dest dir><dest leaf> dest = <dest dir><dest leaf>
making making
destn = <destdir><dest leaf><gunge> destn = <destdir><dest leaf><gunge>
or or
dest = <dest leaf> dest = <dest leaf>
making making
destn = <source dir><dest leaf><gunge> destn = <source dir><dest leaf><gunge>
*/ */
/* /*
sourcegunge points to the stuff past the source leaf (which is sourcegunge points to the stuff past the source leaf (which is
one of the selected items). one of the selected items).
*/ */
if ( strchr( sourceleaf, '.' ) == 0 ) if ( strchr( sourceleaf, '.' ) == 0 )
{ {
sourcegunge = source + strlen( source ); sourcegunge = source + strlen( source );
} }
else else
{ {
sourcegunge = strchr( sourceleaf, '.' ); sourcegunge = strchr( sourceleaf, '.' );
} }
/*
destleaf points to the leaf part of the destination
*/
destleaf = strrchr( env->destination_name, '.' );
temp = strrchr( env->destination_name, ':' );
if ( temp > destleaf )
destleaf = temp;
if ( destleaf == NULL )
{
destleaf = env->destination_name;
}
else
{
destleaf++; /* move beyond the separator (. or :) */
}
if ( destleaf > env->destination_name )
{
/* /*
destleaf points to the leaf part of the destination Destination directory is present
*/ */
destleaf = strrchr( env->destination_name, '.' ); *destination = overflowing_malloc( strlen( env->destination_name ) + strlen( sourcegunge ) + 1 );
temp = strrchr( env->destination_name, ':' );
if ( temp > destleaf ) if ( *destination == NULL )
destleaf = temp; return error( mb_malloc_failed );
if ( destleaf == NULL ) sprintf( *destination, "%s%s", env->destination_name, sourcegunge );
{ }
destleaf = env->destination_name; else
} {
else *destination = overflowing_malloc( env->source_directory_name_length + 1 + strlen( env->destination_name ) + strlen( sourcegunge ) + 1 );
{
destleaf++; /* move beyond the separator (. or :) */
}
if ( destleaf > env->destination_name )
{
/*
Destination directory is present
*/
*destination = overflowing_malloc( strlen( env->destination_name ) + strlen( sourcegunge ) + 1 );
if ( *destination == NULL )
return error( mb_malloc_failed );
sprintf( *destination, "%s%s", env->destination_name, sourcegunge );
}
else
{
*destination = overflowing_malloc( env->source_directory_name_length + 1 + strlen( env->destination_name ) +
strlen( sourcegunge ) + 1 );
if ( *destination == NULL ) if ( *destination == NULL )
return error( mb_malloc_failed ); return error( mb_malloc_failed );
strncpy( *destination, source, env->source_directory_name_length + 1 ); strncpy( *destination, source, env->source_directory_name_length + 1 );
sprintf( *destination + env->source_directory_name_length + 1, "%s%s", sprintf( *destination + env->source_directory_name_length + 1, "%s%s", env->destination_name, sourcegunge );
env->destination_name, }
sourcegunge );
}
return NULL; return NULL;
} }
/* /*
...@@ -1174,151 +1324,133 @@ static os_error *create_destination_filename( action_environment *env, char *sou ...@@ -1174,151 +1324,133 @@ static os_error *create_destination_filename( action_environment *env, char *sou
/* /*
Add next file to read list Add next file to read list
*/ */
static os_error *test_add_to_read_list( action_environment *env, int *should_be_added ) static os_error *test_add_to_read_list( action_environment *env, BOOL *should_be_added )
{ {
char *destination; char *destination;
char *source; char *source;
os_filestr fileplace; os_filestr fileplace;
os_error *err; os_error *err;
int source_reload; int source_reload;
int destination_reload; int destination_reload;
wimpt_noerr( next_nodename( env->test_search, &source )); wimpt_noerr( next_nodename( env->test_search, &source ));
if ( env->operation != Action_CopyLocal ) if ( env->operation != Action_CopyLocal )
{ {
wimpt_noerr( create_destination_filename( env, source, &destination )); wimpt_noerr( create_destination_filename( env, source, &destination ));
} }
else else
{ {
wimpt_noerr( create_destination_localfile( env, source, &destination )); wimpt_noerr( create_destination_localfile( env, source, &destination ));
} }
source_reload = reload_of_next_node( env->test_search );
/*
Only look newer if source has a datestamp
*/
if ( env->looknewer &&
( source_reload & DateStamped_Mask ) == DateStamped_Mask &&
objecttype_of_next_node( env->test_search ) != object_directory )
{
/*
Get the destination's information
*/
fileplace.action = OSFile_ReadInfo;
fileplace.name = destination;
source_reload = reload_of_next_node( env->test_search ); err = os_file( &fileplace );
/* /*
Only look newer if source has a datestamp If an error happened which wasn't 'not found' then return
with that error. 'not found' means datestamp checking need
not happen.
*/ */
if ( env->looknewer && if ( err )
( source_reload & DateStamped_Mask ) == DateStamped_Mask &&
objecttype_of_next_node( env->test_search ) != ObjectType_Directory )
{ {
/* if ( ( err->errnum & FileError_Mask ) != ErrorNumber_NotFound )
Get the destination's information {
*/ overflowing_free( source );
fileplace.action = 5; /* read catalogue information */ overflowing_free( destination );
fileplace.name = destination;
err = os_file( &fileplace );
/* return err;
If an error happened which wasn't 'not found' then return }
with that error. 'not found' means datestamp checking need }
not happen. else
*/ {
if ( err ) /*
If destination is datestamped after source, then don't
add source to read list
*/
destination_reload = fileplace.loadaddr;
if ( ( destination_reload & DateStamped_Mask ) == DateStamped_Mask )
{
if ( (destination_reload & DateStamp_HighByte) >
(source_reload & DateStamp_HighByte) ||
( (destination_reload & DateStamp_HighByte) ==
(source_reload & DateStamp_HighByte) &&
(unsigned int)fileplace.execaddr >=
(unsigned int)execute_of_next_node( env->test_search ) )
)
{ {
if ( ( err->errnum & FileError_Mask ) != ErrorNumber_NotFound ) overflowing_free( source );
{ overflowing_free( destination );
overflowing_free( source );
overflowing_free( destination );
return err; *should_be_added = No;
}
} return NULL;
else
{
/*
If destination is datestamped after source, then don't
add source to read list
*/
destination_reload = fileplace.loadaddr;
if ( ( destination_reload & DateStamped_Mask ) == DateStamped_Mask )
{
if ( (destination_reload & DateStamp_HighByte) >
(source_reload & DateStamp_HighByte) ||
( (destination_reload & DateStamp_HighByte) ==
(source_reload & DateStamp_HighByte) &&
(unsigned int)fileplace.execaddr >=
(unsigned int)execute_of_next_node( env->test_search ) )
)
{
overflowing_free( source );
overflowing_free( destination );
*should_be_added = No;
return NULL;
}
}
} }
}
} }
}
overflowing_free( destination ); overflowing_free( destination );
overflowing_free( source ); overflowing_free( source );
*should_be_added = Yes; *should_be_added = Yes;
return NULL; return NULL;
} }
/* /*
This actually adds the next file to the read list. This actually adds the next file to the read list.
*/ */
static void add_to_read_list( action_environment *env, int *i_am_full ) static void add_to_read_list( action_environment *env, BOOL *i_am_full )
{ {
char *destination; char *destination;
char *source; char *source;
wimpt_noerr( next_nodename( env->test_search, &source ));
if ( env->operation != Action_CopyLocal )
{
wimpt_noerr( create_destination_filename( env, source, &destination ));
}
else
{
wimpt_noerr( create_destination_localfile( env, source, &destination ));
}
wimpt_noerr( add_file_to_chain( destination, source, wimpt_noerr( next_nodename( env->test_search, &source ));
size_of_next_node( env->test_search ),
reload_of_next_node( env->test_search ),
execute_of_next_node( env->test_search ),
attributes_of_next_node( env->test_search ),
objecttype_of_next_node( env->test_search ),
env->force,
i_am_full ));
overflowing_free( destination ); if ( env->operation != Action_CopyLocal )
overflowing_free( source ); {
wimpt_noerr( create_destination_filename( env, source, &destination ));
switch_to_reading( env ); }
} else
{
/* wimpt_noerr( create_destination_localfile( env, source, &destination ));
Record more top progress }
*/
static void more_top_progress( action_environment *env, int change ) wimpt_noerr( add_file_to_chain( destination, source,
{ size_of_next_node( env->test_search ),
env->top_progress += change; reload_of_next_node( env->test_search ),
set_top_progress_field( env, env->top_progress ); execute_of_next_node( env->test_search ),
attributes_of_next_node( env->test_search ),
objecttype_of_next_node( env->test_search ),
env->force,
i_am_full
#ifdef USE_PROGRESS_BAR
, progress_of_next_node( env->test_search )
, chain_ref_ptr_of_next_node(env->test_search)
#endif
));
overflowing_free( destination );
overflowing_free( source );
switch_to_reading( env );
} }
/*
Record more bottom progress
*/
static void more_bottom_progress( action_environment *env, unsigned int change )
{
env->bottom_progress += change;
if ( !env->faster || show_when_faster[ env->operation ][ 1 ] )
{
dbox_setlongnumeric( env->status_box, Bottom_Progress_Field, env->bottom_progress);
/* char buf[20]; */
/* sprintf(buf,"%u",env->bottom_progress); */
/* dbox_setfield( env->status_box, Bottom_Progress_Field, buf ); */
}
}
/* /*
Get the access of a file Get the access of a file
...@@ -1328,7 +1460,7 @@ static os_error *get_access_to_file( char *filename, int *access ) ...@@ -1328,7 +1460,7 @@ static os_error *get_access_to_file( char *filename, int *access )
os_error *err; os_error *err;
os_filestr fileplace; os_filestr fileplace;
fileplace.action = 5; /* get file attributes */ fileplace.action = OSFile_ReadInfo;
fileplace.name = filename; fileplace.name = filename;
err = os_file( &fileplace ); err = os_file( &fileplace );
...@@ -1337,6 +1469,7 @@ static os_error *get_access_to_file( char *filename, int *access ) ...@@ -1337,6 +1469,7 @@ static os_error *get_access_to_file( char *filename, int *access )
return err; return err;
} }
/* /*
Set the access to any file Set the access to any file
*/ */
...@@ -1344,25 +1477,27 @@ static os_error *set_access_to_file( char *filename, int access ) ...@@ -1344,25 +1477,27 @@ static os_error *set_access_to_file( char *filename, int access )
{ {
os_filestr fileplace; os_filestr fileplace;
fileplace.action = 4; /* set file attributes */ fileplace.action = OSFile_WriteAttr;
fileplace.name = filename; fileplace.name = filename;
fileplace.end = access; fileplace.end = access;
return os_file( &fileplace ); return os_file( &fileplace );
} }
/* /*
Attempt to delete a node Attempt to delete a node
*/ */
static os_error *delete_node(char *name) static os_error *delete_node(char *name)
{ {
os_filestr fileplace; os_filestr fileplace;
fileplace.action = 6; /* delete object */ fileplace.action = OSFile_Delete;
fileplace.name = name; fileplace.name = name;
return os_file( &fileplace ); return os_file( &fileplace );
} }
/* /*
Set the access of next node Set the access of next node
*/ */
...@@ -1383,6 +1518,7 @@ static os_error *set_access( action_environment *env, int access ) ...@@ -1383,6 +1518,7 @@ static os_error *set_access( action_environment *env, int access )
return err; return err;
} }
/* /*
Stamp any file Stamp any file
*/ */
...@@ -1390,12 +1526,13 @@ static os_error *stamp_file( char *filename ) ...@@ -1390,12 +1526,13 @@ static os_error *stamp_file( char *filename )
{ {
os_filestr fileplace; os_filestr fileplace;
fileplace.action = 9; /* stamp file */ fileplace.action = OSFile_SetStamp;
fileplace.name = filename; fileplace.name = filename;
return os_file( &fileplace ); return os_file( &fileplace );
} }
/* /*
Stamp next node Stamp next node
*/ */
...@@ -1416,1007 +1553,1104 @@ static os_error *stamp( action_environment *env ) ...@@ -1416,1007 +1553,1104 @@ static os_error *stamp( action_environment *env )
return err; return err;
} }
/* /*
Do a rename Do a rename
*/ */
static os_error *riscos_rename( action_environment *env ) static os_error *riscos_rename( action_environment *env )
{ {
os_error *err; os_error *err;
os_regset r; os_regset r;
char *source; char *source;
char *destination; char *destination;
int should_be_added; BOOL should_be_added;
test_add_to_read_list(env, &should_be_added); test_add_to_read_list(env, &should_be_added);
wimpt_noerr( next_nodename( env->test_search, &source )); wimpt_noerr( next_nodename( env->test_search, &source ));
if (!should_be_added) return 0; if (!should_be_added) return 0;
wimpt_noerr( create_destination_filename( env, source, &destination )); wimpt_noerr( create_destination_filename( env, source, &destination ));
#ifdef debugact debugact(( "riscos_rename: src = %s, dest = %s\n",source,destination ));
dprintf("riscos_rename: src = %s, dest = %s\n",source,destination); r.r[0] = FSControl_Rename;
#endif r.r[1] = (int)source;
r.r[0] = 25; /* rename */ r.r[2] = (int)destination;
r.r[1] = (int)source;
r.r[2] = (int)destination;
err = os_swix( OS_FSControl, &r ); err = os_swix( OS_FSControl, &r );
overflowing_free( source ); overflowing_free( source );
overflowing_free( destination ); overflowing_free( destination );
return err; return err;
} }
static os_error *Do_Next_File( action_environment *env ) static os_error *Do_Next_File( action_environment *env )
{ {
os_error *err; os_error *err;
char *filename; char *filename;
int inhibit_confirm = No; BOOL inhibit_confirm = No;
int is_cvs_directory = No; BOOL is_cvs_directory = No;
uint32_t p = 0;
err = step_to_next_node( env->test_search, &p);
#ifdef USE_PROGRESS_BAR
add_progress(env, p, "Do_Next_File");
#endif
err = step_to_next_node( env->test_search ); if ( err )
return err;
if ( another_node( env->test_search ))
{
err = next_nodename( env->test_search, &filename );
if ( err ) if ( err )
return err; return err;
if ( another_node( env->test_search )) set_bottom_info_field( env, filename );
if ( env->auto_skip_cvs )
{ {
err = next_nodename( env->test_search, &filename ); size_t length = strlen( filename );
if (length > 4 && strcmp(filename + length - 4, ".CVS") == 0)
{
is_cvs_directory = Yes;
}
else if (length > 8 && strcmp(filename + length - 8, "./cvstag") == 0)
{
is_cvs_directory = Yes;
}
}
if ( err ) overflowing_free( filename );
return err;
set_bottom_info_field( env, filename ); switch( env->operation )
{
case Action_Copying:
case Action_CopyLocal:
env->action = Test_Add_To_Read_List;
inhibit_confirm = Yes;
if ( is_cvs_directory == Yes)
{
skip_list_file(env->test_search);
env->action = Next_File;
}
break;
if ( env->auto_skip_cvs ) { case Action_Moving:
size_t length = strlen( filename ); env->action = Attempt_1st_Rename;
if (length > 4 && strcmp(filename + length - 4, ".CVS") == 0) break;
{
is_cvs_directory = Yes;
}
else if (length > 8 && strcmp(filename + length - 8, "./cvstag") == 0)
{
is_cvs_directory = Yes;
}
}
overflowing_free( filename ); case Action_CopyMoving:
if ( objecttype_of_next_node( env->test_search ) == object_directory &&
directory_is_after_contents( env->test_search ) )
{
env->action = Add_To_Read_List;
}
else
{
env->action = Test_Add_To_Read_List;
}
inhibit_confirm = Yes;
break;
switch( env->operation ) case Action_Deleting:
if ( objecttype_of_next_node( env->test_search ) == object_directory )
{
if ( directory_is_after_contents( env->test_search ) )
{ {
case Action_Copying: env->action = Attempt_Delete;
case Action_CopyLocal: inhibit_confirm = Yes;
env->action = Test_Add_To_Read_List; }
inhibit_confirm = Yes; else
if ( is_cvs_directory == Yes) {
{ env->action = Next_File;
skip_list_file(env->test_search); }
env->action = Next_File; }
} else
break; {
env->action = Attempt_Delete;
}
break;
case Action_Moving: case Action_Setting_Access:
env->action = Attempt_1st_Rename; env->action = Attempt_Set_Access;
break; break;
case Action_CopyMoving: case Action_Setting_Type:
if ( objecttype_of_next_node( env->test_search ) == ObjectType_Directory && env->action = Attempt_Set_Type;
directory_is_after_contents( env->test_search ) ) break;
{
env->action = Add_To_Read_List;
}
else
{
env->action = Test_Add_To_Read_List;
}
inhibit_confirm = Yes;
break;
case Action_Deleting: case Action_Counting:
if ( objecttype_of_next_node( env->test_search ) == ObjectType_Directory ) more_top_progress( env, 1 );
{ more_bottom_progress( env, size_of_next_node( env->test_search ) );
if ( directory_is_after_contents( env->test_search ) )
{
env->action = Attempt_Delete;
inhibit_confirm = Yes;
}
else
{
env->action = Next_File;
}
}
else
{
env->action = Attempt_Delete;
}
break;
case Action_Setting_Access: #ifdef USE_PROGRESS_BAR
env->action = Attempt_Set_Access; add_progress(env, progress_of_next_node(env->test_search), "Action_Counting");
break; #endif
break;
case Action_Setting_Type: case Action_Stamping:
env->action = Attempt_Set_Type; env->action = Attempt_Stamp;
break; break;
case Action_Counting: case Action_Finding:
more_top_progress( env, 1 ); if ( !caseless_wildcmp( env->destination_name, name_of_next_node( env->test_search )) )
more_bottom_progress( env, size_of_next_node( env->test_search ) ); {
break; set_top_info_field( env, "84" );
case Action_Stamping: if ( (objecttype_of_next_node( env->test_search ) == object_directory &&
env->action = Attempt_Stamp; name_of_next_node( env->test_search )[0] != '!') ||
break; objecttype_of_next_node( env->test_search ) == (object_directory | object_file) )
{
switch_buttons( env, &open_buttons );
}
else
{
switch_buttons( env, &run_view_buttons );
}
}
case Action_Finding: /*
if ( !caseless_wildcmp( env->destination_name, name_of_next_node( env->test_search )) ) Keep the user informed of what's happening
{ */
last_top_info_field = msgs_lookup( "84" ); if ( objecttype_of_next_node( env->test_search ) != object_file )
dbox_setfield( env->status_box, Top_Info_Field, last_top_info_field ); {
if ( (objecttype_of_next_node( env->test_search ) == ObjectType_Directory && more_top_progress( env, 1 );
name_of_next_node( env->test_search )[0] != '!') || }
objecttype_of_next_node( env->test_search ) == (ObjectType_Directory | ObjectType_File) ) else
{ {
switch_buttons( env, &open_buttons ); more_bottom_progress( env, 1 );
} }
else
{
switch_buttons( env, &run_view_buttons );
}
}
/* #ifdef USE_PROGRESS_BAR
Keep the user informed of what's happening add_progress(env, progress_of_next_node(env->test_search), "Action_Finding");
*/ #endif
if ( objecttype_of_next_node( env->test_search ) != ObjectType_File )
{
more_top_progress( env, 1 );
}
else
{
more_bottom_progress( env, 1 );
}
break;
default: break;
break;
}
/* default:
Don't confirm until we are sure this file is going to break;
be added to the read list.
*/
if ( env->confirm &&
!inhibit_confirm )
{
switch_buttons( env, &confirm_buttons );
last_top_info_field = msgs_lookup( action_prompt[ env->operation ] );
dbox_setfield( env->status_box, Top_Info_Field, last_top_info_field );
}
} }
else
/*
Don't confirm until we are sure this file is going to
be added to the read list.
*/
if ( env->confirm &&
!inhibit_confirm )
{ {
/* switch_buttons( env, &confirm_buttons );
No more files set_top_info_field( env, action_prompt[ env->operation ] );
*/ }
if ( env->operation == Action_Copying || }
env->operation == Action_CopyMoving || else
env->operation == Action_CopyLocal ) {
{ /*
switch_to_writing( env ); No more files
} */
else if ( env->operation == Action_Counting ) if ( env->operation == Action_Copying ||
{ env->operation == Action_CopyMoving ||
/* env->operation == Action_CopyLocal )
Change buttons, display dbox, clear {
unwanted fields etc switch_to_writing( env );
*/ }
switch_buttons( env, &ok_button ); else if ( env->operation == Action_Counting )
{
/*
Change buttons, display dbox, clear
unwanted fields etc
*/
switch_buttons( env, &ok_button );
set_top_info_field( env, "85" );
set_bottom_info_field( env, env->selection_summary );
}
else if ( ( env->operation == Action_Deleting ||
env->operation == Action_CopyMoving ) &&
env->locked_not_deleted > 0 )
{
char top_field[ 50 ];
dbox_setfield( env->status_box, Top_Info_Field, msgs_lookup( "85" )); switch_buttons( env, &ok_button );
set_bottom_info_field( env, env->selection_summary );
}
else if ( ( env->operation == Action_Deleting ||
env->operation == Action_CopyMoving ) &&
env->locked_not_deleted > 0 )
{
char top_field[ 50 ];
switch_buttons( env, &ok_button ); sprintf( top_field, msgs_lookup( "86" ), env->locked_not_deleted );
sprintf( top_field, msgs_lookup( "86" ), env->locked_not_deleted ); set_top_info_field( env, "85" );
set_bottom_info_field( env, top_field);
dbox_setfield( env->status_box, Top_Info_Field, top_field );
set_bottom_info_field( env, env->selection_summary );
}
else
{
/*
Finished doing everything else, so
kill ourselves off
*/
abort_operation( env );
}
} }
else
{
/*
Finished doing everything else, so
kill ourselves off
*/
abort_operation( env );
}
}
return NULL; return NULL;
} }
static os_error *Do_Test_Add_To_Read_List( action_environment *env ) static os_error *Do_Test_Add_To_Read_List( action_environment *env )
{ {
os_error *err; os_error *err;
int should_be_added; BOOL should_be_added;
err = test_add_to_read_list( env, &should_be_added ); err = test_add_to_read_list( env, &should_be_added );
if ( err ) if ( err )
return err; return err;
if ( should_be_added ) if ( should_be_added )
{ {
env->action = Add_To_Read_List; env->action = Add_To_Read_List;
/* /*
Confirm if necessary. Confirm if necessary.
*/ */
if ( env->confirm ) if ( env->confirm )
{
switch_buttons( env, &confirm_buttons );
last_top_info_field = msgs_lookup( action_prompt[ env->operation ] );
dbox_setfield( env->status_box, Top_Info_Field, last_top_info_field );
}
}
else
{ {
env->action = Next_File; switch_buttons( env, &confirm_buttons );
set_top_info_field( env, action_prompt[ env->operation ] );
} }
}
else
{
env->action = Next_File;
}
return NULL; return NULL;
} }
static os_error *Do_Add_To_Read_List( action_environment *env ) static os_error *Do_Add_To_Read_List( action_environment *env )
{ {
int i_am_full; BOOL i_am_full;
add_to_read_list( env, &i_am_full ); add_to_read_list( env, &i_am_full );
if ( i_am_full ) if ( i_am_full )
switch_to_writing( env ); switch_to_writing( env );
return NULL; return NULL;
} }
static os_error *Do_Check_Full_Reading( action_environment *env ) static os_error *Do_Check_Full_Reading( action_environment *env )
{ {
os_error *err; os_error *err;
int i_am_full; BOOL i_am_full;
int need_another_file; BOOL need_another_file;
int that_finished_a_file; BOOL that_finished_a_file;
uint32_t p = 0;
err = read_a_block( &i_am_full, &need_another_file, &that_finished_a_file ); err = read_a_block( &i_am_full, &need_another_file, &that_finished_a_file, &p );
if ( err ) if ( err )
return err; return err;
if ( i_am_full ) #ifdef USE_PROGRESS_BAR
add_progress(env, p, "Block read");
#endif
if ( i_am_full )
{
switch_to_writing( env );
}
else if ( need_another_file )
{
if ( another_node( env->test_search ))
{ {
switch_to_writing( env ); env->action = Next_File;
} }
else if ( need_another_file ) else if ( next_file_to_be_written() == NULL )
{ {
if ( another_node( env->test_search )) abort_operation( env );
{
env->action = Next_File;
}
else if ( next_file_to_be_written() == NULL )
{
abort_operation( env );
}
else
{
switch_to_writing( env );
}
} }
else else
{ {
set_top_progress_field( env, bytes_left_to_read()); switch_to_writing( env );
}
}
else
{
set_top_progress_field( env, bytes_left_to_read());
if ( that_finished_a_file ) if ( that_finished_a_file )
{ {
set_bottom_info_field( env, next_file_to_be_read()); set_bottom_info_field( env, next_file_to_be_read());
}
} }
}
return NULL; return NULL;
} }
static os_error *Do_Check_Empty_Writing( action_environment *env ) static os_error *Do_Check_Empty_Writing( action_environment *env )
{ {
os_error *err; os_error *err;
int i_am_empty; BOOL i_am_empty;
int that_finished_a_file; BOOL that_finished_a_file;
uint32_t p = 0;
err = write_a_block( &i_am_empty, &that_finished_a_file ); err = write_a_block( &i_am_empty, &that_finished_a_file, &p );
if ( err ) if ( err )
return err; return err;
if ( i_am_empty ) #ifdef USE_PROGRESS_BAR
{ add_progress(env, p, "Block write");
switch_to_reading( env ); #endif
}
else if ( that_finished_a_file ) if ( i_am_empty )
{
switch_to_reading( env );
}
else if ( that_finished_a_file )
{
if ( env->operation != Action_CopyMoving )
{ {
if ( env->operation != Action_CopyMoving ) if ( finished_obj_was_file )
{ {
if ( size_of_finished_file >= 0 ) more_bottom_progress( env, 1 );
{ }
more_bottom_progress( env, 1 );
}
set_bottom_info_field( env, next_file_to_be_written()); set_bottom_info_field( env, next_file_to_be_written());
set_top_progress_field( env, bytes_left_to_write()); set_top_progress_field( env, bytes_left_to_write());
}
else
{
/*
We are copyMoving, hence:
Attempt_Delete (will work for dirs on way up tree, but fail on way down)
*/
env->action = Attempt_Delete;
}
} }
else else
{ {
set_top_progress_field( env, bytes_left_to_write()); /*
We are copyMoving, hence:
Attempt_Delete (will work for dirs on way up tree, but fail on way down)
*/
env->action = Attempt_Delete;
} }
}
else
{
set_top_progress_field( env, bytes_left_to_write());
}
return NULL; return NULL;
} }
static os_error *Do_Attempt_Rename( action_environment *env, int which_one ) static os_error *Do_Attempt_Rename( action_environment *env, int which_one )
{ {
os_error *err; os_error *err;
err = riscos_rename( env ); err = riscos_rename( env );
if ( err ) if ( err )
{
switch ( err->errnum & FileError_Mask )
{ {
switch ( err->errnum & FileError_Mask ) case ErrorNumber_Locked:
{ if ( which_one == 1 )
case ErrorNumber_Locked: {
if ( which_one == 1 ) env->action = Attempt_Unlock;
{ err = NULL;
env->action = Attempt_Unlock; }
err = NULL; break;
}
break; case ErrorNumber_NotSameDisc:
case ErrorNumber_BadRename:
case ErrorNumber_NotSameDisc: case ErrorNumber_AlreadyExists:
case ErrorNumber_BadRename: if ( which_one == 1 )
case ErrorNumber_AlreadyExists: env->action = Convert_To_CopyMove;
if ( which_one == 1 ) else
env->action = Convert_To_CopyMove; env->action = Convert_To_CopyMove_After_Unlock;
else err = NULL;
env->action = Convert_To_CopyMove_After_Unlock; break;
err = NULL; }
break; }
} else
{
if ( which_one == 1 )
{
more_bottom_progress( env, 1 );
env->action = Next_File;
} }
else else
{ {
if ( which_one == 1 ) env->action = Attempt_Relock;
{
more_bottom_progress( env, 1 );
env->action = Next_File;
}
else
{
env->action = Attempt_Relock;
}
} }
#ifdef USE_PROGRESS_BAR
add_progress(env, progress_of_next_node(env->test_search), "Do_Attempt_Rename");
#endif
}
return err; return err;
} }
static os_error *Do_Attempt_Unlock( action_environment *env ) static os_error *Do_Attempt_Unlock( action_environment *env )
{ {
os_error *err; os_error *err;
char *filename; char *filename;
err = next_nodename( env->test_search, &filename ); err = next_nodename( env->test_search, &filename );
if ( err ) if ( err )
return err; return err;
/* /*
Ignore error as don't care if it fails Ignore error as don't care if it fails
*/ */
(void)set_access_to_file( filename, attributes_of_next_node( env->test_search ) & ~Attribute_Locked ); (void)set_access_to_file( filename, attributes_of_next_node( env->test_search ) & ~locked_attribute );
overflowing_free( filename ); overflowing_free( filename );
env->action = Attempt_2nd_Rename; env->action = Attempt_2nd_Rename;
return NULL; return NULL;
} }
/* /*
Relock destination of rename after unlocking source Relock destination of rename after unlocking source
*/ */
static os_error *Do_Attempt_Relock( action_environment *env ) static os_error *Do_Attempt_Relock( action_environment *env )
{ {
os_error *err; os_error *err;
char *source; char *source;
char *destination; char *destination;
err = next_nodename( env->test_search, &source ); err = next_nodename( env->test_search, &source );
if ( err ) if ( err )
return err; return err;
err = create_destination_filename( env, source, &destination ); err = create_destination_filename( env, source, &destination );
overflowing_free( source ); overflowing_free( source );
if ( err ) if ( err )
return err; return err;
/* /*
Ignore error as don't care if it fails Ignore error as don't care if it fails
*/ */
(void)set_access_to_file( destination, attributes_of_next_node( env->test_search ) ); (void)set_access_to_file( destination, attributes_of_next_node( env->test_search ) );
overflowing_free( destination ); overflowing_free( destination );
more_bottom_progress( env, 1 ); more_bottom_progress( env, 1 );
env->action = Next_File; env->action = Next_File;
return NULL; return NULL;
} }
static os_error *Do_Convert_To_CopyMove( action_environment *env, int after_unlock )
{
os_error *err;
char *filename;
static os_error *Do_Convert_To_CopyMove( action_environment *env, BOOL after_unlock )
{
os_error *err;
char *filename;
/*
Relock the node if necessary, don't object if this
fails!
*/
if ( after_unlock )
{
/* /*
Relock the node if necessary, don't object if this return the attributes to their old values (but ignore errors back)
fails!
*/ */
if ( after_unlock )
{
/*
return the attributes to their old values (but ignore errors back)
*/
err = next_nodename( env->test_search, &filename );
if ( err )
return err;
(void)set_access_to_file( filename, attributes_of_next_node( env->test_search ));
overflowing_free( filename ); err = next_nodename( env->test_search, &filename );
}
init_for_copying();
env->flex_memory = Yes;
env->operation = Action_CopyMoving;
env->action = Add_To_Read_List;
return_directories_first( env->test_search, Yes );
return_directories_last( env->test_search, Yes );
recurse_search_context( env->test_search, Yes );
err = selection_summary( env->test_search, &env->selection_summary ); if ( err )
return err;
env->locked_not_deleted = 0; (void)set_access_to_file( filename, attributes_of_next_node( env->test_search ));
return err; overflowing_free( filename );
}
init_for_copying();
env->flex_memory = Yes;
env->operation = Action_CopyMoving;
env->action = Add_To_Read_List;
return_directories_first( env->test_search, Yes );
return_directories_last( env->test_search, Yes );
recurse_search_context( env->test_search, Yes );
/*
Reset the progress bar as the operation is restarted as a copymove
*/
#ifdef USE_PROGRESS_BAR
debugact(( "changed operation: %s\n", debug_operation( env->operation ) ));
listfiles_convert_to_copymove( env->test_search );
env->progress = 0;
#endif
err = selection_summary( env->test_search, &env->selection_summary );
env->locked_not_deleted = 0;
return err;
} }
static os_error *Do_Attempt_Delete( action_environment *env ) static os_error *Do_Attempt_Delete( action_environment *env )
{ {
os_error *err; os_error *err;
char *filename; char *filename;
int inhibit_progress = No; BOOL inhibit_progress = No;
int prev_access; int prev_access;
uint32_t p = 0;
if ( env->operation != Action_CopyMoving )
{ if ( env->operation != Action_CopyMoving )
wimpt_noerr( next_nodename( env->test_search, &filename )); {
} wimpt_noerr( next_nodename( env->test_search, &filename ));
else #ifdef USE_PROGRESS_BAR
{ p = progress_of_next_node(env->test_search);
filename = source_of_finished_file; #endif
} }
else
#ifdef debugact {
dprintf("Do_Attempt_Delete: filename = %s\n",filename); filename = finished_obj_source_name;
#endif }
debugact(( "Do_Attempt_Delete: filename = %s p = %08x\n", filename, p ));
/*
JRS 29/1/92 1st attempt to delete the node without touching the access.
In most cases this will work without further ado
*/
err = delete_node( filename );
/*
If forcing delete, set no read/write access and
unlock it. If this fails, then the delete will
never work!
*/
prev_access = -1; /* special value to test for */
if ( (err != NULL) &&
(env->force ||
env->operation == Action_CopyMoving) )
{
err = get_access_to_file(filename, &prev_access);
if ( err ) prev_access = -1;
err = set_access_to_file(filename, prev_access & ~locked_attribute);
if ( err && (err->errnum & FileError_Mask) != ErrorNumber_NotFound )
return err;
/* /*
JRS 29/1/92 1st attempt to delete the node without touching the access. Retry deletion
In most cases this will work without further ado
*/ */
err = delete_node( filename ); err = delete_node( filename );
}
/*
If forcing delete, set no read/write access and
unlock it. If this fails, then the delete will
never work!
*/
prev_access = -1; /* special value to test for */
if ( (err != NULL) &&
(env->force ||
env->operation == Action_CopyMoving) )
{
err = get_access_to_file(filename, &prev_access);
if ( err ) prev_access = -1;
err = set_access_to_file(filename, prev_access & ~Attribute_Locked); /*
If it didn't work, cancel the error if its an ignorable
if ( err && (err->errnum & FileError_Mask) != ErrorNumber_NotFound ) error for this operation
return err; */
/* if ( err )
Retry deletion {
*/ /* JRS 28/1/92 test if access should be restored */
err = delete_node( filename ); if ( prev_access != -1 )
{
/*
Put the access back to where it was
*/
set_access_to_file( filename, prev_access);
} }
switch( err->errnum & FileError_Mask )
{
case ErrorNumber_Locked:
/*
If forcing delete failed due to locked file then something's
happening which the user should know about, so don't drop
through the 'cancel this error' code.
*/
if ( env->force )
break;
/*
Otherwise, just note that one file hasn't been deleted
due to a locked file and drop through to the 'it didn't
get deleted, and it was there, and we don't mind' case.
*/
env->locked_not_deleted++;
case ErrorNumber_DirectoryNotEmpty:
/*
Reach here if the file didn't get deleted and it was
there and we don't mind. If these conditions are satisfied
then we don't want to count this object as deleted.
*/
inhibit_progress = Yes;
err = NULL;
break;
case ErrorNumber_NotFound:
/*
This
entry point is used for the 'its already gone' situation,
in which case we fib to the user that it was the user which
caused the deletion (but it wasn't really; who cares -
the file's gone anyway).
*/
err = NULL;
deleted_next_node( env->test_search, filename );
break;
default:
break;
}
}
else
{
/* /*
If it didn't work, cancel the error if its an ignorable Tell the file listing stuff we've deleted the node
error for this operation
*/ */
if ( err ) deleted_next_node( env->test_search, filename );
{ }
/* JRS 28/1/92 test if access should be restored */
if ( prev_access != -1 )
{ /*
Put the access back to where it was
*/
set_access_to_file( filename, prev_access);
}
switch( err->errnum & FileError_Mask ) if ( env->operation != Action_CopyMoving )
{ overflowing_free( filename );
case ErrorNumber_Locked:
/*
If forcing delete failed due to locked file then something's
happening which the user should know about, so don't drop
through the 'cancel this error' code.
*/
if ( env->force )
break;
/* if ( err )
Otherwise, just note that one file hasn't been deleted return err;
due to a locked file and drop through to the 'it didn't
get deleted, and it was there, and we don't mind' case.
*/
env->locked_not_deleted++;
case ErrorNumber_DirectoryNotEmpty: /*
/* Only update progress bar if the file was actually deleted
Reach here if the file didn't get deleted and it was */
there and we don't mind. If these conditions are satisfied #ifdef USE_PROGRESS_BAR
then we don't want to count this object as deleted. add_progress(env, p, "Do_Attempt_Delete");
*/ #endif
inhibit_progress = Yes;
err = NULL;
break;
case ErrorNumber_NotFound: if ( env->operation != Action_CopyMoving )
/* {
This if ( !inhibit_progress )
entry point is used for the 'its already gone' situation,
in which case we fib to the user that it was the user which
caused the deletion (but it wasn't really; who cares -
the file's gone anyway).
*/
err = NULL;
deleted_next_node( env->test_search, filename );
break;
default:
break;
}
}
else
{ {
/* /*
Tell the file listing stuff we've deleted the node Keep the user informed of what's happening
*/ */
deleted_next_node( env->test_search, filename ); if ( objecttype_of_next_node( env->test_search ) != object_file )
{
more_top_progress( env, 1 );
}
else
{
more_bottom_progress( env, 1 );
}
} }
if ( env->operation != Action_CopyMoving ) env->action = Next_File;
overflowing_free( filename ); }
else
if ( err ) {
return err; /*
Update progress if it's a file we've just finished moving
if ( env->operation != Action_CopyMoving ) */
if ( finished_obj_was_file )
{ {
if ( !inhibit_progress ) more_bottom_progress( env, 1 );
{
/*
Keep the user informed of what's happening
*/
if ( objecttype_of_next_node( env->test_search ) != ObjectType_File )
{
more_top_progress( env, 1 );
}
else
{
more_bottom_progress( env, 1 );
}
}
env->action = Next_File;
} }
else
{
/*
Update progress if it's a file we've just finished moving
*/
if ( size_of_finished_file >= 0 )
{
more_bottom_progress( env, 1 );
}
set_bottom_info_field( env, next_file_to_be_written()); set_bottom_info_field( env, next_file_to_be_written());
env->action = Check_Empty_Writing; env->action = Check_Empty_Writing;
} }
return NULL; return NULL;
} }
static os_error *Do_Attempt_Set_Access( action_environment *env ) static os_error *Do_Attempt_Set_Access( action_environment *env )
{ {
os_error *err; os_error *err;
if ( objecttype_of_next_node( env->test_search ) != ObjectType_File ) if ( objecttype_of_next_node( env->test_search ) != object_file )
{ {
err = err =
set_access( set_access(
env, env,
((attributes_of_next_node( env->test_search) & (env->new_access >> 16) & 0xffff) | ((attributes_of_next_node( env->test_search) & (env->new_access >> 16) & 0xffff) |
(env->new_access & ~(env->new_access >> 16) & 0xffff)) & (env->new_access & ~(env->new_access >> 16) & 0xffff)) &
env->directory_access_setting_mask ); env->directory_access_setting_mask );
if ( err ) if ( err )
return err; return err;
more_top_progress( env, 1 );
}
else
{
err =
set_access(
env,
(attributes_of_next_node( env->test_search) & (env->new_access >> 16) & 0xffff) |
(env->new_access & ~(env->new_access >> 16) & 0xffff) );
more_top_progress( env, 1 ); if ( err )
} return err;
else
{
err =
set_access(
env,
(attributes_of_next_node( env->test_search) & (env->new_access >> 16) & 0xffff) |
(env->new_access & ~(env->new_access >> 16) & 0xffff) );
if ( err ) more_bottom_progress( env, 1 );
return err; }
more_bottom_progress( env, 1 ); #ifdef USE_PROGRESS_BAR
} add_progress(env, progress_of_next_node(env->test_search), "Do_Attempt_Set_Access");
#endif
env->action = Next_File; env->action = Next_File;
return NULL; return NULL;
} }
static os_error *Do_Attempt_Set_Type( action_environment *env ) static os_error *Do_Attempt_Set_Type( action_environment *env )
{ {
os_error *err; os_error *err;
char *filename; char *filename;
os_filestr fileplace; os_filestr fileplace;
if ( objecttype_of_next_node( env->test_search ) == ObjectType_Directory ) if ( objecttype_of_next_node( env->test_search ) == object_directory )
{ {
more_top_progress( env, 1 ); more_top_progress( env, 1 );
} }
else else
{ {
err = next_nodename( env->test_search, &filename ); err = next_nodename( env->test_search, &filename );
if ( err ) if ( err )
return err; return err;
fileplace.action = OSFile_SetType;
fileplace.name = filename;
fileplace.loadaddr = env->new_type;
fileplace.action = 0x12; /* set file type */ err = os_file( &fileplace );
fileplace.name = filename;
fileplace.loadaddr = env->new_type;
err = os_file( &fileplace ); overflowing_free( filename );
overflowing_free( filename ); if ( err )
return err;
if ( err ) more_bottom_progress( env, 1 );
return err;
more_bottom_progress( env, 1 ); }
} #ifdef USE_PROGRESS_BAR
add_progress(env, progress_of_next_node(env->test_search), "Do_Attempt_Set_Type");
#endif
env->action = Next_File; env->action = Next_File;
return NULL; return NULL;
} }
static os_error *Do_Attempt_Stamp( action_environment *env ) static os_error *Do_Attempt_Stamp( action_environment *env )
{ {
os_error *err; os_error *err;
err = stamp( env ); err = stamp( env );
/* #ifdef USE_PROGRESS_BAR
Filter out F. S. Error 46 as this is the error generated by file add_progress(env, progress_of_next_node(env->test_search), "Do_Attempt_Stamp");
servers which can't stamp directories #endif
*/
if ( err && (err->errnum & FileError_Mask) != ErrorNumber_FSError46 )
return err;
err = NULL; /*
Filter out F. S. Error 46 as this is the error generated by file
servers which can't stamp directories
*/
if ( err && (err->errnum & FileError_Mask) != ErrorNumber_FSError46 )
return err;
if ( objecttype_of_next_node( env->test_search ) == ObjectType_File ) err = NULL;
more_bottom_progress( env, 1 );
else
more_top_progress( env, 1 );
env->action = Next_File; if ( objecttype_of_next_node( env->test_search ) == object_file )
more_bottom_progress( env, 1 );
else
more_top_progress( env, 1 );
return NULL; env->action = Next_File;
return NULL;
} }
/* /*
--- Activity processor for null events --- --- Activity processor for null events ---
*/ */
static void null_event_activity( action_environment *env ) static void null_event_activity( action_environment *env )
{ {
os_error *err = NULL; os_error *err = NULL;
char info_buffer[ Info_Field_Length + 15 ]; clock_t end_time;
int end_time;
end_time = clock() + doings_time; end_time = clock() + doings_time;
hide_faster_stuff( env ); hide_faster_stuff( env );
do do
{
if ( env->action == Abort_Operation )
{ {
if ( env->action == Abort_Operation ) abort_operation( env );
{ }
abort_operation( env );
}
if ( last_top_info_field != env->current_info )
{
if ( env->in_error )
{
#ifdef REDERROR
wimp_set_icon_state( dbox_syshandle( env->status_box ), Top_Info_Field, 0xc000000, 0 );
wimp_set_icon_state( dbox_syshandle( env->status_box ), Bottom_Info_Field, 0xc000000, 0 );
#endif
env->in_error = No;
switch_box_from_error( env );
}
dbox_setfield( env->status_box, Top_Info_Field, env->current_info );
last_top_info_field = env->current_info;
}
switch( env->action ) if ( last_top_info_field != env->current_info )
{ {
case Next_File: if ( env->in_error )
err = Do_Next_File( env ); {
break; #ifdef USE_RED_ERROR
wimp_set_icon_state( dbox_syshandle( env->status_box ), Top_Info_Field, 0xc000000, 0 );
wimp_set_icon_state( dbox_syshandle( env->status_box ), Bottom_Info_Field, 0xc000000, 0 );
#endif
env->in_error = No;
switch_box_from_error( env );
}
set_top_info_field_raw( env, env->current_info );
}
case Test_Add_To_Read_List: switch( env->action )
err = Do_Test_Add_To_Read_List( env ); {
break; case Next_File:
err = Do_Next_File( env );
break;
case Add_To_Read_List: case Test_Add_To_Read_List:
err = Do_Add_To_Read_List( env ); err = Do_Test_Add_To_Read_List( env );
break; break;
case Check_Full_Reading: case Add_To_Read_List:
err = Do_Check_Full_Reading( env ); err = Do_Add_To_Read_List( env );
break; break;
case Check_Empty_Writing: case Check_Full_Reading:
err = Do_Check_Empty_Writing( env ); err = Do_Check_Full_Reading( env );
break; break;
case Attempt_1st_Rename: case Check_Empty_Writing:
err = Do_Attempt_Rename( env, 1 ); err = Do_Check_Empty_Writing( env );
break; break;
case Attempt_Unlock: case Attempt_1st_Rename:
err = Do_Attempt_Unlock( env ); err = Do_Attempt_Rename( env, 1 );
break; break;
case Attempt_2nd_Rename: case Attempt_Unlock:
err = Do_Attempt_Rename( env, 2 ); err = Do_Attempt_Unlock( env );
break; break;
case Attempt_Relock: case Attempt_2nd_Rename:
err = Do_Attempt_Relock( env ); err = Do_Attempt_Rename( env, 2 );
break; break;
case Convert_To_CopyMove: case Attempt_Relock:
err = Do_Convert_To_CopyMove( env, No ); err = Do_Attempt_Relock( env );
break; break;
case Convert_To_CopyMove_After_Unlock: case Convert_To_CopyMove:
err = Do_Convert_To_CopyMove( env, Yes ); err = Do_Convert_To_CopyMove( env, No );
break; break;
case Attempt_Delete: case Convert_To_CopyMove_After_Unlock:
err = Do_Attempt_Delete( env ); err = Do_Convert_To_CopyMove( env, Yes );
break; break;
case Attempt_Set_Access: case Attempt_Delete:
err = Do_Attempt_Set_Access( env ); err = Do_Attempt_Delete( env );
break; break;
case Attempt_Set_Type: case Attempt_Set_Access:
err = Do_Attempt_Set_Type( env ); err = Do_Attempt_Set_Access( env );
break; break;
case Attempt_Stamp: case Attempt_Set_Type:
err = Do_Attempt_Stamp( env ); err = Do_Attempt_Set_Type( env );
break; break;
default: case Attempt_Stamp:
break; err = Do_Attempt_Stamp( env );
} break;
default:
break;
} }
/*
While there is not error and
we havn't run out of time and
we are accepting NULL events
*/
while ( !err &&
clock() < end_time &&
( event_getmask() & wimp_EMNULL ) == 0 );
if ( err ) /*
While there is not error and
we havn't run out of time and
we are accepting NULL events
*/
} while ( !err &&
clock() < end_time &&
( event_getmask() & wimp_EMNULL ) == 0 );
#ifdef USE_PROGRESS_BAR
update_progress_bar(env);
#endif
/*
Update the various fields in the dialogue box, if the flags are set
*/
if (UpdatePath)
{
UpdatePath = 0;
dbox_setfield( env->status_box, Bottom_Info_Path, PathString );
}
if (UpdateTop)
{
UpdateTop = 0;
if ( !env->faster || show_when_faster[ env->operation ][ 0 ] )
{
dbox_setlongnumeric( env->status_box, Top_Progress_Field, env->top_progress );
}
}
if (UpdateBottom)
{
UpdateBottom = 0;
if ( !env->faster || show_when_faster[ env->operation ][ 1 ] )
{
dbox_setlongnumeric( env->status_box, Bottom_Progress_Field, env->bottom_progress);
}
}
if ( err )
{
if ( err->errnum == 0 )
{ {
if ( err->errnum == 0 ) /*
Internally generated error - this is fatal
*/
wimpt_noerr( err );
}
else
{
/*
Externally generated error - give the user a chance
to correct it.
*/
if ( ( env->operation == Action_Copying ||
env->operation == Action_CopyMoving ||
env->operation == Action_CopyLocal ) &&
( env->action == Check_Full_Reading ||
env->action == Check_Empty_Writing ) )
{
/*
Read/Write during a copy or copy move
*/
switch_buttons( env, &restart_button );
}
else
{
/*
Attempted activity normal for operation, but failed
*/
switch_buttons( env, &norestart_button );
}
/*
Construct error indicator
*/
if ( ( err->errnum & FileError_Mask ) == ErrorNumber_DiscFull )
{
set_top_info_field_with_current_info(env, "87a", "87");
if ( env->disc_full_already )
{ {
/* /*
Internally generated error - this is fatal Cancel the report of a second or subsequent disc full error
*/ */
wimpt_noerr( err ); err = NULL;
} }
else else
{ {
/* env->disc_full_already = Yes;
Externally generated error - give the user a chance switch_box_to_error( env, err );
to correct it.
*/
if ( ( env->operation == Action_Copying ||
env->operation == Action_CopyMoving ||
env->operation == Action_CopyLocal ) &&
( env->action == Check_Full_Reading ||
env->action == Check_Empty_Writing ) )
{
/*
Read/Write during a copy or copy move
*/
switch_buttons( env, &restart_button );
}
else
{
/*
Attempted activity normal for operation, but failed
*/
switch_buttons( env, &norestart_button );
}
/*
Construct error indicator
*/
if ( ( err->errnum & FileError_Mask ) == ErrorNumber_DiscFull )
{
strcpy(info_buffer, "87a");
strcat(info_buffer, env->current_info_token);
sprintf(info_buffer, msgs_lookup(info_buffer), tolower(env->current_info[0]), &env->current_info[1]);
if ( env->disc_full_already )
{
/*
Cancel the report of a second or subsequent disc full error
*/
err = NULL;
}
else
{
env->disc_full_already = Yes;
switch_box_to_error( env, err );
}
}
else
{
strcpy(info_buffer, "88a");
strcat(info_buffer, env->current_info_token);
sprintf(info_buffer, msgs_lookup(info_buffer), tolower(env->current_info[0]), &env->current_info[1]);
switch_box_to_error( env, err );
}
dbox_setfield( env->status_box, Top_Info_Field, info_buffer );
last_top_info_field = info_buffer;
/*
Set the info field text to red (assuming it was black)
*/
env->in_error = Yes;
#ifdef REDERROR
wimp_set_icon_state( dbox_syshandle( env->status_box ), Top_Info_Field, 0xc000000, 0 );
wimp_set_icon_state( dbox_syshandle( env->status_box ), Bottom_Info_Field, 0xc000000, 0 );
#endif
} }
}
else
{
set_top_info_field_with_current_info(env, "88a", "88");
switch_box_to_error( env, err );
}
/*
Set the info field text to red (assuming it was black)
*/
env->in_error = Yes;
#ifdef USE_RED_ERROR
wimp_set_icon_state( dbox_syshandle( env->status_box ), Top_Info_Field, 0xc000000, 0 );
wimp_set_icon_state( dbox_syshandle( env->status_box ), Bottom_Info_Field, 0xc000000, 0 );
#endif
} }
}
} }
/* /*
--- NULL event handler for status box. --- --- NULL event handler for status box. ---
*/ */
BOOL idle_event_handler(dbox db, void *event, void *handle) BOOL idle_event_handler(dbox db, void *event, void *handle)
{ {
BOOL handled = No; BOOL handled = No;
db = db; /* keep the compiler quiet */ IGNORE(db);
switch( ((wimp_eventstr *)event)->e ) switch( ((wimp_eventstr *)event)->e )
{
case wimp_ENULL:
{ {
case wimp_ENULL: action_environment *env = handle;
/*
Process delayed box showing and hiding
*/
if ( env->boxchange_direction != 0 &&
clock() >= env->time_to_boxchange )
{
if ( env->boxchange_direction > 0 )
{ {
action_environment *env = handle; dbox_showstatic( env->status_box );
}
/* else
Process delayed box showing and hiding {
*/ dbox_hide( env->status_box );
if ( env->boxchange_direction != 0 &&
clock() >= env->time_to_boxchange )
{
if ( env->boxchange_direction > 0 )
{
dbox_showstatic( env->status_box );
}
else
{
dbox_hide( env->status_box );
}
env->boxchange_direction = 0;
}
null_event_activity( env );
} }
handled = Yes;
break;
case wimp_ESEND: env->boxchange_direction = 0;
case wimp_ESENDWANTACK: }
handled = message_event_handler( event, handle );
break;
default: null_event_activity( env );
break;
} }
handled = Yes;
break;
case wimp_ESEND:
case wimp_ESENDWANTACK:
handled = message_event_handler( event, handle );
break;
default:
break;
}
return handled; return handled;
} }
/* Fixed stack size !!! /* Fixed stack size !!!
* 3.5k is the max required. * 3.5k is the max required.
* 2k is a bodge safety factor. * 2k is a bodge safety factor.
...@@ -2429,17 +2663,17 @@ extern int disable_stack_extension; ...@@ -2429,17 +2663,17 @@ extern int disable_stack_extension;
*/ */
int main( int argc, char *argv[] ) int main( int argc, char *argv[] )
{ {
disable_stack_extension = 1; disable_stack_extension = 1;
wimpt_install_signal_handlers(); wimpt_install_signal_handlers();
wimpt_noerr( initialise( &env, argc, argv )); wimpt_noerr( initialise( &env, argc, argv ));
while (TRUE) while (TRUE)
{ {
event_process(); event_process();
} }
return 0; return 0;
} }
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#include <limits.h> #include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <inttypes.h> #include <stdint.h>
#include <locale.h> #include <locale.h>
#include "dbox.h" #include "dbox.h"
...@@ -23,10 +23,8 @@ ...@@ -23,10 +23,8 @@
#include "Options.h" #include "Options.h"
#include "dboxlong.h" #include "dboxlong.h"
#ifdef USE_LONG_LONG
#ifdef USE_COMMAS #ifdef USE_COMMAS
static void cvtlong(char *out, uintmax_t num) static void cvtlong(char *out, uint64_t num)
{ {
struct lconv *l = localeconv(); struct lconv *l = localeconv();
char buffer[128]; char buffer[128];
...@@ -64,7 +62,7 @@ static void cvtlong(char *out, uintmax_t num) ...@@ -64,7 +62,7 @@ static void cvtlong(char *out, uintmax_t num)
#define cvtlong(buf, n) snprintf(buf, "%ju", n) #define cvtlong(buf, n) snprintf(buf, "%ju", n)
#endif #endif
void dbox_setlongnumeric(dbox d, dbox_field f, uintmax_t n) void dbox_setlongnumeric(dbox d, dbox_field f, uint64_t n)
{ {
char buf[128]; char buf[128];
...@@ -72,5 +70,3 @@ void dbox_setlongnumeric(dbox d, dbox_field f, uintmax_t n) ...@@ -72,5 +70,3 @@ void dbox_setlongnumeric(dbox d, dbox_field f, uintmax_t n)
dbox_setfield(d, f, buf); dbox_setfield(d, f, buf);
} }
#endif
...@@ -31,52 +31,69 @@ Revision History: ...@@ -31,52 +31,69 @@ Revision History:
*/ */
#if 0 #if 0
#define debuglist #define debuglist(k) dprintf k
#else
#define debuglist(k) /* Disabled */
#endif #endif
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdint.h>
#include "Interface/HighFSI.h"
#ifndef __os_h
#include "os.h" #include "os.h"
#endif
#include "Options.h"
#include "malloc+.h" #include "malloc+.h"
#include "listfiles.h" #include "listfiles.h"
#include "allerrs.h" #include "allerrs.h"
#include "debug.h" #include "debug.h"
#include "memmanage.h"
#define Yes 1
#define No 0 #define No 0
#define Yes (!No)
#define Directory_Buffer_Size 20 #define Directory_Buffer_Size 20
#define Temp_DirBuffer_Size 640 #define Temp_DirBuffer_Size 640
#define Directory_File_Type 2
typedef struct typedef struct
{ {
int load_address; int load_address;
int execution_address; int execution_address;
int length; uint32_t length;
int attributes; int attributes;
int object_type; int object_type;
char *object_name; char *object_name;
#ifdef USE_PROGRESS_BAR
void *chain_ref;
#endif
} directory_buffer_entry; } directory_buffer_entry;
typedef struct Search_Nest_Level typedef struct Search_Nest_Level
{ {
struct Search_Nest_Level *next_search_nest_level; struct Search_Nest_Level *next_search_nest_level;
int offset_to_next_item; int offset_to_next_item;
int entries_in_buffer; int entries_in_buffer;
int next_entry_to_return; int next_entry_to_return;
directory_buffer_entry directory_buffer[ Directory_Buffer_Size ]; directory_buffer_entry directory_buffer[ Directory_Buffer_Size ];
#ifdef USE_PROGRESS_BAR
BOOL counted;
uint32_t total_entries;
int total_progress;
int progress_per_object;
#endif
} search_nest_level; } search_nest_level;
typedef struct File_Selection typedef struct File_Selection
{ {
struct File_Selection *next_file; struct File_Selection *next_file;
char *selection_name; char *selection_name;
} file_selection; } file_selection;
/* /*
...@@ -92,21 +109,77 @@ typedef enum ...@@ -92,21 +109,77 @@ typedef enum
typedef struct search_context typedef struct search_context
{ {
search_nest_level *nested_filenames; search_nest_level *nested_filenames;
char *directory; char *directory;
file_selection *selection; file_selection *selection;
file_selection **last_selections_link; file_selection **last_selections_link;
next_leaf_state action; next_leaf_state action;
unsigned int selections_size; uint32_t selections_size;
unsigned int selections_reload; int selections_loadaddr;
unsigned int selections_execute; int selections_execaddr;
unsigned int selections_attributes; int selections_attributes;
unsigned int selections_objecttype; int selections_objecttype;
unsigned int recursive:1; int recursive:1;
unsigned int directories_first:1; int directories_first:1;
unsigned int directories_last:1; int directories_last:1;
unsigned int partitions_as_directories:1; int partitions_as_directories:1;
} search_context;
#ifdef USE_PROGRESS_BAR
uint32_t total_entries;
int total_progress;
int progress_per_object;
void *chain_ref;
#endif
} search_context;
#ifdef USE_PROGRESS_BAR
static uint32_t count_objects_in_dir( char *dir )
{
os_error *err;
os_gbpbstr request;
char buff[Temp_DirBuffer_Size];
int context = 0, c, num = 0;
uint32_t total = 0;
while (context != -1)
{
request.action = OSGBPB_ReadDirEntries;
request.file_handle = (int)dir;
request.data_addr = buff;
request.number = 256;
request.seq_point = context;
request.buf_len = Temp_DirBuffer_Size;
request.wild_fld = 0;
err = os_gbpb( &request );
num = request.number;
c = request.seq_point;
if (err == NULL)
{
if (c == context)
{
/*
Broken archives cause context to never be updated ... not sure why
the SWI does not return an error.
*/
debuglist(( "count_objects_in_dir: aborting\n" ));
return 0;
}
context = c;
total += num;
}
else
{
debuglist(( "count_objects_in_dir: %s\n", e->errmess ));
return 0;
}
}
return total;
}
#endif
/* /*
This initialises an empty search context. This initialises an empty search context.
...@@ -116,89 +189,96 @@ typedef struct search_context ...@@ -116,89 +189,96 @@ typedef struct search_context
*/ */
os_error *create_search_context( search_handle *handle ) os_error *create_search_context( search_handle *handle )
{ {
search_context *new_context; search_context *new_context;
if ( ( new_context = overflowing_malloc( sizeof( search_context ))) != NULL )
{
*handle = (search_handle)new_context;
new_context->directory = NULL;
new_context->nested_filenames = NULL;
new_context->selection = NULL;
new_context->last_selections_link = &new_context->selection;
new_context->recursive = Yes;
new_context->directories_first = No;
new_context->directories_last = No;
new_context->partitions_as_directories = Yes;
new_context->action = Process_Node;
#ifdef USE_PROGRESS_BAR
new_context->total_entries = 0;
new_context->total_progress = INT32_MAX;
new_context->progress_per_object = 0;
new_context->chain_ref = NULL;
#endif
if ( ( new_context = overflowing_malloc( sizeof( search_context ))) != NULL ) return NULL;
{ }
*handle = (search_handle)new_context; else
new_context->directory = NULL; {
new_context->nested_filenames = NULL; return error( mb_malloc_failed );
new_context->selection = NULL; }
new_context->last_selections_link = &new_context->selection;
new_context->recursive = Yes;
new_context->directories_first = No;
new_context->directories_last = No;
new_context->partitions_as_directories = Yes;
new_context->action = Process_Node;
return NULL;
}
else
{
return error( mb_malloc_failed );
}
} }
static int is_a_directory( search_handle handle, int objecttype ) static int is_a_directory( search_handle handle, int objecttype )
{ {
if ( objecttype == ObjectType_Directory || if ( objecttype == object_directory ||
(objecttype == (ObjectType_Directory | ObjectType_File) && (objecttype == (object_directory | object_file) &&
handle->partitions_as_directories) ) handle->partitions_as_directories) )
{ {
return Yes; return Yes;
} }
else else
{ {
return No; return No;
} }
} }
/* /*
Sets whether the search is recursive or not Sets whether the search is recursive or not
*/ */
extern void recurse_search_context( search_handle handle, int recursive ) void recurse_search_context( search_handle handle, BOOL recursive )
{ {
/* /*
Make sure when changing to recursive that the children of this Make sure when changing to recursive that the children of this
directory get returned directory get returned
*/ */
if ( !handle->recursive && if ( !handle->recursive &&
recursive && recursive &&
is_a_directory( handle, objecttype_of_next_node( handle )) && is_a_directory( handle, objecttype_of_next_node( handle )) &&
handle->action == Next_Leaf ) handle->action == Next_Leaf )
{ {
handle->action = Nest_Into_Directory; handle->action = Nest_Into_Directory;
} }
handle->recursive = recursive != No; handle->recursive = recursive != No;
} }
/* /*
Sets whether directories should be returned before their contents. Sets whether directories should be returned before their contents.
This is relevant only when recursing. This is relevant only when recursing.
*/ */
extern void return_directories_first( search_handle handle, int directories_first ) void return_directories_first( search_handle handle, BOOL directories_first )
{ {
((search_context *)handle)->directories_first = directories_first != No; ((search_context *)handle)->directories_first = directories_first != No;
} }
/* /*
Sets whether directories should be returned after their contents. Sets whether directories should be returned after their contents.
This is relevant only when recursing. This is relevant only when recursing.
*/ */
extern void return_directories_last( search_handle handle, int directories_last ) void return_directories_last( search_handle handle, BOOL directories_last )
{ {
handle->directories_last = directories_last != No; handle->directories_last = directories_last != No;
} }
/* /*
Sets whether partitions should be treated the same as directories or not. Sets whether partitions should be treated the same as directories or not.
This is relevant only when recursing. This is relevant only when recursing.
*/ */
extern void treat_partitions_as_directories( search_handle handle, int partitions_are_directories ) void treat_partitions_as_directories( search_handle handle, BOOL partitions_are_directories )
{ {
handle->partitions_as_directories = partitions_are_directories; handle->partitions_as_directories = partitions_are_directories;
} }
/* /*
...@@ -210,18 +290,18 @@ os_error *set_directory( search_handle handle, char *directory ) ...@@ -210,18 +290,18 @@ os_error *set_directory( search_handle handle, char *directory )
if ( context->directory ) if ( context->directory )
{ {
overflowing_free( context->directory ); overflowing_free( context->directory );
} }
if ( ( context->directory = overflowing_malloc( strlen( directory ) + 1 )) != NULL ) if ( ( context->directory = overflowing_malloc( strlen( directory ) + 1 )) != NULL )
{ {
strcpy( context->directory, directory ); strcpy( context->directory, directory );
return NULL; return NULL;
} }
else else
{ {
return error( mb_malloc_failed ); return error( mb_malloc_failed );
} }
} }
...@@ -244,18 +324,18 @@ void clear_selection( search_handle handle ) ...@@ -244,18 +324,18 @@ void clear_selection( search_handle handle )
file_selection *this_selection; file_selection *this_selection;
/* /*
Free the chain of selections Free the chain of selections
*/ */
for ( this_selection = context->selection; for ( this_selection = context->selection;
this_selection != NULL; this_selection != NULL;
this_selection = next_selection ) this_selection = next_selection )
{ {
next_selection = this_selection->next_file; next_selection = this_selection->next_file;
free_selection( this_selection ); free_selection( this_selection );
} }
/* /*
close off the head of the list close off the head of the list
*/ */
context->selection = NULL; context->selection = NULL;
context->last_selections_link = &context->selection; context->last_selections_link = &context->selection;
...@@ -271,43 +351,49 @@ os_error *add_selection( search_handle handle, char *file_name, int wordlen ) ...@@ -271,43 +351,49 @@ os_error *add_selection( search_handle handle, char *file_name, int wordlen )
search_context *context = (search_context *)handle; search_context *context = (search_context *)handle;
/* /*
These two if statements allocate the new selection structure and These two if statements allocate the new selection structure and
then some space for the file name. The mallocs are checked to then some space for the file name. The mallocs are checked to
work, and if they don't everything is tidied up and an error work, and if they don't everything is tidied up and an error
is returned. is returned.
*/ */
new_selection = overflowing_malloc( sizeof( file_selection )); new_selection = overflowing_malloc( sizeof( file_selection ));
if ( new_selection != NULL ) if ( new_selection != NULL )
{ {
new_selection->selection_name = overflowing_malloc( wordlen + 1 ); new_selection->selection_name = overflowing_malloc( wordlen + 1 );
if ( new_selection->selection_name != NULL ) if ( new_selection->selection_name != NULL )
{ {
/* /*
Everything allocated OK, so copy the string and Everything allocated OK, so copy the string and
link the new selection onto the end of the list. link the new selection onto the end of the list.
*/ */
*context->last_selections_link = new_selection; *context->last_selections_link = new_selection;
strncpy( new_selection->selection_name, file_name, wordlen ); strncpy( new_selection->selection_name, file_name, wordlen );
new_selection->selection_name[ wordlen ] = '\0'; new_selection->selection_name[ wordlen ] = '\0';
context->last_selections_link = &new_selection->next_file; context->last_selections_link = &new_selection->next_file;
new_selection->next_file = NULL; new_selection->next_file = NULL;
return NULL; debuglist(( "context: %x new selection: %s\n", context, new_selection->selection_name ));
} #ifdef USE_PROGRESS_BAR
else context->total_entries++;
{ context->progress_per_object = context->total_progress / context->total_entries;
/* #endif
No room for selection name.
Free up the selection structure and tidy up the ends return NULL;
*/ }
overflowing_free( new_selection ); else
{
return error( mb_malloc_failed ); /*
} No room for selection name.
Free up the selection structure and tidy up the ends
*/
overflowing_free( new_selection );
return error( mb_malloc_failed );
}
} }
else else
{ {
return error( mb_malloc_failed ); return error( mb_malloc_failed );
} }
} }
...@@ -324,19 +410,19 @@ void dispose_search_context( search_handle handle ) ...@@ -324,19 +410,19 @@ void dispose_search_context( search_handle handle )
int i; int i;
/* /*
Free the search nest level chain Free the search nest level chain
*/ */
rover = context->nested_filenames; rover = context->nested_filenames;
while( rover != NULL ) while( rover != NULL )
{ {
temp_rover = rover; temp_rover = rover;
rover = rover->next_search_nest_level; rover = rover->next_search_nest_level;
for ( i = 0; i < Directory_Buffer_Size; i++ ) for ( i = 0; i < Directory_Buffer_Size; i++ )
{ {
overflowing_free( temp_rover->directory_buffer[ i ].object_name ); overflowing_free( temp_rover->directory_buffer[ i ].object_name );
} }
overflowing_free( temp_rover ); overflowing_free( temp_rover );
} }
clear_selection( handle ); clear_selection( handle );
...@@ -352,29 +438,29 @@ static int size_of_next_filename( search_context *context, search_nest_level *ne ...@@ -352,29 +438,29 @@ static int size_of_next_filename( search_context *context, search_nest_level *ne
int returned_length = 0; int returned_length = 0;
if ( context->directory && if ( context->directory &&
context->selection && context->selection &&
context->selection->selection_name ) context->selection->selection_name )
{ {
returned_length = strlen( context->directory ); returned_length = strlen( context->directory );
/* /*
Only Add one in if there's going to be a . in between dir and selection Only Add one in if there's going to be a . in between dir and selection
*/ */
if ( returned_length ) if ( returned_length )
returned_length++; returned_length++;
returned_length += strlen( context->selection->selection_name ); returned_length += strlen( context->selection->selection_name );
if ( context->recursive ) if ( context->recursive )
{ {
while ( nest_level != NULL ) while ( nest_level != NULL )
{ {
returned_length += 1 + strlen( nest_level-> returned_length += 1 + strlen( nest_level->
directory_buffer[ nest_level->next_entry_to_return ]. directory_buffer[ nest_level->next_entry_to_return ].
object_name ); object_name );
nest_level = nest_level->next_search_nest_level; nest_level = nest_level->next_search_nest_level;
} }
} }
} }
return returned_length; return returned_length;
...@@ -396,44 +482,44 @@ static os_error *next_filename( search_context *context, search_nest_level *nest ...@@ -396,44 +482,44 @@ static os_error *next_filename( search_context *context, search_nest_level *nest
if ( next_filename_size > 0 ) if ( next_filename_size > 0 )
{ {
buffer = overflowing_malloc( next_filename_size + 1 ); buffer = overflowing_malloc( next_filename_size + 1 );
if ( buffer == NULL ) if ( buffer == NULL )
{ {
return error( mb_malloc_failed ); return error( mb_malloc_failed );
} }
} }
if ( buffer != NULL ) if ( buffer != NULL )
{ {
if ( context->directory[0] ) if ( context->directory[0] )
{ {
sprintf( buffer, "%s.%s", context->directory, context->selection->selection_name ); sprintf( buffer, "%s.%s", context->directory, context->selection->selection_name );
} }
else else
{ {
sprintf( buffer, "%s", context->selection->selection_name ); sprintf( buffer, "%s", context->selection->selection_name );
} }
rover = buffer + next_filename_size; rover = buffer + next_filename_size;
*rover = '\0'; *rover = '\0';
while ( nest_level != NULL ) while ( nest_level != NULL )
{ {
part_length = strlen( nest_level-> part_length = strlen( nest_level->
directory_buffer[ nest_level->next_entry_to_return ]. directory_buffer[ nest_level->next_entry_to_return ].
object_name ); object_name );
rover -= part_length + 1; rover -= part_length + 1;
rover[0] = '.'; rover[0] = '.';
memcpy( &rover[1], nest_level-> memcpy( &rover[1], nest_level->
directory_buffer[ nest_level->next_entry_to_return ]. directory_buffer[ nest_level->next_entry_to_return ].
object_name, part_length ); object_name, part_length );
nest_level = nest_level->next_search_nest_level; nest_level = nest_level->next_search_nest_level;
} }
} }
*hook_location = buffer; *hook_location = buffer;
...@@ -449,30 +535,30 @@ os_error *next_nodename( search_handle handle, char **hook_location ) ...@@ -449,30 +535,30 @@ os_error *next_nodename( search_handle handle, char **hook_location )
os_error *selection_summary( search_handle handle, char **summary ) os_error *selection_summary( search_handle handle, char **summary )
{ {
search_context *context = (search_context *)handle; search_context *context = (search_context *)handle;
char *cont; char *cont;
if ( context->selection == NULL ) if ( context->selection == NULL )
{ {
cont = msgs_lookup("93"); cont = msgs_lookup("93"); /* 'nothing' */
} }
else if ( context->selection->next_file == NULL ) else if ( context->selection->next_file == NULL )
{ {
cont = context->selection->selection_name; cont = context->selection->selection_name;
} }
else else
{ {
cont = msgs_lookup("92"); cont = msgs_lookup("92"); /* 'many' */
} }
*summary = overflowing_malloc( strlen( context->directory ) + 1 + strlen( cont ) + 1 ); *summary = overflowing_malloc( strlen( context->directory ) + 1 + strlen( cont ) + 1 );
if ( *summary == NULL ) if ( *summary == NULL )
return error( mb_malloc_failed ); return error( mb_malloc_failed );
sprintf( *summary, "%s.%s", context->directory, cont ); sprintf( *summary, "%s.%s", context->directory, cont );
return NULL; return NULL;
} }
/* /*
...@@ -490,93 +576,93 @@ static char *first_position_not_matched( search_handle handle, search_nest_level ...@@ -490,93 +576,93 @@ static char *first_position_not_matched( search_handle handle, search_nest_level
if ( nl == NULL ) if ( nl == NULL )
{ {
matched_position = mstring; matched_position = mstring;
dl = strlen( handle->directory ); dl = strlen( handle->directory );
if ( strncmp( handle->directory, matched_position, dl ) != 0 ) if ( strncmp( handle->directory, matched_position, dl ) != 0 )
return NULL; return NULL;
matched_position += dl; matched_position += dl;
if ( *matched_position != '.' ) if ( *matched_position != '.' )
return NULL; return NULL;
matched_position += 1; matched_position += 1;
sl = strlen( handle->selection->selection_name ); sl = strlen( handle->selection->selection_name );
if ( strncmp( handle->selection->selection_name, matched_position, sl ) != 0 ) if ( strncmp( handle->selection->selection_name, matched_position, sl ) != 0 )
return NULL; return NULL;
matched_position += sl; matched_position += sl;
return matched_position; return matched_position;
} }
else else
{ {
matched_position = first_position_not_matched( handle, nl->next_search_nest_level, mstring, matched_position = first_position_not_matched( handle, nl->next_search_nest_level, mstring,
deepest_match, shallowest_non_match ); deepest_match, shallowest_non_match );
if ( matched_position == NULL ) if ( matched_position == NULL )
return NULL; return NULL;
ms = nl->directory_buffer[ nl->next_entry_to_return ].object_name; ms = nl->directory_buffer[ nl->next_entry_to_return ].object_name;
sl = strlen( ms ); sl = strlen( ms );
if ( *matched_position == '.' && if ( *matched_position == '.' &&
strncmp( matched_position + 1, ms, sl ) == 0 ) strncmp( matched_position + 1, ms, sl ) == 0 )
{ {
matched_position += 1 + sl; matched_position += 1 + sl;
*deepest_match = nl; *deepest_match = nl;
} }
else else
{ {
if ( nl->next_search_nest_level == *deepest_match ) if ( nl->next_search_nest_level == *deepest_match )
{ {
*shallowest_non_match = nl; *shallowest_non_match = nl;
} }
} }
return matched_position; return matched_position;
} }
} }
/* /*
Informs that next node has been deleted Informs that next node has been deleted
*/ */
void deleted_next_node( search_handle handle, char *deleted_node ) void deleted_next_node( search_handle handle, char *deleted_node )
{ {
if ( handle->nested_filenames && handle->selection ) if ( handle->nested_filenames && handle->selection )
{ {
char *matched_position; char *matched_position;
search_nest_level *deepest_match = NULL; search_nest_level *deepest_match = NULL;
search_nest_level *shallowest_non_match = NULL; search_nest_level *shallowest_non_match = NULL;
matched_position = first_position_not_matched( handle, handle->nested_filenames, deleted_node, &deepest_match, &shallowest_non_match ); matched_position = first_position_not_matched( handle, handle->nested_filenames, deleted_node, &deepest_match, &shallowest_non_match );
if ( matched_position != NULL ) if ( matched_position != NULL )
{ {
/* /*
Deleted node is before something in shallowest non-match Deleted node is before something in shallowest non-match
*/ */
if ( matched_position == strrchr( deleted_node, '.' ) && if ( matched_position == strrchr( deleted_node, '.' ) &&
shallowest_non_match != NULL ) shallowest_non_match != NULL )
{ {
shallowest_non_match->offset_to_next_item--; shallowest_non_match->offset_to_next_item--;
} }
/* /*
Deleted is current node or a parent of it (gulp!) Deleted is current node or a parent of it (gulp!)
*/ */
if ( *matched_position == '\0' && if ( *matched_position == '\0' &&
deepest_match != NULL ) deepest_match != NULL )
{ {
deepest_match->offset_to_next_item--; deepest_match->offset_to_next_item--;
} }
}
} }
}
} }
/* /*
...@@ -585,501 +671,682 @@ void deleted_next_node( search_handle handle, char *deleted_node ) ...@@ -585,501 +671,682 @@ void deleted_next_node( search_handle handle, char *deleted_node )
*/ */
void read_next_node_parameters( search_handle handle ) void read_next_node_parameters( search_handle handle )
{ {
os_filestr fileplace; os_filestr fileplace;
char *filename; char *filename;
os_error *err; os_error *err;
err = next_nodename( handle, &filename ); err = next_nodename( handle, &filename );
if ( err ) if ( err )
return; return;
fileplace.action = 5; /* read catalogue information */ fileplace.action = OSFile_ReadInfo;
fileplace.name = filename; fileplace.name = filename;
err = os_file( &fileplace ); err = os_file( &fileplace );
if ( err ) if ( err )
return; return;
handle->selections_size = fileplace.start; handle->selections_size = fileplace.start;
handle->selections_reload = fileplace.loadaddr; handle->selections_loadaddr = fileplace.loadaddr;
handle->selections_execute = fileplace.execaddr; handle->selections_execaddr = fileplace.execaddr;
handle->selections_attributes = fileplace.end; handle->selections_attributes = fileplace.end;
} }
typedef enum { the_size, the_load_address, the_execute_address, the_attributes, the_type, the_name } which_thing; typedef enum {
the_size, the_load_address, the_execute_address, the_attributes, the_type, the_name
#ifdef USE_PROGRESS_BAR
, the_progress, the_ref_ptr
#endif
} which_thing;
/* /*
Returns one of the values associated with the next node. Returns one of the values associated with the next node.
If the node doesn't exist the value not_found is returned. If the node doesn't exist the value not_found is returned.
*/ */
static unsigned int thing_of_next_node( search_handle handle, which_thing thing, int not_found ) static int thing_of_next_node( search_handle handle, which_thing thing, int not_found )
{ {
search_context *context = (search_context *)handle; search_context *context = (search_context *)handle;
search_nest_level *nf; search_nest_level *nf;
if ( context->selection ) if ( context->selection )
{
if ( (nf = context->nested_filenames) == NULL )
{ {
if ( (nf = context->nested_filenames) == NULL ) switch( thing )
{
case the_size:
return (int) context->selections_size;
case the_load_address:
return context->selections_loadaddr;
case the_execute_address:
return context->selections_execaddr;
case the_attributes:
return context->selections_attributes;
case the_type:
return context->selections_objecttype;
case the_name:
return (int) context->selection->selection_name;
#ifdef USE_PROGRESS_BAR
case the_progress:
if (context->selections_objecttype == object_directory)
{ {
switch( thing ) debuglist(( "ponn: selection: %08x\n", 0 ));
{ return 0;
case the_size:
return context->selections_size;
case the_load_address:
return context->selections_reload;
case the_execute_address:
return context->selections_execute;
case the_attributes:
return context->selections_attributes;
case the_type:
return context->selections_objecttype;
case the_name:
return (int)context->selection->selection_name;
}
} }
else else
{ {
switch( thing ) debuglist(( "ponn: selection: %08x\n", context->progress_per_object ));
{ return context->progress_per_object;
case the_size:
return nf->directory_buffer[ nf->next_entry_to_return ].length;
case the_load_address:
return nf->directory_buffer[ nf->next_entry_to_return ].load_address;
case the_execute_address:
return nf->directory_buffer[ nf->next_entry_to_return ].execution_address;
case the_attributes:
return nf->directory_buffer[ nf->next_entry_to_return ].attributes;
case the_type:
return nf->directory_buffer[ nf->next_entry_to_return ].object_type;
case the_name:
return (int)nf->directory_buffer[ nf->next_entry_to_return ].object_name;
}
} }
case the_ref_ptr:
return (int) &context->chain_ref;
#endif
} /* end switch */
} }
else
{
directory_buffer_entry *d;
d = nf->directory_buffer + nf->next_entry_to_return;
switch( thing )
{
case the_size:
return (int) d->length;
case the_load_address:
return d->load_address;
case the_execute_address:
return d->execution_address;
case the_attributes:
return d->attributes;
case the_type:
return d->object_type;
case the_name:
return (int) d->object_name;
#ifdef USE_PROGRESS_BAR
case the_progress:
if (d->object_type == object_directory)
{
debuglist(( "ponn: nested: %08x\n", 0 ));
return 0;
}
else
{
debuglist(( "ponn: nested: %08x\n", nf->progress_per_object ));
return nf->progress_per_object;
}
case the_ref_ptr:
return (int) &d->chain_ref;
#endif
return not_found; }
}
}
debuglist(( "tonn: not found\n" ));
return not_found;
} }
unsigned int size_of_next_node( search_handle handle ) uint32_t size_of_next_node( search_handle handle )
{ {
return thing_of_next_node( handle, the_size, -1 ); return (uint32_t)thing_of_next_node( handle, the_size, 0 );
} }
unsigned int reload_of_next_node( search_handle handle ) int reload_of_next_node( search_handle handle )
{ {
return thing_of_next_node( handle, the_load_address, -1 ); return thing_of_next_node( handle, the_load_address, -1 );
} }
unsigned int execute_of_next_node( search_handle handle ) int execute_of_next_node( search_handle handle )
{ {
return thing_of_next_node( handle, the_execute_address, -1 ); return thing_of_next_node( handle, the_execute_address, -1 );
} }
unsigned int attributes_of_next_node( search_handle handle ) int attributes_of_next_node( search_handle handle )
{ {
return thing_of_next_node( handle, the_attributes, -1 ); return thing_of_next_node( handle, the_attributes, -1 );
} }
unsigned int objecttype_of_next_node( search_handle handle ) int objecttype_of_next_node( search_handle handle )
{ {
return thing_of_next_node( handle, the_type, ObjectType_NotFound ); return thing_of_next_node( handle, the_type, object_nothing );
} }
char *name_of_next_node( search_handle handle ) char *name_of_next_node( search_handle handle )
{ {
return (char *)thing_of_next_node( handle, the_name, NULL ); return (char *)thing_of_next_node( handle, the_name, NULL );
}
#ifdef USE_PROGRESS_BAR
uint32_t progress_of_next_node( search_handle handle )
{
return (uint32_t)thing_of_next_node( handle, the_progress, 0 );
}
void **chain_ref_ptr_of_next_node( search_handle handle )
{
return (void **)thing_of_next_node( handle, the_ref_ptr, NULL );
} }
#endif
/* /*
Assuming a directory has just been found, return whether this return Assuming a directory has just been found, return whether this return
of this directory was before or after its contents. of this directory was before or after its contents.
*/ */
unsigned int directory_is_after_contents( search_handle handle ) BOOL directory_is_after_contents( search_handle handle )
{ {
search_context *context = (search_context *)handle; search_context *context = (search_context *)handle;
return context->action == Next_Leaf; return context->action == Next_Leaf;
} }
/* /*
Returns 0 if no more nodes Returns 0 if no more nodes
Returns non-0 if more nodes Returns non-0 if more nodes
*/ */
unsigned int another_node( search_handle handle ) BOOL another_node( search_handle handle )
{ {
return ((search_context *)handle)->selection != NULL; return ((search_context *)handle)->selection != NULL;
} }
/* /*
When finding a selection fails call this to skip it. When finding a selection fails call this to skip it.
*/ */
void skip_failed_selection( search_handle handle ) void skip_failed_selection( search_handle handle )
{ {
search_context *context = (search_context *)handle; search_context *context = (search_context *)handle;
switch ( context->action )
{
case Next_Leaf:
/*
Can't generate an error in this state
*/
break;
case Process_Node:
context->action = Next_Leaf;
break;
case Read_Next_Cache_Full:
/*
This forces un-nesting then continuing at the upper level
*/
context->nested_filenames->offset_to_next_item = -1;
break;
case Nest_Into_Directory:
context->action = Next_Leaf;
break;
}
}
void skip_list_file( search_handle handle )
{
search_context *context = (search_context *)handle;
switch ( context->action ) context->action = Next_Leaf;
}
os_error *step_to_next_node( search_handle handle, uint32_t *progress )
{
search_context *context = (search_context *)handle;
search_nest_level *temp_context;
os_gbpbstr gbpbplace;
os_filestr fileplace;
char temp_directory_buffer[ Temp_DirBuffer_Size ];
int i;
int pos;
BOOL resolved = No;
os_error *err = NULL;
file_selection *next_selection;
int objecttype;
debuglist(( "\nstep_to_next_node\n" ));
/*
While the answer hasn't resolved itself and there's no error
then try the next step of resolving the answer
*/
while( !resolved && !err )
{
switch( context->action )
{ {
case Next_Leaf: case Next_Leaf:
/*
Step to the next leaf at this nesting level
*/
debuglist(( "Next_Leaf " ));
if ( context->nested_filenames == NULL )
{
/* /*
Can't generate an error in this state Get next selection
*/ */
break; next_selection = context->selection->next_file;
free_selection( context->selection );
context->selection = next_selection;
debuglist(( "get next selection" ));
context->action = Process_Node;
}
else
{
/*
Get next cached entry
*/
context->nested_filenames->next_entry_to_return++;
if ( context->nested_filenames->next_entry_to_return >=
context->nested_filenames->entries_in_buffer )
{
/*
We've run out of cached entries
*/
debuglist(( "cache empty " ));
context->action = Read_Next_Cache_Full;
}
else
{
/*
Found an entry in the cache, so let's
process it
*/
debuglist(( "cache ok " ));
context->action = Process_Node;
}
}
break;
case Process_Node: case Process_Node:
context->action = Next_Leaf; /*
break; Process the node as supplied by Next_Leaf
*/
debuglist(( "Process_Node " ));
if ( context->selection == NULL )
{
/*
No more entries in the selection, so we've
resolved what happens next
*/
debuglist(( "resolved all " ));
resolved = Yes;
}
else
{
/*
Get type of node if needed
*/
debuglist(( "%s ", name_of_next_node( context ) ));
if ( context->nested_filenames == NULL )
{
fileplace.action = OSFile_ReadNoPath;
err = next_filename( context, context->nested_filenames, &fileplace.name );
debuglist(( "%s ", fileplace.name ));
if ( err )
{
debuglist(( "err\n" ));
continue;
}
err = os_file( &fileplace );
if ( err )
{
overflowing_free( fileplace.name );
debuglist(( " error\n" ));
continue;
}
/*
Didn't find a selection - generate an error.
*/
if ( fileplace.action == object_nothing )
{
fileplace.loadaddr = fileplace.action;
fileplace.action = OSFile_MakeError;
err = os_file( &fileplace );
overflowing_free( fileplace.name );
debuglist(( " not found\n" ));
continue;
}
overflowing_free( fileplace.name );
context->selections_objecttype = fileplace.action;
context->selections_size = fileplace.start;
context->selections_loadaddr = fileplace.loadaddr;
context->selections_execaddr = fileplace.execaddr;
context->selections_attributes = fileplace.end;
} /* end if (nested_filenames == NULL) */
objecttype = objecttype_of_next_node( (search_handle)context );
if ( objecttype == object_nothing )
{
/*
Didn't find that, so go around
for another time - nothing to do here
*/
debuglist(( "not found " ));
context->action = Next_Leaf;
}
else if ( context->recursive &&
is_a_directory( context, objecttype ) )
{
/*
If we are returning directories first, then
we have resolved it at this level
*/
debuglist(( "directory " ));
resolved = context->directories_first;
context->action = Nest_Into_Directory;
}
else
{
/*
Found a file or we found a directory
when not recursing, in which case
we've found something worth while and
so we've resolved things.
*/
resolved = Yes;
context->action = Next_Leaf;
debuglist(( "resolved " ));
}
}
break;
case Read_Next_Cache_Full: case Read_Next_Cache_Full:
/*
If run out of entries in this directory
*/
debuglist(( "Read_Next_Cache_Full " ));
if ( context->nested_filenames->offset_to_next_item == -1 )
{
#ifdef USE_PROGRESS_BAR
search_nest_level *nf = context->nested_filenames;
int p = 0;
/* /*
This forces un-nesting then continuing at the upper level Compensate for rounding errors by adding the 'spare' progress
Isn't totally accurate if copying, as the actual progress values
used will have been halved.
*/ */
context->nested_filenames->offset_to_next_item = -1; p = nf->total_progress - (nf->total_entries * nf->progress_per_object);
break; if (p > 0) *progress += (uint32_t)p;
debuglist(( "finished %d entries (total %08x) extra progress +%08x", nf->total_entries, nf->total_progress, p ));
#else
IGNORE(progress);
#endif
/*
Down down one level
*/
temp_context = context->nested_filenames->next_search_nest_level;
for ( i = 0; i < Directory_Buffer_Size; i++ )
{
overflowing_free( context->nested_filenames->directory_buffer[ i ].object_name );
}
overflowing_free( context->nested_filenames );
context->nested_filenames = temp_context;
/*
Return the directory after all the files in it
*/
resolved = context->directories_last;
case Nest_Into_Directory:
context->action = Next_Leaf; context->action = Next_Leaf;
break; }
} else
} {
char **filename_store;
search_nest_level *nf = context->nested_filenames;
void skip_list_file( search_handle handle ) /*
{ Read more of this directory
search_context *context = (search_context *)handle; */
gbpbplace.action = OSGBPB_ReadDirEntriesInfo;
context->action = Next_Leaf; err = next_filename( context, nf->next_search_nest_level, (char **)&gbpbplace.file_handle );
}
os_error *step_to_next_node( search_handle handle ) if ( err )
{ continue;
search_context *context = (search_context *)handle;
search_nest_level *temp_context;
os_gbpbstr gbpbplace;
os_filestr fileplace;
char temp_directory_buffer[ Temp_DirBuffer_Size ];
int i;
int pos;
int resolved = No;
os_error *err = NULL;
file_selection *next_selection;
int objecttype;
/* debuglist(( "%s ", (char *)gbpbplace.file_handle ));
While the answer hasn't resolved itself and there's no error
then try the next step of resolving the answer
*/ #ifdef USE_PROGRESS_BAR
while( !resolved && !err ) if (!nf->counted)
{
switch( context->action )
{ {
case Next_Leaf: nf->total_entries = count_objects_in_dir( (char *)gbpbplace.file_handle );
nf->counted = Yes;
if (nf->total_entries != 0)
{
nf->progress_per_object = nf->total_progress / nf->total_entries;
}
else
{
void *ref;
/* /*
Step to the next leaf at this nesting level Modify progress values so that half the progress for the dir is
added when the dir is finished (in the rounding process above)
and the other half when written. We have to do this now as when
the dir was added to the chain, we didn't know it was empty.
Of course if the dir is not in the chain, we are not copying, and
so we add all the progress for this dir at once.
*/ */
if ( context->nested_filenames == NULL )
if (nf->next_search_nest_level == NULL)
{ {
/* /* top level */
Get next selection ref = context->chain_ref;
*/
next_selection = context->selection->next_file;
free_selection( context->selection );
context->selection = next_selection;
context->action = Process_Node;
} }
else else
{ {
/* int i = nf->next_search_nest_level->next_entry_to_return;
Get next cached entry ref = nf->next_search_nest_level->directory_buffer[i].chain_ref;
*/
context->nested_filenames->next_entry_to_return++;
if ( context->nested_filenames->next_entry_to_return >=
context->nested_filenames->entries_in_buffer )
{
/*
We've run out of cached entries
*/
context->action = Read_Next_Cache_Full;
}
else
{
/*
Found an entry in the cache, so let's
process it
*/
context->action = Process_Node;
}
} }
break;
case Process_Node: if (ref != NULL)
/*
Process the node as supplied by Next_Leaf
*/
if ( context->selection == NULL )
{ {
/* nf->total_progress /= 2;
No more entries in the selection, so we've nf->progress_per_object = 0;
resolved what happens next modify_chain_file_progress(ref, nf->total_progress);
*/
resolved = Yes;
} }
else
{
/*
Get type of node if needed
*/
if ( context->nested_filenames == NULL )
{
fileplace.action = 17;
err = next_filename( context, context->nested_filenames, &fileplace.name );
if ( err )
continue;
err = os_file( &fileplace );
if ( err )
{
overflowing_free( fileplace.name );
continue;
}
/*
Didn't find a selection - generate an error.
*/
if ( fileplace.action == ObjectType_NotFound )
{
fileplace.loadaddr = fileplace.action;
fileplace.action = 19;
err = os_file( &fileplace );
overflowing_free( fileplace.name );
continue;
}
overflowing_free( fileplace.name );
context->selections_objecttype = fileplace.action;
context->selections_size = fileplace.start;
context->selections_reload = fileplace.loadaddr;
context->selections_execute = fileplace.execaddr;
context->selections_attributes = fileplace.end;
}
objecttype = objecttype_of_next_node( (search_handle)context );
if ( objecttype == ObjectType_NotFound )
{
/*
Didn't find that, so go around
for another time - nothing to do here
*/
context->action = Next_Leaf;
}
else if ( context->recursive &&
is_a_directory( context, objecttype ) )
{
/*
If we are returning directories first, then
we have resolved it at this level
*/
resolved = context->directories_first;
context->action = Nest_Into_Directory;
}
else
{
/*
Found a file or we found a directory
when not recursing, in which case
we've found something worth while and
so we've resolved things.
*/
resolved = Yes;
context->action = Next_Leaf;
}
}
break;
case Read_Next_Cache_Full: } /* end if (total_entries > 0) */
debuglist(( "%d entries %08x total progress %08x per object ", nf->total_entries, nf->total_progress, nf->progress_per_object ));
} /* end if (!counted) */
#endif
gbpbplace.data_addr = &temp_directory_buffer;
gbpbplace.number = Directory_Buffer_Size;
gbpbplace.seq_point = context->nested_filenames->offset_to_next_item;
gbpbplace.buf_len = Temp_DirBuffer_Size;
gbpbplace.wild_fld = "*";
err = os_gbpb( &gbpbplace );
overflowing_free( (void *)gbpbplace.file_handle );
if ( err )
{
if ( (err->errnum & FileError_Mask) == ErrorNumber_NotFound )
{
/* /*
If run out of entries in this directory Cancel the error
*/ */
if ( context->nested_filenames->offset_to_next_item == -1 ) err = NULL;
{
/* /*
Down down one level Down down one level
*/ */
temp_context = context->nested_filenames->next_search_nest_level; temp_context = context->nested_filenames->next_search_nest_level;
for ( i = 0; i < Directory_Buffer_Size; i++ ) for ( i = 0; i < Directory_Buffer_Size; i++ )
{
overflowing_free( context->nested_filenames->directory_buffer[ i ].object_name );
}
overflowing_free( context->nested_filenames );
context->nested_filenames = temp_context;
/*
Return the directory after all the files in it
*/
resolved = context->directories_last;
context->action = Next_Leaf;
}
else
{ {
char **filename_store; overflowing_free( context->nested_filenames->directory_buffer[ i ].object_name );
/*
Read more of this directory
*/
gbpbplace.action = 10;
err = next_filename( context, context->nested_filenames->next_search_nest_level, (char **)&gbpbplace.file_handle );
if ( err )
continue;
gbpbplace.data_addr = &temp_directory_buffer;
gbpbplace.number = Directory_Buffer_Size;
gbpbplace.seq_point = context->nested_filenames->offset_to_next_item;
gbpbplace.buf_len = Temp_DirBuffer_Size;
gbpbplace.wild_fld = "*";
err = os_gbpb( &gbpbplace );
overflowing_free( (void *)gbpbplace.file_handle );
if ( err )
{
if ( (err->errnum & FileError_Mask) == ErrorNumber_NotFound )
{
/*
Cancel the error
*/
err = NULL;
/*
Down down one level
*/
temp_context = context->nested_filenames->next_search_nest_level;
for ( i = 0; i < Directory_Buffer_Size; i++ )
{
overflowing_free( context->nested_filenames->directory_buffer[ i ].object_name );
}
overflowing_free( context->nested_filenames );
context->nested_filenames = temp_context;
/*
Don't return the directory, as it
doesn't exist!
*/
context->action = Next_Leaf;
}
continue;
}
for ( i = 0, pos = 0; i < gbpbplace.number; i++ )
{
context->nested_filenames->directory_buffer[ i ].load_address = *(int *)&temp_directory_buffer[ pos ];
pos += 4;
context->nested_filenames->directory_buffer[ i ].execution_address = *(int *)&temp_directory_buffer[ pos ];
pos += 4;
context->nested_filenames->directory_buffer[ i ].length = *(int *)&temp_directory_buffer[ pos ];
pos += 4;
context->nested_filenames->directory_buffer[ i ].attributes = *(int *)&temp_directory_buffer[ pos ];
pos += 4;
context->nested_filenames->directory_buffer[ i ].object_type = *(int *)&temp_directory_buffer[ pos ];
pos += 4;
/*
Free the filename if there's one there
*/
filename_store = &context->nested_filenames->directory_buffer[ i ].object_name;
if ( *filename_store )
{
overflowing_free ( *filename_store );
*filename_store = NULL;
}
/*
Allocate some space for the file name
*/
if ( ( *filename_store = overflowing_malloc( strlen( &temp_directory_buffer[ pos ] ) + 1 ) ) == NULL )
{
/*
If the allocation failed, free everything up
*/
int j;
for ( j = 0; j < i; j++ )
{
overflowing_free( context->nested_filenames->directory_buffer[ j ].object_name );
context->nested_filenames->directory_buffer[ j ].object_name = NULL;
}
err = error( mb_malloc_failed );
break;
}
strcpy( *filename_store, &temp_directory_buffer[ pos ] );
pos += strlen( &temp_directory_buffer[ pos ] ) + 1;
/* round pos up to a word boundary */
pos = (( pos + 3 ) / 4 ) * 4;
}
if ( err )
break;
context->nested_filenames->offset_to_next_item = gbpbplace.seq_point;
context->nested_filenames->entries_in_buffer = gbpbplace.number;
context->nested_filenames->next_entry_to_return = -1;
context->action = Next_Leaf;
} }
break; overflowing_free( context->nested_filenames );
context->nested_filenames = temp_context;
case Nest_Into_Directory:
/* /*
Go down into the next nesting level Don't return the directory, as it
doesn't exist!
*/ */
temp_context = context->nested_filenames; context->action = Next_Leaf;
}
context->nested_filenames = overflowing_malloc( sizeof( search_nest_level )); continue;
if ( context->nested_filenames == NULL ) }
{
context->nested_filenames = temp_context;
err = error( mb_malloc_failed );
continue;
}
context->nested_filenames->next_search_nest_level = temp_context; for ( i = 0, pos = 0; i < gbpbplace.number; i++ )
context->nested_filenames->offset_to_next_item = 0; {
context->nested_filenames->entries_in_buffer = 0; context->nested_filenames->directory_buffer[ i ].load_address = *(int *)&temp_directory_buffer[ pos ];
context->nested_filenames->next_entry_to_return = -1; pos += sizeof(int);
context->nested_filenames->directory_buffer[ i ].execution_address = *(int *)&temp_directory_buffer[ pos ];
pos += sizeof(int);
context->nested_filenames->directory_buffer[ i ].length = *(uint32_t *)&temp_directory_buffer[ pos ];
pos += sizeof(uint32_t);
context->nested_filenames->directory_buffer[ i ].attributes = *(int *)&temp_directory_buffer[ pos ];
pos += sizeof(int);
context->nested_filenames->directory_buffer[ i ].object_type = *(int *)&temp_directory_buffer[ pos ];
pos += sizeof(int);
/*
Free the filename if there's one there
*/
filename_store = &context->nested_filenames->directory_buffer[ i ].object_name;
if ( *filename_store )
{
overflowing_free ( *filename_store );
*filename_store = NULL;
}
/*
Allocate some space for the file name
*/
if ( ( *filename_store = overflowing_malloc( strlen( &temp_directory_buffer[ pos ] ) + 1 ) ) == NULL )
{
/*
If the allocation failed, free everything up
*/
int j;
for ( i = 0; i < Directory_Buffer_Size; i++ ) for ( j = 0; j < i; j++ )
{ {
context->nested_filenames->directory_buffer[ i ].object_name = NULL; overflowing_free( context->nested_filenames->directory_buffer[ j ].object_name );
context->nested_filenames->directory_buffer[ j ].object_name = NULL;
} }
context->action = Next_Leaf; err = error( mb_malloc_failed );
break; break;
}
default: /* disaster!!!!! */ strcpy( *filename_store, &temp_directory_buffer[ pos ] );
err = error( mb_unexpected_state );
break; pos += strlen( &temp_directory_buffer[ pos ] ) + 1;
/* round pos up to a word boundary */
pos = (( pos + 3 ) / 4 ) * 4;
} }
}
return err; if ( err )
break;
context->nested_filenames->offset_to_next_item = gbpbplace.seq_point;
context->nested_filenames->entries_in_buffer = gbpbplace.number;
context->nested_filenames->next_entry_to_return = -1;
context->action = Next_Leaf;
}
break;
case Nest_Into_Directory:
/*
Go down into the next nesting level
*/
debuglist(( "Nest_Into_Directory " ));
temp_context = context->nested_filenames;
context->nested_filenames = overflowing_malloc( sizeof( search_nest_level ));
if ( context->nested_filenames == NULL )
{
context->nested_filenames = temp_context;
err = error( mb_malloc_failed );
continue;
}
context->nested_filenames->next_search_nest_level = temp_context;
context->nested_filenames->offset_to_next_item = 0;
context->nested_filenames->entries_in_buffer = 0;
context->nested_filenames->next_entry_to_return = -1;
#ifdef USE_PROGRESS_BAR
if (temp_context != NULL)
{
context->nested_filenames->total_progress = temp_context->progress_per_object;
}
else
{
context->nested_filenames->total_progress = context->progress_per_object;
}
/* Default values, will be overwitten if this object is a dir */
context->nested_filenames->progress_per_object = 0;
context->nested_filenames->total_entries = 0;
context->nested_filenames->counted = No;
#endif
for ( i = 0; i < Directory_Buffer_Size; i++ )
{
context->nested_filenames->directory_buffer[ i ].object_name = NULL;
#ifdef USE_PROGRESS_BAR
context->nested_filenames->directory_buffer[ i ].chain_ref = NULL;
#endif
}
context->action = Next_Leaf;
break;
default: /* disaster!!!!! */
err = error( mb_unexpected_state );
break;
} /* end switch */
debuglist(( "\n" ));
} /* end while */
return err;
} }
#ifdef USE_PROGRESS_BAR
void listfiles_convert_to_copymove( search_handle handle )
{
search_context *context = (search_context *)handle;
if (context == NULL) return;
context->total_progress /= 2;
}
#endif
...@@ -28,7 +28,7 @@ Theory: ...@@ -28,7 +28,7 @@ Theory:
(1) read blocks (or all) of source file(s) into a contiguous chunk of store (1) read blocks (or all) of source file(s) into a contiguous chunk of store
- extend as necessary up to next slot size - extend as necessary up to next slot size
- be prepared to loose information if slot size has to be shrunk - be prepared to lose information if slot size has to be shrunk
(2) write blocks to destination file(s) (2) write blocks to destination file(s)
...@@ -64,19 +64,24 @@ Notes: ...@@ -64,19 +64,24 @@ Notes:
*/ */
#if 0 #if 0
#define debugmem #define debugmem(k) dprintf k
#else
#define debugmem(k) /* Disabled */
#endif #endif
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdint.h>
#include <time.h> #include <time.h>
#include <stdlib.h> #include <stdlib.h>
#include "kernel.h" #include "kernel.h"
#include "Interface/HighFSI.h"
#include "os.h" #include "os.h"
#include "wimp.h" #include "wimp.h"
#include "Options.h"
#include "chains.h" #include "chains.h"
#include "allerrs.h" #include "allerrs.h"
#include "malloc+.h" #include "malloc+.h"
...@@ -84,16 +89,11 @@ Notes: ...@@ -84,16 +89,11 @@ Notes:
#include "debug.h" #include "debug.h"
#if Timing #if Timing
static int copytime; static clock_t copytime;
#endif #endif
#define Yes 1
#define No 0 #define No 0
#define Yes (!No)
#define ObjectType_NotFound 0
#define ObjectType_File 1
#define ObjectType_Directory 2
#define InitialBlockSize 4096 #define InitialBlockSize 4096
#define SmallBlockSize 3072 /* check the transfer rate is not too low if the blocksize reduces below this */ #define SmallBlockSize 3072 /* check the transfer rate is not too low if the blocksize reduces below this */
...@@ -107,37 +107,43 @@ static int copytime; ...@@ -107,37 +107,43 @@ static int copytime;
The file headers are held in a doubly linked list, on the malloc+ heap The file headers are held in a doubly linked list, on the malloc+ heap
*/ */
typedef enum { typedef enum {
write_not_started, write_not_started,
write_f_tried_unlock, /* open/save failed - have tried to unlock it */ write_f_tried_unlock, /* open/save failed - have tried to unlock it */
write_f_tried_cdirs, /* open/save failed - have tried to cdir it */ write_f_tried_cdirs, /* open/save failed - have tried to cdir it */
write_f_tried_both, /* open/save failed - have tried both cdirs and unlock */ write_f_tried_both, /* open/save failed - have tried both cdirs and unlock */
write_openit, /* have created it, now open it */ write_openit, /* have created it, now open it */
write_truncateopen, /* have opened it now truncate it */ write_truncateopen, /* have opened it now truncate it */
write_blocks, /* next thing is writing blocks out */ write_blocks, /* next thing is writing blocks out */
write_closeit, /* next thing is to close it */ write_closeit, /* next thing is to close it */
write_adjust_access, /* next thing is adjust the access */ write_adjust_access, /* next thing is adjust the access */
write_adjust_info, /* next thing is adjust the info */ write_adjust_info, /* next thing is adjust the info */
write_all_done /* and junk the fh */ write_all_done /* and junk the fh */
} write_activity; } write_activity;
typedef struct typedef struct
{ {
chain_link link; chain_link link;
char *source_filename; char *source_filename;
int source_file_handle; int source_file_handle;
char *destination_filename; char *destination_filename;
int destination_file_handle; int destination_file_handle;
int size; uint32_t size;
int reload; int reload;
int execute; int execute;
int attributes; int attributes;
int objecttype; int objecttype;
int forceit; BOOL forceit;
int read_to; uint32_t read_to;
int written_to; uint32_t written_to;
write_activity write_state; write_activity write_state;
int start_of_buffer; /* offset into memory */ int start_of_buffer; /* offset into memory */
} files_header;
#ifdef USE_PROGRESS_BAR
uint32_t total_progress;
uint32_t read_progress;
uint32_t write_progress;
#endif
} files_header;
/* /*
Structures for copying files Structures for copying files
...@@ -145,18 +151,18 @@ typedef struct ...@@ -145,18 +151,18 @@ typedef struct
static chain_header files_chain; /* All the files registered with memmanage */ static chain_header files_chain; /* All the files registered with memmanage */
static int application_max_size; static int application_max_size;
static char *buffer_base_address; /* Base of buffer area */ static char *buffer_base_address; /* Base of buffer area */
static int buffer_offset; /* offset to add to botom, top, and any other offsets into the area */ static int buffer_offset; /* offset to add to bottom, top, and any other offsets into the area */
/* used when the area contents are shuffled */ /* used when the area contents are shuffled */
static int buffer_bottom; /* offset to 1st used byte in buffer area */ static int buffer_bottom; /* offset to 1st used byte in buffer area */
static int buffer_top; /* offset to top free section in buffer area */ static int buffer_top; /* offset to top free section in buffer area */
static int buffer_end; /* offset to end of buffer area */ static int buffer_end; /* offset to end of buffer area */
static int last_requested_size;
static int src_block_size; static int src_block_size;
static int dest_block_size; static int dest_block_size;
static int time_quanta = NominalTimeQuanta; static int time_quanta = NominalTimeQuanta;
static int minimum_block_size = 512; static int minimum_block_size = 512;
int size_of_finished_file;
char *source_of_finished_file; BOOL finished_obj_was_file;
char *finished_obj_source_name;
/* JRS addition 16/1/92 */ /* JRS addition 16/1/92 */
/* accumulate transfer times at initial blocksize to compare timings at smaller /* accumulate transfer times at initial blocksize to compare timings at smaller
...@@ -170,360 +176,360 @@ char *source_of_finished_file; ...@@ -170,360 +176,360 @@ char *source_of_finished_file;
#define timing_NAccumulated 4 /* accumulate this many timings to average out variation */ #define timing_NAccumulated 4 /* accumulate this many timings to average out variation */
static struct static struct
{ {
int rate; /* transfer rate calculated from accumulator and blocksize */ int rate; /* transfer rate calculated from accumulator and blocksize */
int accumulator; int accumulator;
int naccumulated; int naccumulated;
} timing[2]; /* read and write initial timing */ } timing[2]; /* read and write initial timing */
/*
Rate evaluation functions
*/
static void timing_init(void) static void timing_init(void)
{ {
int rw; int rw;
for (rw = 0; rw < 2; rw++) /* reading and writing */ for (rw = 0; rw < 2; rw++) /* reading and writing */
{ {
timing[rw].rate = 0; timing[rw].rate = 0;
timing[rw].accumulator = 0; timing[rw].accumulator = 0;
timing[rw].naccumulated = 0; timing[rw].naccumulated = 0;
} }
} }
static int t__accumulatortorate(int accumulated_time, int blocksize) static int t__accumulatortorate(int accumulated_time, int blocksize)
{ /* convert an accumulated timing to a transfer rate value */ { /* convert an accumulated timing to a transfer rate value */
if (accumulated_time < 1) accumulated_time = 1; /* ensure no div by zero */ if (accumulated_time < 1) accumulated_time = 1; /* ensure no div by zero */
#ifdef debugmem debugmem(( "t__accumulatortorate: %d,%d->%d\n", accumulated_time, blocksize,(blocksize<<8) / accumulated_time));
dprintf("calcrate %d,%d->%d\n", accumulated_time, blocksize,(blocksize<<8) / accumulated_time);
#endif return (blocksize<<8) / accumulated_time; /* shift is to gain integer value range */
return (blocksize<<8) / accumulated_time; /* shift is to gain integer value range */
} }
static void timing_accumulate(int rw, int t, int blocksize) static void timing_accumulate(int rw, int t, int blocksize)
/* accumulate a timing for read or write, return Yes if it is full (enough have been accumulated) */ /* accumulate a timing for read or write, return Yes if it is full (enough have been accumulated) */
{ {
assert((rw==timing_Reading)||(rw==timing_Writing)); assert((rw==timing_Reading)||(rw==timing_Writing));
assert(timing[rw].naccumulated < timing_NAccumulated); assert(timing[rw].naccumulated < timing_NAccumulated);
timing[rw].naccumulated++; timing[rw].naccumulated++;
timing[rw].accumulator += t; timing[rw].accumulator += t;
if ( timing[rw].naccumulated >= timing_NAccumulated ) if ( timing[rw].naccumulated >= timing_NAccumulated )
{ /* accumulator is full and rate is not yet calculated; calculate rate */ { /* accumulator is full and rate is not yet calculated; calculate rate */
assert(timing[rw].rate == 0); assert(timing[rw].rate == 0);
timing[rw].rate = t__accumulatortorate(timing[rw].accumulator, blocksize); timing[rw].rate = t__accumulatortorate(timing[rw].accumulator, blocksize);
} }
} }
static int timing_accumulating(int rw) static int timing_accumulating(int rw)
{ {
assert((rw==timing_Reading)||(rw==timing_Writing)); assert((rw==timing_Reading)||(rw==timing_Writing));
return (timing[rw].naccumulated < timing_NAccumulated); return (timing[rw].naccumulated < timing_NAccumulated);
} }
static int timing_poorrate(int rw, int t, int blocksize) static int timing_poorrate(int rw, int t, int blocksize)
{ /* compare the given time, converted to a rate against the rate for the initial blocksize. { /* compare the given time, converted to a rate against the rate for the initial blocksize.
* Return Yes if it is worse than 2/3 of the initial rate */ * Return Yes if it is worse than 2/3 of the initial rate */
assert((rw==timing_Reading)||(rw==timing_Writing)); assert((rw==timing_Reading)||(rw==timing_Writing));
return ( t__accumulatortorate(t * timing_NAccumulated, blocksize) < (2*timing[rw].rate)/3 ); return ( t__accumulatortorate(t * timing_NAccumulated, blocksize) < (2*timing[rw].rate)/3 );
} }
static int application_current_size( void ) static int application_current_size( void )
{ {
int currentslot = -1; int currentslot = -1;
int nextslot = -1; int nextslot = -1;
int freepool; int freepool;
wimp_slotsize( &currentslot, &nextslot, &freepool ); wimp_slotsize( &currentslot, &nextslot, &freepool );
return currentslot; return currentslot;
} }
static int current_next_slot( void ) static int current_next_slot( void )
{ {
int currentslot = -1; int currentslot = -1;
int nextslot = -1; int nextslot = -1;
int freepool; int freepool;
wimp_slotsize( &currentslot, &nextslot, &freepool ); wimp_slotsize( &currentslot, &nextslot, &freepool );
return nextslot; return nextslot;
} }
/* /*
returns amount actually changed by returns amount actually changed by
*/ */
static int extend_application_slot( int amount ) static int extend_application_slot( int amount )
{ {
int oldslot; int oldslot;
int currentslot; int currentslot;
int nextslot = -1; int nextslot = -1;
int freepool; int freepool;
if ( amount != 0 ) if ( amount != 0 )
{ {
oldslot = application_current_size(); oldslot = application_current_size();
currentslot = oldslot + amount; currentslot = oldslot + amount;
wimp_slotsize( &currentslot, &nextslot, &freepool ); wimp_slotsize( &currentslot, &nextslot, &freepool );
#ifdef debugmem debugmem(( "extend_application_slot: amount = %d, new size = %d\n",amount,currentslot));
dprintf("extend_application_slot: amount = %d, new size = %d\n",amount,currentslot);
#endif
return currentslot - oldslot; return currentslot - oldslot;
} }
else else
{ {
return 0; return 0;
} }
} }
/* /*
Ensure that the top to end amount free is at least size Ensure that the top to end amount free is at least size
*/ */
static int buffer_ensure( int size ) static BOOL buffer_ensure( int size )
{ {
if ( buffer_end - buffer_top < size ) if ( buffer_end - buffer_top < size )
{ {
buffer_end += extend_application_slot( size - (buffer_end - buffer_top) ); buffer_end += extend_application_slot( size - (buffer_end - buffer_top) );
} }
return buffer_end - buffer_top >= size; return buffer_end - buffer_top >= size;
} }
/* /*
Grow the buffer so that "size" is available, limiting by application_max_siz. Grow the buffer so that "size" is available, limiting by application_max_siz.
Reduces *size to fit space. Reduces *size to fit space.
Returns Yes if not enough space available for original requested *size. Returns Yes if not enough space available for original requested *size.
*/ */
static int grow_buffer( int *size ) static int grow_buffer( int *size )
{ {
int answer = No; BOOL answer = No;
/* /*
Upper bound by application_max_size Upper bound by application_max_size
*/ */
if ( (int)(buffer_base_address + *size + buffer_top + buffer_offset) > application_max_size + 0x8000 ) if ( (int)(buffer_base_address + *size + buffer_top + buffer_offset) > application_max_size + 0x8000 )
{ {
*size = application_max_size + 0x8000 - (int)(buffer_base_address + buffer_top + buffer_offset); *size = application_max_size + 0x8000 - (int)(buffer_base_address + buffer_top + buffer_offset);
answer = Yes; answer = Yes;
} }
/* /*
Try to ensure that much space Try to ensure that much space
*/ */
answer = answer || !buffer_ensure( *size ); answer = answer || !buffer_ensure( *size );
if ( buffer_end - buffer_top < *size ) if ( buffer_end - buffer_top < *size )
{ {
*size = buffer_end - buffer_top; *size = buffer_end - buffer_top;
answer = Yes; answer = Yes;
} }
return answer; return answer;
} }
static os_error *close_file( int *handle ) static os_error *close_file( int *handle )
{ {
os_regset r; os_regset r;
os_error *err; os_error *err;
r.r[0] = 0; /* close file */ r.r[0] = 0; /* close file */
r.r[1] = *handle; r.r[1] = *handle;
err = os_find( &r ); err = os_find( &r );
/* /*
Even a failed close leaves the file closed afterwards Even a failed close leaves the file closed afterwards
*/ */
*handle = 0; *handle = 0;
return err; return err;
} }
/* /*
Creates the file to be the given size, dead, with read/write Creates the file to be the given size, dead, with read/write
access only. access only.
*/ */
static os_error *create_file_dead( char *filename, int size ) static os_error *create_file_dead( char *filename, uint32_t size )
{ {
os_filestr fileplace; os_filestr fileplace;
os_error *err; os_error *err;
fileplace.action = 7; /* create a file */ fileplace.action = OSFile_Create;
fileplace.name = filename; fileplace.name = filename;
fileplace.loadaddr = (int) 0xdeaddead; fileplace.loadaddr = (int) 0xdeaddead;
fileplace.execaddr = (int) 0xdeaddead; fileplace.execaddr = (int) 0xdeaddead;
fileplace.start = 0; fileplace.start = 0;
fileplace.end = size; fileplace.end = (int)size;
err = os_file( &fileplace ); err = os_file( &fileplace );
if ( err ) if ( err )
return err; return err;
fileplace.action = 4; /* set access to a file */ fileplace.action = OSFile_WriteAttr;
fileplace.name = filename; fileplace.name = filename;
fileplace.end = 0x3; /* read/write only */ fileplace.end = read_attribute | write_attribute;
return os_file( &fileplace ); return os_file( &fileplace );
} }
static os_error *create_directory( char *dirname ) static os_error *create_directory( char *dirname )
{ {
os_filestr fileplace; os_filestr fileplace;
fileplace.action = 8; /* create a directory */ fileplace.action = OSFile_CreateDir;
fileplace.name = dirname; fileplace.name = dirname;
fileplace.start = 0; fileplace.start = 0;
return os_file( &fileplace ); return os_file( &fileplace );
} }
static os_error *write_catalogue_information( char *filename, int reload, int execute, int attributes ) static os_error *write_catalogue_information( char *filename, int reload, int execute, int attributes )
{ {
os_filestr fileplace; os_filestr fileplace;
fileplace.action = 1; /* write catalogue information */ fileplace.action = OSFile_WriteInfo;
fileplace.name = filename; fileplace.name = filename;
fileplace.loadaddr = reload; fileplace.loadaddr = reload;
fileplace.execaddr = execute; fileplace.execaddr = execute;
fileplace.end = attributes; fileplace.end = attributes;
return os_file( &fileplace ); return os_file( &fileplace );
} }
static os_error *write_attributes( char *filename, int attributes ) static os_error *write_attributes( char *filename, int attributes )
{ {
os_filestr fileplace; os_filestr fileplace;
fileplace.action = 4; /* write attributes */ fileplace.action = OSFile_WriteAttr;
fileplace.name = filename; fileplace.name = filename;
fileplace.end = attributes; fileplace.end = attributes;
return os_file( &fileplace ); return os_file( &fileplace );
} }
static char *first_dirbreak( char *filename ) static char *first_dirbreak( char *filename )
{ {
char *trypos; char *trypos;
char *endpos; char *endpos;
/*
Point trypos past the -<fsname>- / <fsname>: bit
*/
if ( filename[0] == '-' )
{
/*
-<fsname>-
*/
trypos = strchr( filename + 1, '-' ) + 1;
}
else if ( filename[0] != ':' )
{
/* /*
Point trypos past the -<fsname>- / <fsname>: bit <fsname>: perhaps
*/ */
if ( filename[0] == '-' ) trypos = strchr( filename, ':' );
if ( trypos == NULL )
{ {
/* /*
-<fsname>- It wasn't <fsname>:, never mind
*/ */
trypos = strchr( filename + 1, '-' ) + 1; trypos = filename;
} }
else if ( filename[0] != ':' ) else
{ {
/* trypos++;
<fsname>: perhaps
*/
trypos = strchr( filename, ':' );
if ( trypos == NULL )
{
/*
It wasn't <fsname>:, never mind
*/
trypos = filename;
}
else
{
trypos++;
}
} }
else }
else
{
trypos = filename;
}
/*
Move trypos past the :<devname> or :<devname>. bit if it's there
*/
if ( *trypos == ':' )
{
endpos = strchr( trypos, '.' );
if ( endpos == NULL )
{ {
trypos = filename; trypos = trypos + strlen( trypos );
} }
else
/*
Move trypos past the :<devname> or :<devname>. bit if it's there
*/
if ( *trypos == ':' )
{ {
endpos = strchr( trypos, '.' ); trypos = endpos + 1;
if ( endpos == NULL )
{
trypos = trypos + strlen( trypos );
}
else
{
trypos = endpos + 1;
}
} }
}
/*
Move past the first component (and any $. &. %. @. or \.) /*
*/ Move past the first component (and any $. &. %. @. or \.)
if ( *trypos != '\0' ) */
if ( *trypos != '\0' )
{
switch( *trypos )
{ {
switch( *trypos ) case '$':
{ case '&':
case '$': case '%':
case '&': case '@':
case '%': case '\\':
case '@':
case '\\': trypos ++;
trypos ++; if ( *trypos == '.' )
trypos++;
if ( *trypos == '.' )
trypos++; /*
Fall through to skipping over the next component
/* */
Fall through to skipping over the next component
*/ default:
endpos = strchr( trypos, '.' );
default:
endpos = strchr( trypos, '.' ); if ( endpos == NULL )
{
if ( endpos == NULL ) trypos = trypos + strlen( trypos );
{ }
trypos = trypos + strlen( trypos ); else
} {
else trypos = endpos;
{ }
trypos = endpos;
} break;
break;
}
} }
}
/* /*
trypos now points past the first non-special component trypos now points past the first non-special component
of the filename or at the terminating nul of the filename or at the terminating nul
*/ */
return trypos; return trypos;
} }
static os_error *ensure_file_directories( char *filename ) static os_error *ensure_file_directories( char *filename )
{ {
char *currpos; char *currpos;
os_error *err; os_error *err;
for ( currpos = first_dirbreak( filename ); for ( currpos = first_dirbreak( filename );
currpos && *currpos; currpos && *currpos;
currpos = strchr( currpos + 1, '.' ) ) currpos = strchr( currpos + 1, '.' ) )
{ {
*currpos = '\0'; *currpos = '\0';
err = create_directory( filename ); err = create_directory( filename );
*currpos = '.'; *currpos = '.';
if ( err ) if ( err )
return err; return err;
} }
return NULL; return NULL;
} }
/* /*
...@@ -533,11 +539,11 @@ static os_error *ensure_file_directories( char *filename ) ...@@ -533,11 +539,11 @@ static os_error *ensure_file_directories( char *filename )
*/ */
static void ensure_files_closed( files_header *fh ) static void ensure_files_closed( files_header *fh )
{ {
if ( fh->destination_file_handle ) if ( fh->destination_file_handle )
close_file( &fh->destination_file_handle ); close_file( &fh->destination_file_handle );
if ( fh->source_file_handle ) if ( fh->source_file_handle )
close_file( &fh->source_file_handle ); close_file( &fh->source_file_handle );
} }
/* /*
...@@ -545,70 +551,71 @@ static void ensure_files_closed( files_header *fh ) ...@@ -545,70 +551,71 @@ static void ensure_files_closed( files_header *fh )
*/ */
static void remove_fh( files_header *fh ) static void remove_fh( files_header *fh )
{ {
chain_remove_link( &fh->link ); chain_remove_link( &fh->link );
ensure_files_closed( fh ); ensure_files_closed( fh );
if ( fh->start_of_buffer + fh->read_to - fh->written_to >= buffer_top ) if ( fh->start_of_buffer + fh->read_to - fh->written_to >= buffer_top )
{ {
/* /*
removing buffer at end removing buffer at end
*/ */
if ( fh->start_of_buffer < buffer_top ) if ( fh->start_of_buffer < buffer_top )
buffer_top = fh->start_of_buffer; buffer_top = fh->start_of_buffer;
} }
else else
{ {
/* /*
removing buffer at start removing buffer at start
*/ */
buffer_bottom += fh->read_to - fh->written_to; buffer_bottom += fh->read_to - fh->written_to;
} }
if ( fh->source_filename ) if ( fh->source_filename )
overflowing_free( fh->source_filename ); overflowing_free( fh->source_filename );
overflowing_free( fh->destination_filename );
overflowing_free( fh ); overflowing_free( fh->destination_filename );
overflowing_free( fh );
} }
/* /*
Assumuing no buffer in buffer chain, and no open files, remove Assuming no buffer in buffer chain, and no open files, remove
forwards file from files_chain. forwards file from files_chain.
*/ */
static void remove_file_from_chain( void ) static void remove_file_from_chain( void )
{ {
chain_link *link = files_chain.forwards; chain_link *link = files_chain.forwards;
files_header *fh; files_header *fh;
if ( !link->forwards ) if ( !link->forwards )
return; return;
fh = chain_link_Wrapper( link ); fh = chain_link_Wrapper( link );
/* /*
Special indication that it has been a directory that's just Special indication that it has been a directory that's just
been finished been finished
*/ */
if ( fh->objecttype == ObjectType_Directory ) if ( fh->objecttype == object_directory )
{ {
size_of_finished_file = -1; finished_obj_was_file = No;
} }
else else
{ {
size_of_finished_file = fh->size; finished_obj_was_file = Yes;
} }
/* /*
Record the source filename of the finished file Record the source filename of the finished file
*/ */
if ( source_of_finished_file ) if ( finished_obj_source_name )
overflowing_free( source_of_finished_file ); overflowing_free( finished_obj_source_name );
source_of_finished_file = fh->source_filename; finished_obj_source_name = fh->source_filename;
fh->source_filename = NULL; fh->source_filename = NULL;
remove_fh( fh ); remove_fh( fh );
} }
/* /*
...@@ -616,22 +623,22 @@ static void remove_file_from_chain( void ) ...@@ -616,22 +623,22 @@ static void remove_file_from_chain( void )
*/ */
static files_header *next_fh_to_read( void ) static files_header *next_fh_to_read( void )
{ {
chain_link *link; chain_link *link;
files_header *fh; files_header *fh;
for ( link = files_chain.forwards; link->forwards; link = link->forwards ) for ( link = files_chain.forwards; link->forwards; link = link->forwards )
{ {
fh = chain_link_Wrapper( link ); fh = chain_link_Wrapper( link );
if ( fh->objecttype != ObjectType_Directory && if ( fh->objecttype != object_directory &&
( fh->read_to < fh->size || ( fh->read_to < fh->size ||
fh->source_file_handle ) ) fh->source_file_handle ) )
{ {
return fh; return fh;
}
} }
}
return NULL; return NULL;
} }
/* /*
...@@ -639,10 +646,10 @@ static files_header *next_fh_to_read( void ) ...@@ -639,10 +646,10 @@ static files_header *next_fh_to_read( void )
*/ */
static void skip_file( files_header *fh ) static void skip_file( files_header *fh )
{ {
if ( fh == NULL ) if ( fh == NULL )
return; return;
remove_fh( fh ); remove_fh( fh );
} }
/* /*
...@@ -651,156 +658,152 @@ static void skip_file( files_header *fh ) ...@@ -651,156 +658,152 @@ static void skip_file( files_header *fh )
static int grow( int block ) static int grow( int block )
{ {
if ( block < 4096 ) if ( block < 4096 )
{ {
block = (block + 1024) & ~1023; block = (block + 1024) & ~1023;
} }
else if ( block < 16384 ) else if ( block < 16384 )
{ {
block = (block + 4096) & ~4095; block = (block + 4096) & ~4095;
} }
else else
{ {
block = (block + (block>>1)) & ~4095; block = (block + (block>>1)) & ~4095;
} }
#ifdef debugmem debugmem(( "grow: to %d\n", block ));
dprintf( "growing to %d\n", block );
#endif return block;
return block;
} }
static int shrink( int block ) static int shrink( int block )
{ {
if ( block < 4096 ) if ( block < 4096 )
{ {
block = (block - 256) & ~255; block = (block - 256) & ~255;
} }
else if ( block < 16384 ) else if ( block < 16384 )
{ {
block = (block - 1024) & ~1023; block = (block - 1024) & ~1023;
} }
else else
{ {
block = (block - (block>>2)) & ~1023; block = (block - (block>>2)) & ~1023;
} }
if ( block < minimum_block_size ) if ( block < minimum_block_size )
block = minimum_block_size; block = minimum_block_size;
#ifdef debugmem debugmem(( "shrink: to %d\n", block ));
dprintf( "shrinking to %d\n", block );
#endif return block;
return block;
} }
/* /*
Go through all readable files and discard their buffers if they overhang Go through all readable files and discard their buffers if they overhang
the top of the buffer the top of the buffer
*/ */
static void truncate_overhanging_files( void ) static void truncate_overhanging_files( void )
{ {
chain_link *link; chain_link *link;
files_header *fh; files_header *fh;
for ( link = files_chain.forwards; link->forwards; link = link->forwards ) for ( link = files_chain.forwards; link->forwards; link = link->forwards )
{ {
fh = chain_link_Wrapper( link ); fh = chain_link_Wrapper( link );
if ( fh->objecttype != ObjectType_Directory ) if ( fh->objecttype != object_directory )
{ {
if ( fh->start_of_buffer >= buffer_top ) if ( fh->start_of_buffer >= buffer_top )
{ {
/* /*
file buffer starts beyond end of buffer file buffer starts beyond end of buffer
*/ */
fh->start_of_buffer = 0; fh->start_of_buffer = 0;
fh->read_to = fh->written_to; fh->read_to = fh->written_to;
} }
else if ( fh->start_of_buffer + fh->read_to - fh->written_to > buffer_top ) else if ( fh->start_of_buffer + fh->read_to - fh->written_to > buffer_top )
{ {
/* /*
file buffer hangs over end of buffer file buffer hangs over end of buffer
*/ */
fh->read_to = buffer_top - (fh->start_of_buffer - fh->written_to); fh->read_to = buffer_top - (fh->start_of_buffer - fh->written_to);
} }
}
} }
}
} }
static int memmanage_slotextend( int n, void **p ) static int memmanage_slotextend( int n, void **p )
{ {
int size_grown; int size_grown;
int movement; int movement;
size_grown = MinimumWorkingSize - (buffer_end + buffer_offset - n); size_grown = MinimumWorkingSize - (buffer_end + buffer_offset - n);
if ( size_grown > 0 ) if ( size_grown > 0 )
{ {
/* /*
Not enough room in current slot, so try to extend Not enough room in current slot, so try to extend
If fail to extend then can't satisfy request If fail to extend then can't satisfy request
*/ */
buffer_end += extend_application_slot( size_grown ); buffer_end += extend_application_slot( size_grown );
if ( buffer_end + buffer_offset - n < MinimumWorkingSize )
return 0;
if ( application_max_size < (int)(buffer_base_address + buffer_offset + buffer_end) - 0x8000 ) if ( buffer_end + buffer_offset - n < MinimumWorkingSize )
application_max_size = (int)(buffer_base_address + buffer_offset + buffer_end) - 0x8000; return 0;
}
if ( buffer_bottom + buffer_offset >= n ) if ( application_max_size < (int)(buffer_base_address + buffer_offset + buffer_end) - 0x8000 )
{ application_max_size = (int)(buffer_base_address + buffer_offset + buffer_end) - 0x8000;
/* }
Already enough room below used section - no action necessary
*/
}
else if ( buffer_bottom + buffer_offset + buffer_end - buffer_top >= n )
{
/*
Enough room in unused space, but not enough room below
used section so move used section of buffer up
to make room.
*/
memmove( buffer_base_address + n,
buffer_base_address + buffer_bottom + buffer_offset,
buffer_top - buffer_bottom );
movement = n - (buffer_offset + buffer_bottom); if ( buffer_bottom + buffer_offset >= n )
buffer_end -= movement; {
buffer_offset += movement; /*
} Already enough room below used section - no action necessary
else */
{ }
/* else if ( buffer_bottom + buffer_offset + buffer_end - buffer_top >= n )
Not enough room in the available slot - try to extend {
*/ /*
size_grown = n - (buffer_bottom + buffer_offset + buffer_end - buffer_top); Enough room in unused space, but not enough room below
used section so move used section of buffer up
to make room.
*/
memmove( buffer_base_address + n,
buffer_base_address + buffer_bottom + buffer_offset,
buffer_top - buffer_bottom );
movement = n - (buffer_offset + buffer_bottom);
buffer_end -= movement;
buffer_offset += movement;
}
else
{
/*
Not enough room in the available slot - try to extend
*/
size_grown = n - (buffer_bottom + buffer_offset + buffer_end - buffer_top);
(void)grow_buffer( &size_grown ); (void)grow_buffer( &size_grown );
memmove( buffer_base_address + n, memmove( buffer_base_address + n,
buffer_base_address + buffer_bottom + buffer_offset, buffer_base_address + buffer_bottom + buffer_offset,
buffer_end + buffer_offset - n ); buffer_end + buffer_offset - n );
movement = n - (buffer_offset + buffer_bottom); movement = n - (buffer_offset + buffer_bottom);
buffer_end -= movement; buffer_end -= movement;
buffer_offset += movement; buffer_offset += movement;
if ( buffer_top > buffer_end ) if ( buffer_top > buffer_end )
{ {
buffer_top = buffer_end; buffer_top = buffer_end;
truncate_overhanging_files(); truncate_overhanging_files();
}
} }
}
*p = buffer_base_address; *p = buffer_base_address;
buffer_base_address += n; buffer_base_address += n;
buffer_offset -= n; buffer_offset -= n;
return n; return n;
} }
/***************************************************************** /*****************************************************************
...@@ -812,113 +815,101 @@ Below here is the external interface stuff ...@@ -812,113 +815,101 @@ Below here is the external interface stuff
/* /*
Set the slot size to that passed. Set the slot size to that passed.
Return an error if the wimp_slotsize failed or the slot size Return an error if the wimp_slotsize failed or the slot size
obtained is less than that requested. obtained is less than that requested.
*/ */
void action_slot( int size ) void action_slot( int size )
{ {
int size_change = size - application_current_size(); int size_change = size - application_current_size();
#ifdef debugmem debugmem(( "action_slot: by %d to %d\n", size_change, size ));
dprintf( "Change slot by %d to %d\n", size_change, size );
#endif
if ( size_change > 0 ) if ( size_change > 0 )
{ {
/*
Grow slot
*/
buffer_end += extend_application_slot( size_change );
}
else if ( size_change < 0 )
{
/*
Shrink slot
*/
/*
Lower-bound size change to ensure we still have MinimumWorkingSize
*/
if ( buffer_end + buffer_offset + size_change < MinimumWorkingSize )
size_change = MinimumWorkingSize - buffer_end - buffer_offset;
if ( buffer_top > buffer_end + size_change )
{
/*
Ensure the data is at the bottom of the buffer area
*/
#ifdef debugmem
dprintf( "Base=%#010x, offset=%d, bottom=%d, top=%d, end=%d\n", (int)buffer_base_address, buffer_offset, buffer_bottom, buffer_top, buffer_end );
#endif
memmove(
buffer_base_address,
buffer_base_address + buffer_bottom + buffer_offset,
buffer_top - buffer_bottom );
buffer_end += buffer_bottom + buffer_offset;
buffer_offset -= buffer_bottom + buffer_offset;
}
size_change = extend_application_slot( size_change );
/*
Adjust buffer_end by actual amount changed by
*/
buffer_end += size_change;
/*
Upper bound buffer_top by buffer_end
*/
if ( buffer_top > buffer_end )
buffer_top = buffer_end;
}
truncate_overhanging_files();
application_max_size = (int)(buffer_base_address + buffer_offset + buffer_end) - 0x8000;
#ifdef debugmem
dprintf( "Application max size is now %d\n", application_max_size );
dprintf( "Base=%#010x, offset=%d, bottom=%d, top=%d, end=%d\n", (int)buffer_base_address, buffer_offset, buffer_bottom, buffer_top, buffer_end );
#endif
}
/*
Initialise to end in suitable place for closedown
*/
os_error *init_memmanagement( void )
{
/* /*
Things that use real memory ( base = null ) Grow slot
*/
buffer_end += extend_application_slot( size_change );
}
else if ( size_change < 0 )
{
/*
Shrink slot
*/ */
chain_initialise_header( &files_chain );
/* /*
This determins the maximum size we will allow buffer Lower-bound size change to ensure we still have MinimumWorkingSize
allocation to grow to. This starts at the
current next slot size, then gets adjusted when the
user drags the memory slider
*/ */
application_max_size = current_next_slot(); if ( buffer_end + buffer_offset + size_change < MinimumWorkingSize )
size_change = MinimumWorkingSize - buffer_end - buffer_offset;
if ( buffer_top > buffer_end + size_change )
{
/*
Ensure the data is at the bottom of the buffer area
*/
debugmem(( "action_slot: Base=%#010x, offset=%d, bottom=%d, top=%d, end=%d\n", (int)buffer_base_address, buffer_offset, buffer_bottom, buffer_top, buffer_end ));
memmove(
buffer_base_address,
buffer_base_address + buffer_bottom + buffer_offset,
buffer_top - buffer_bottom );
buffer_end += buffer_bottom + buffer_offset;
buffer_offset -= buffer_bottom + buffer_offset;
}
size_change = extend_application_slot( size_change );
/* /*
The buffer area Adjust buffer_end by actual amount changed by
*/ */
buffer_base_address = (char *)(application_current_size() + 0x8000); buffer_end += size_change;
buffer_offset = 0;
buffer_bottom = 0;
buffer_top = 0;
buffer_end = 0;
/* /*
A cludge to stop memory size dragging from oscillating Upper bound buffer_top by buffer_end
about a non-memory block size boundary.
*/ */
last_requested_size = -1; if ( buffer_top > buffer_end )
buffer_top = buffer_end;
}
source_of_finished_file = NULL; truncate_overhanging_files();
(void)_kernel_register_slotextend( memmanage_slotextend ); application_max_size = (int)(buffer_base_address + buffer_offset + buffer_end) - 0x8000;
debugmem(( "action_slot: app max size %d\n", application_max_size ));
debugmem(( "action_slot: Base=%#010x, offset=%d, bottom=%d, top=%d, end=%d\n", (int)buffer_base_address, buffer_offset, buffer_bottom, buffer_top, buffer_end ));
}
return NULL; /*
Initialise to end in suitable place for closedown
*/
os_error *init_memmanagement( void )
{
/*
Things that use real memory ( base = null )
*/
chain_initialise_header( &files_chain );
/*
This determines the maximum size we will allow buffer
allocation to grow to. This starts at the
current next slot size, then gets adjusted when the
user drags the memory slider
*/
application_max_size = current_next_slot();
/*
The buffer area
*/
buffer_base_address = (char *)(application_current_size() + 0x8000);
buffer_offset = 0;
buffer_bottom = 0;
buffer_top = 0;
buffer_end = 0;
finished_obj_source_name = NULL;
(void)_kernel_register_slotextend( memmanage_slotextend );
return NULL;
} }
/* /*
...@@ -933,47 +924,47 @@ os_error *init_memmanagement( void ) ...@@ -933,47 +924,47 @@ os_error *init_memmanagement( void )
os_error *init_for_copying( void ) os_error *init_for_copying( void )
{ {
#if Timing #if Timing
copytime = clock(); copytime = clock();
#endif #endif
src_block_size = InitialBlockSize; src_block_size = InitialBlockSize;
dest_block_size = InitialBlockSize; dest_block_size = InitialBlockSize;
timing_init(); timing_init();
if ( buffer_ensure( MinimumWorkingSize ) ) if ( buffer_ensure( MinimumWorkingSize ) )
{ {
if ( application_max_size < application_current_size() ) if ( application_max_size < application_current_size() )
application_max_size = application_current_size(); application_max_size = application_current_size();
return NULL; return NULL;
} }
else else
{ {
return error( mb_slotsize_too_small ); /* was mb_malloc_failed */ return error( mb_slotsize_too_small ); /* was mb_malloc_failed */
} }
} }
/* /*
Misc. ESSENTIAL tidying up: Misc. ESSENTIAL tidying up:
Close down any open files Close down any open files
*/ */
void closedown_memmanagement( void ) void closedown_memmanagement( void )
{ {
chain_link *link; chain_link *link;
files_header *fh; files_header *fh;
for ( link = files_chain.forwards; link->forwards; link = link->forwards ) for ( link = files_chain.forwards; link->forwards; link = link->forwards )
{ {
fh = chain_link_Wrapper( link ); fh = chain_link_Wrapper( link );
ensure_files_closed( fh ); ensure_files_closed( fh );
} }
#if Timing #if Timing
copytime = clock() - copytime; copytime = clock() - copytime;
werr(0, "time taken for file copy = %d.%02ds", copytime/100, copytime%100); werr(0, "time taken for file copy = %d.%02ds", copytime/100, copytime%100);
#endif #endif
#ifdef debug #ifdef debug
#ifdef debugfile #ifdef debugfile
if ( debugf != NULL ) fclose( debugf ); if ( debugf != NULL ) fclose( debugf );
#endif #endif
#endif #endif
} }
...@@ -981,774 +972,779 @@ void closedown_memmanagement( void ) ...@@ -981,774 +972,779 @@ void closedown_memmanagement( void )
/* /*
Add a file to the end of the files chain Add a file to the end of the files chain
*/ */
os_error *add_file_to_chain( char *destination, char *source, int size, int reload, int execute, int attributes, int objecttype, int forceit, int *i_am_full ) os_error *add_file_to_chain( char *destination, char *source,
uint32_t size, int reload, int execute, int attributes, int objecttype,
BOOL forceit, BOOL *i_am_full
#ifdef USE_PROGRESS_BAR
, uint32_t progress, void **ref
#endif
)
{ {
files_header *fh; files_header *fh;
fh = overflowing_malloc( sizeof( files_header ));
if ( fh )
{
fh->source_filename = overflowing_malloc( strlen( source ) + 1 );
fh = overflowing_malloc( sizeof( files_header )); if ( fh->source_filename )
if ( fh )
{ {
fh->source_filename = overflowing_malloc( strlen( source ) + 1 ); fh->destination_filename = overflowing_malloc( strlen( destination ) + 1 );
if ( fh->source_filename ) if ( fh->destination_filename )
{ {
fh->destination_filename = overflowing_malloc( strlen( destination ) + 1 ); /*
Initialise the structure
if ( fh->destination_filename ) */
{ strcpy( fh->source_filename, source );
/* fh->source_file_handle = 0;
Initialise the structure strcpy( fh->destination_filename, destination );
*/ fh->destination_file_handle = 0;
strcpy( fh->source_filename, source ); fh->size = size;
fh->source_file_handle = 0; fh->reload = reload;
strcpy( fh->destination_filename, destination ); fh->execute = execute;
fh->destination_file_handle = 0; fh->attributes = attributes;
fh->size = size; fh->objecttype = objecttype;
fh->reload = reload; fh->forceit = forceit;
fh->execute = execute; fh->read_to = 0;
fh->attributes = attributes; fh->written_to = 0;
fh->objecttype = objecttype; fh->write_state = write_not_started;
fh->forceit = forceit; fh->start_of_buffer = 0;
fh->read_to = 0;
fh->written_to = 0; #ifdef USE_PROGRESS_BAR
fh->write_state = write_not_started; fh->total_progress = progress / 2;
fh->start_of_buffer = 0; fh->write_progress = fh->read_progress = fh->total_progress;
if (ref != NULL) *ref = fh;
/* debugmem(( "add_file_to_chain: %s type %d progress %08x\n", destination, objecttype, fh->total_progress ));
link to backwards end of files chain #endif
*/
chain_insert_before_header( &fh->link, fh, &files_chain ); /*
link to backwards end of files chain
*i_am_full = No; */
chain_insert_before_header( &fh->link, fh, &files_chain );
return NULL;
} *i_am_full = No;
overflowing_free( fh->source_filename );
}
overflowing_free( fh ); return NULL;
}
overflowing_free( fh->source_filename );
} }
*i_am_full = Yes; overflowing_free( fh );
}
/* *i_am_full = Yes;
one of the heap_allocs failed
*/ /*
return error( mb_malloc_failed ); one of the heap_allocs failed
*/
return error( mb_malloc_failed );
} }
os_error *read_a_block( int *i_am_full, int *need_another_file, int *that_finished_a_file )
#ifdef USE_PROGRESS_BAR
void modify_chain_file_progress(void *ref, uint32_t progress)
{ {
files_header *fh; files_header *fh = (files_header *)ref;
os_regset r;
os_error *err;
os_gbpbstr gbpbplace;
int size_needed;
int t;
*i_am_full = No; if (fh != NULL)
*that_finished_a_file = No; {
debugmem(( "\nmodify chain: %s %x\n", fh->destination_filename, progress ));
fh->write_progress = fh->total_progress = progress;
}
}
#endif
fh = next_fh_to_read();
if ( !fh ) /* Modified to return the progress value of the finished file */
{ os_error *read_a_block( BOOL *i_am_full, BOOL *need_another_file, BOOL *that_finished_a_file, uint32_t *progress )
*need_another_file = Yes; {
files_header *fh;
os_regset r;
os_error *err;
os_gbpbstr gbpbplace;
int size_needed;
uint32_t start_read_to;
clock_t t;
return NULL; *i_am_full = No;
} *that_finished_a_file = No;
*need_another_file = No; fh = next_fh_to_read();
#ifdef debugmem if ( !fh )
dprintf( "read_a_block from %s\n", fh->source_filename ); {
#endif *need_another_file = Yes;
return NULL;
}
*need_another_file = No;
debugmem(( "read_a_block: from %s\n", fh->source_filename ));
start_read_to = fh->read_to;
/*
If we have to do some reading
*/
if ( fh->read_to < fh->size )
{
debugmem(( "R" ));
/* /*
If we have to do some reading Work out how much buffer is needed...
*/ */
if ( fh->read_to < fh->size )
/*
Upper bound to src_block_size and amount to read in file
*/
if ( fh->size - fh->read_to > src_block_size )
{ {
#ifdef debugmem size_needed = src_block_size;
dprintf( "R" ); }
#endif else
/* {
Work out how much buffer is needed... /* This calculation fits in a signed integer provided src_block_size < 2G */
*/ size_needed = fh->size - fh->read_to;
}
/* /*
Upper bound to src_block_size and amount to read in file Ensure word-alignment of file ptr and buffer address
*/ equal, to ensure DMA operation on DMA-capable disc
if ( fh->size - fh->read_to > src_block_size ) systems (eg Iyonix ADFS).
{ */
size_needed = src_block_size; if ( fh->read_to == fh->written_to &&
} (buffer_top & 3) != (fh->read_to & 3) )
else {
{ int pad = ((fh->read_to & 3) - (buffer_top & 3)) & 3;
size_needed = fh->size - fh->read_to; *i_am_full = grow_buffer( &pad );
} if ( pad <= 0)
return NULL;
buffer_top += pad;
}
/*
Enlarge the buffer (if possible)
*/
*i_am_full = grow_buffer( &size_needed );
/* if ( size_needed <= 0 )
Ensure word-alignment of file ptr and buffer address return NULL;
equal, to ensure DMA operation on DMA-capable disc
systems (eg Iyonix ADFS).
*/
if ( fh->read_to == fh->written_to &&
(buffer_top & 3) != (fh->read_to & 3) )
{
int pad = ((fh->read_to & 3) - (buffer_top & 3)) & 3;
*i_am_full = grow_buffer( &pad );
if ( pad <= 0)
return NULL;
buffer_top += pad;
}
/*
Enlarge the buffer (if possible)
*/
*i_am_full = grow_buffer( &size_needed );
if ( size_needed <= 0 ) /*
return NULL; Set up new buffer
*/
if ( fh->read_to == fh->written_to )
{
fh->start_of_buffer = buffer_top;
}
/* /*
Set up new buffer Sub-optimal case: read file in chunks
*/
if ( fh->read_to == fh->written_to )
{
fh->start_of_buffer = buffer_top;
}
#if 0 If the file isn't open yet, then open it
/* Using OS_GBPB is faster if the file is already open */ */
/* if ( fh->source_file_handle == 0 )
If haven't already started on the open-gbpb-close sequence AND {
file size fits into buffer allowed debugmem(( "O" ));
*/ r.r[0] = open_read | open_nopath | open_nodir | open_mustopen;
if ( fh->read_to == 0 && fh->size <= size_needed ) r.r[1] = (int)fh->source_filename;
{
/*
If were reading by blocks, but now decided its OK to read by whole file
*/
if ( fh->source_file_handle )
close_file( &fh->source_file_handle );
/*
optimal read case: enough ram to read whole file
*/
fileplace.action = 16; /* load file */
fileplace.name = fh->source_filename;
fileplace.loadaddr = (int)(buffer_base_address + buffer_offset + fh->start_of_buffer);
fileplace.execaddr = 0;
err = os_file( &fileplace );
if ( err )
return err;
fh->read_to = fh->size;
buffer_top += fh->size;
}
else
#endif
{
/*
Sub-optimal case: read file in chunks
If the file isn't open yet, then open it
*/
if ( fh->source_file_handle == 0 )
{
#ifdef debugmem
dprintf( "O" );
#endif
r.r[0] = 0x4f;
r.r[1] = (int)fh->source_filename;
err = os_find( &r ); err = os_find( &r );
if ( err ) if ( err )
return err; return err;
fh->source_file_handle = r.r[0]; fh->source_file_handle = r.r[0];
} }
t = clock(); t = clock();
/* /*
Read a block into the buffer. Read a block into the buffer.
*/ */
gbpbplace.action = 3; /* read bytes from file at position */ gbpbplace.action = OSGBPB_ReadFromGiven;
gbpbplace.file_handle = fh->source_file_handle; gbpbplace.file_handle = fh->source_file_handle;
gbpbplace.data_addr = buffer_base_address + buffer_offset + buffer_top; gbpbplace.data_addr = buffer_base_address + buffer_offset + buffer_top;
gbpbplace.number = size_needed; gbpbplace.number = size_needed;
gbpbplace.seq_point = fh->read_to; gbpbplace.seq_point = fh->read_to;
#ifdef debugmem debugmem(( "read_a_block: buf %x + %u [%u-%u]\n", buffer_base_address, buffer_offset,
dprintf( "r(%d,%d<-%d)", gbpbplace.data_addr, gbpbplace.number, gbpbplace.seq_point ); buffer_bottom, buffer_top ));
#endif debugmem(( "read_a_block: (%d,%d<-%d)\n", gbpbplace.data_addr, gbpbplace.number, gbpbplace.seq_point ));
err = os_gbpb( &gbpbplace ); err = os_gbpb( &gbpbplace );
if ( err ) if ( err )
return err; return err;
fh->read_to += size_needed; fh->read_to += size_needed;
buffer_top += size_needed; buffer_top += size_needed;
if (src_block_size == size_needed) if (src_block_size == size_needed)
{ /* only time full block transfers */ { /* only time full block transfers */
t = clock() - t; t = clock() - t;
if ( timing_accumulating(timing_Reading) ) if ( timing_accumulating(timing_Reading) )
{ /* accumulating initial timings */ { /* accumulating initial timings */
assert(src_block_size == InitialBlockSize); assert(src_block_size == InitialBlockSize);
timing_accumulate(timing_Reading, t, src_block_size); timing_accumulate(timing_Reading, t, src_block_size);
} }
else if (time_quanta < MaxTimeQuanta) else if (time_quanta < MaxTimeQuanta)
{ {
if ( (src_block_size <= SmallBlockSize) if ( (src_block_size <= SmallBlockSize)
&& timing_poorrate(timing_Reading, t, src_block_size) ) && timing_poorrate(timing_Reading, t, src_block_size) )
{ /* if the transfer rate is suffering at this small blocksize, { /* if the transfer rate is suffering at this small blocksize,
* increase time_quanta to cause the blocksize to grow */ * increase time_quanta to cause the blocksize to grow */
if (time_quanta < MaxTimeQuanta) time_quanta *= 2; if (time_quanta < MaxTimeQuanta) time_quanta *= 2;
#ifdef debugmem debugmem(( "read_a_block: time_quanta to %d\n", time_quanta));
dprintf("change time_quanta to %d\n", time_quanta);
#endif
}
if ( t < time_quanta - TimeQuantaHysteresis) src_block_size = grow( src_block_size );
if ( t > time_quanta + TimeQuantaHysteresis) src_block_size = shrink( src_block_size );
}
}
if ( fh->read_to >= fh->size )
{
#ifdef debugmem
dprintf( "C" );
#endif
err = close_file( &fh->source_file_handle );
if ( err )
return err;
}
} }
if ( t < time_quanta - TimeQuantaHysteresis) src_block_size = grow( src_block_size );
if ( t > time_quanta + TimeQuantaHysteresis) src_block_size = shrink( src_block_size );
}
} }
/*
If we've finished reading the file
*/
if ( fh->read_to >= fh->size ) if ( fh->read_to >= fh->size )
{ {
*that_finished_a_file = Yes; debugmem(( "C" ));
err = close_file( &fh->source_file_handle );
/* if ( err )
If there isn't another file to read, tell the client about return err;
it now.
*/
if ( next_fh_to_read() == NULL )
*need_another_file = Yes;
} }
}
#ifdef debugmem /*
dprintf( "X\n" ); If we've finished reading the file
#endif */
if ( fh->read_to >= fh->size )
{
*that_finished_a_file = Yes;
return NULL; #ifdef USE_PROGRESS_BAR
*progress = fh->read_progress;
#else
IGNORE(progress);
#endif
/*
If there isn't another file to read, tell the client about
it now.
*/
if ( next_fh_to_read() == NULL )
*need_another_file = Yes;
#ifdef USE_PROGRESS_BAR
}
else
{
uint64_t p;
uint32_t b;
b = fh->read_to - start_read_to; /* bytes read this time */
p = (fh->total_progress * (uint64_t)b) / fh->size;
fh->read_progress -= (uint32_t) p;
*progress = (uint32_t) p;
debugmem(( "partial read: %u bytes / %u = %08x progress\n", b, fh->size, *progress ));
#endif
}
debugmem(( "X\n" ));
return NULL;
} }
void skip_file_read( void ) void skip_file_read( void )
{ {
skip_file( next_fh_to_read() ); skip_file( next_fh_to_read() );
} }
static os_error *int_write_a_block( int *i_am_empty, int *that_finished_a_file ) static os_error *int_write_a_block( BOOL *i_am_empty, BOOL *that_finished_a_file, uint32_t *progress )
{ {
os_gbpbstr gbpbplace; os_gbpbstr gbpbplace;
os_filestr fileplace; os_filestr fileplace;
files_header *fh; files_header *fh;
os_regset r; os_regset r;
os_error *err = NULL; os_error *err = NULL;
int amount_to_write; int amount_to_write;
int t; uint32_t start_written_to;
static int dont_set_dir_info; clock_t t;
static BOOL dont_set_dir_info = No;
*i_am_empty = No;
*that_finished_a_file = No; *i_am_empty = No;
*that_finished_a_file = No;
/*
no more files to write?
*/
if ( !files_chain.forwards->forwards )
{
*i_am_empty = Yes;
/* return NULL;
no more files to write? }
*/
if ( !files_chain.forwards->forwards )
{
*i_am_empty = Yes;
return NULL;
}
fh = chain_link_Wrapper( files_chain.forwards );
#ifdef debugmem fh = chain_link_Wrapper( files_chain.forwards );
dprintf( "int_write_a_block to %s\n", fh->destination_filename );
#endif
/* debugmem(( "int_write_a_block to %s\n", fh->destination_filename ));
no more buffer to write when there's more file to write?
*/
if ( fh->objecttype != ObjectType_Directory &&
fh->read_to - fh->written_to == 0 &&
fh->written_to < fh->size )
{
*i_am_empty = Yes;
return NULL;
}
#ifdef debugmem /*
dprintf( "W" ); no more buffer to write when there's more file to write?
#endif */
if ( fh->objecttype != object_directory &&
fh->read_to - fh->written_to == 0 &&
fh->written_to < fh->size )
{
*i_am_empty = Yes;
/* return NULL;
amount_to_write is lesser of a dest_block_size and the amount buffered of the file }
*/
if ( fh->read_to - fh->written_to > dest_block_size ) start_written_to = fh->written_to;
debugmem(( "W" ));
/*
amount_to_write is lesser of a dest_block_size and the amount buffered of the file
*/
if ( fh->read_to - fh->written_to > dest_block_size )
{
amount_to_write = dest_block_size;
}
else
{
/* This calculation fits in a signed integer provided dest_block_size < 2G */
amount_to_write = fh->read_to - fh->written_to;
}
while ( !err &&
( fh->write_state == write_not_started ||
fh->write_state == write_f_tried_unlock ||
fh->write_state == write_f_tried_cdirs ||
fh->write_state == write_f_tried_both ))
{
if ( fh->objecttype == object_directory )
{ {
amount_to_write = dest_block_size; debugmem(( "D" ));
/*
Start up directory
*/
err = create_directory( fh->destination_filename );
if ( !err )
fh->write_state = dont_set_dir_info ?
write_adjust_access :
write_adjust_info;
} }
else else
{ {
amount_to_write = fh->read_to - fh->written_to; /*
} Start up file (or partition)
*/
if ( fh->size <= amount_to_write )
{
debugmem(( "S" ));
/*
Optimised case - try save
*/
fileplace.action = OSFile_Save;
fileplace.name = fh->destination_filename;
fileplace.loadaddr = fh->reload;
fileplace.execaddr = fh->execute;
fileplace.start = (int)(buffer_base_address + buffer_offset + fh->start_of_buffer);
fileplace.end = fileplace.start + fh->size;
while ( !err && err = os_file( &fileplace );
( fh->write_state == write_not_started ||
fh->write_state == write_f_tried_unlock ||
fh->write_state == write_f_tried_cdirs ||
fh->write_state == write_f_tried_both ))
{
if ( fh->objecttype == ObjectType_Directory )
{
#ifdef debugmem
dprintf( "D" );
#endif
/*
Start up directory
*/
err = create_directory( fh->destination_filename );
if ( !err )
fh->write_state = dont_set_dir_info ?
write_adjust_access :
write_adjust_info;
}
else
{
/*
Start up file (or partition)
*/
if ( fh->size <= amount_to_write )
{
#ifdef debugmem
dprintf( "S" );
#endif
/*
Optimised case - try save
*/
fileplace.action = 0; /* save file */
fileplace.name = fh->destination_filename;
fileplace.loadaddr = fh->reload;
fileplace.execaddr = fh->execute;
fileplace.start = (int)(buffer_base_address + buffer_offset + fh->start_of_buffer);
fileplace.end = fileplace.start + fh->size;
err = os_file( &fileplace );
if ( !err )
{
fh->written_to = fh->size;
fh->start_of_buffer += fh->size;
buffer_bottom += fh->size;
fh->write_state = write_adjust_access;
}
}
else
{
#ifdef debugmem
dprintf( "c" );
#endif
/*
Sub-optimal case - open, GBPB, close
*/
err = create_file_dead( fh->destination_filename, fh->size );
if ( !err )
{
fh->write_state = write_openit;
}
}
}
if ( err ) if ( !err )
{ {
if ( (err->errnum & FileError_Mask) == ErrorNumber_Locked && fh->written_to = fh->size;
fh->forceit && fh->start_of_buffer += fh->size;
fh->write_state != write_f_tried_unlock && buffer_bottom += fh->size;
fh->write_state != write_f_tried_both )
{
/*
We haven't tried unlocking yet - give it a go
*/
fileplace.action = 4; /* set file attributes */
fileplace.name = fh->destination_filename;
fileplace.end = 3; /* owner read/write */
os_file( &fileplace ); /* ignore any error back */
err = NULL;
if ( fh->write_state == write_not_started )
fh->write_state = write_f_tried_unlock;
else if ( fh->write_state == write_f_tried_cdirs )
fh->write_state = write_f_tried_both;
}
else if ( ((err->errnum & FileError_Mask) == ErrorNumber_NotFound ||
err->errnum == ErrorNumber_CantOpenFile) &&
fh->write_state != write_f_tried_cdirs &&
fh->write_state != write_f_tried_both )
{
/*
We haven't tried cdirs yet - give it a go
*/
err = ensure_file_directories( fh->destination_filename );
if ( !err )
{
/*
no error - try openning/saveing again, but don't retry cdirs on fail
*/
if ( fh->write_state == write_not_started )
fh->write_state = write_f_tried_cdirs;
else if ( fh->write_state == write_f_tried_unlock )
fh->write_state = write_f_tried_both;
}
}
}
}
if ( !err && fh->write_state == write_openit ) fh->write_state = write_adjust_access;
{ }
#ifdef debugmem }
dprintf( "O" ); else
#endif {
debugmem(( "c" ));
/* /*
Open it up. The file has been successfully created if we're here, so Sub-optimal case - open, GBPB, close
any failures at this point are bad news.
*/ */
r.r[0] = 0xcf; /* open up and give an error if directory or not exists */ err = create_file_dead( fh->destination_filename, fh->size );
r.r[1] = (int)fh->destination_filename;
err = os_find( &r );
if ( !err ) if ( !err )
{ {
fh->write_state = write_truncateopen; fh->write_state = write_openit;
fh->destination_file_handle = r.r[0];
} }
}
} }
if ( !err && fh->write_state == write_truncateopen ) if ( err )
{ {
#ifdef debugmem if ( (err->errnum & FileError_Mask) == ErrorNumber_Locked &&
dprintf( "T" ); fh->forceit &&
#endif fh->write_state != write_f_tried_unlock &&
fh->write_state != write_f_tried_both )
{
/* /*
Once the file's open set its extent to 0. This We haven't tried unlocking yet - give it a go
prevents FileSwitch loading before update on
blocks of the file.
*/ */
r.r[0] = 3; /* set extent */ fileplace.action = OSFile_WriteAttr;
r.r[1] = (int)fh->destination_file_handle; fileplace.name = fh->destination_filename;
r.r[2] = 0; /* to 0 */ fileplace.end = read_attribute | write_attribute;
err = os_args( &r ); os_file( &fileplace ); /* ignore any error back */
err = NULL;
if ( fh->write_state == write_not_started )
fh->write_state = write_f_tried_unlock;
else if ( fh->write_state == write_f_tried_cdirs )
fh->write_state = write_f_tried_both;
}
else if ( ((err->errnum & FileError_Mask) == ErrorNumber_NotFound ||
err->errnum == ErrorNumber_CantOpenFile) &&
fh->write_state != write_f_tried_cdirs &&
fh->write_state != write_f_tried_both )
{
/*
We haven't tried cdirs yet - give it a go
*/
err = ensure_file_directories( fh->destination_filename );
if ( !err ) if ( !err )
{ {
fh->write_state = write_blocks; /*
no error - try opening/saving again, but don't retry cdirs on fail
*/
if ( fh->write_state == write_not_started )
fh->write_state = write_f_tried_cdirs;
else if ( fh->write_state == write_f_tried_unlock )
fh->write_state = write_f_tried_both;
} }
}
} }
}
if ( !err && fh->write_state == write_blocks ) if ( !err && fh->write_state == write_openit )
{
debugmem(( "O" ));
/*
Open it up. The file has been successfully created if we're here, so
any failures at this point are bad news.
*/
r.r[0] = open_update | open_nopath | open_nodir | open_mustopen;
r.r[1] = (int)fh->destination_filename;
err = os_find( &r );
if ( !err )
{ {
/* fh->write_state = write_truncateopen;
Write a block out fh->destination_file_handle = r.r[0];
*/ }
gbpbplace.action = 1; /* write bytes at location */ }
gbpbplace.file_handle = fh->destination_file_handle;
gbpbplace.data_addr = buffer_base_address + buffer_offset + fh->start_of_buffer;
gbpbplace.number = amount_to_write;
gbpbplace.seq_point = fh->written_to;
#ifdef debugmem
dprintf( "w(%d,%d->%d)", (int)gbpbplace.data_addr, gbpbplace.number, gbpbplace.seq_point );
#endif
t = clock(); if ( !err && fh->write_state == write_truncateopen )
{
debugmem(( "T" ));
/*
Once the file's open set its extent to 0. This
prevents FileSwitch loading before update on
blocks of the file.
*/
r.r[0] = OSArgs_SetEXT;
r.r[1] = (int)fh->destination_file_handle;
r.r[2] = 0; /* to 0 */
err = os_gbpb( &gbpbplace ); err = os_args( &r );
if ( !err ) if ( !err )
{ {
if (dest_block_size == amount_to_write) fh->write_state = write_blocks;
{ /* only time full block transfers */
t = clock() - t;
if ( timing_accumulating(timing_Writing) )
{ /* accumulating initial timings */
assert(dest_block_size == InitialBlockSize);
timing_accumulate(timing_Writing, t, dest_block_size);
}
else
{
if ( (dest_block_size <= SmallBlockSize)
&& timing_poorrate(timing_Writing, t, dest_block_size) )
{ /* if the transfer rate is suffering at this small blocksize,
* increase time_quanta to cause the blocksize to grow */
if (time_quanta < MaxTimeQuanta) time_quanta *= 2;
#ifdef debugmem
dprintf( "change time_quanta to %d\n", time_quanta );
#endif
}
if ( t < time_quanta - TimeQuantaHysteresis) dest_block_size = grow( dest_block_size );
if ( t > time_quanta + TimeQuantaHysteresis) dest_block_size = shrink( dest_block_size );
}
}
fh->written_to += amount_to_write;
fh->start_of_buffer += amount_to_write;
buffer_bottom += amount_to_write;
if ( fh->written_to >= fh->size )
fh->write_state = write_closeit;
}
} }
}
if ( !err && fh->write_state == write_closeit ) if ( !err && fh->write_state == write_blocks )
{ {
#ifdef debugmem /*
dprintf( "C" ); Write a block out
#endif */
err = close_file( &fh->destination_file_handle ); gbpbplace.action = OSGBPB_WriteAtGiven;
gbpbplace.file_handle = fh->destination_file_handle;
gbpbplace.data_addr = buffer_base_address + buffer_offset + fh->start_of_buffer;
gbpbplace.number = amount_to_write;
gbpbplace.seq_point = fh->written_to;
/* debugmem(( "int_write_a_block: buf %x + %d [%d-%d]\n", buffer_base_address, buffer_offset,
Regardless of whether the close worked, the file will be closed, buffer_bottom, buffer_top ));
so always move onto adjusting the file's info debugmem(( "int_write_a_block: w(%d,%u->%u)", (int)gbpbplace.data_addr, gbpbplace.number, gbpbplace.seq_point ));
*/
fh->write_state = write_adjust_info;
}
if ( !err && fh->write_state == write_adjust_info ) t = clock();
{
#ifdef debugmem
dprintf( "I" );
#endif
/*
Always adjust the info as its almost always wrong
*/
err = write_catalogue_information(
fh->destination_filename,
fh->reload,
fh->execute,
fh->attributes );
if ( err && fh->objecttype == ObjectType_Directory) err = os_gbpb( &gbpbplace );
if ( !err )
{
if (dest_block_size == amount_to_write)
{ /* only time full block transfers */
t = clock() - t;
if ( timing_accumulating(timing_Writing) )
{ /* accumulating initial timings */
assert(dest_block_size == InitialBlockSize);
timing_accumulate(timing_Writing, t, dest_block_size);
}
else
{ {
/* Some FS's can't do this for a directory - back if ( (dest_block_size <= SmallBlockSize)
off to just doing the access permission. && timing_poorrate(timing_Writing, t, dest_block_size) )
*/ { /* if the transfer rate is suffering at this small blocksize,
err = NULL; * increase time_quanta to cause the blocksize to grow */
dont_set_dir_info = 1; if (time_quanta < MaxTimeQuanta) time_quanta *= 2;
fh->write_state = write_adjust_access; debugmem(( "int_write_a_block: time_quanta to %d\n", time_quanta ));
}
if ( t < time_quanta - TimeQuantaHysteresis) dest_block_size = grow( dest_block_size );
if ( t > time_quanta + TimeQuantaHysteresis) dest_block_size = shrink( dest_block_size );
} }
else if ( !err ) }
fh->write_state = write_all_done; fh->written_to += amount_to_write;
fh->start_of_buffer += amount_to_write;
buffer_bottom += amount_to_write;
if ( fh->written_to >= fh->size )
fh->write_state = write_closeit;
} }
}
if ( !err && fh->write_state == write_adjust_access ) if ( !err && fh->write_state == write_closeit )
{ {
#ifdef debugmem debugmem(( "C" ));
dprintf( "A" ); err = close_file( &fh->destination_file_handle );
#endif
/*
Only adjust attributes if they're non-default ones
*/
err = write_attributes(
fh->destination_filename,
fh->attributes );
if ( !err ) /*
fh->write_state = write_all_done; Regardless of whether the close worked, the file will be closed,
} so always move onto adjusting the file's info
*/
fh->write_state = write_adjust_info;
}
if ( !err && fh->write_state == write_all_done ) if ( !err && fh->write_state == write_adjust_info )
{ {
*that_finished_a_file = Yes; debugmem(( "I" ));
/*
Always adjust the info as it's almost always wrong
*/
err = write_catalogue_information(
fh->destination_filename,
fh->reload,
fh->execute,
fh->attributes );
remove_file_from_chain(); if ( err && fh->objecttype == object_directory)
{
/* Some FS's can't do this for a directory - back
off to just doing the access permission.
*/
err = NULL;
dont_set_dir_info = Yes;
fh->write_state = write_adjust_access;
} }
else if ( !err )
fh->write_state = write_all_done;
}
#ifdef debugmem if ( !err && fh->write_state == write_adjust_access )
dprintf( "X\n" ); {
#endif debugmem(( "A" ));
/*
Only adjust attributes if they're non-default ones
*/
err = write_attributes(
fh->destination_filename,
fh->attributes );
if ( !err )
fh->write_state = write_all_done;
}
return err; if ( !err && fh->write_state == write_all_done )
{
*that_finished_a_file = Yes;
#ifdef USE_PROGRESS_BAR
*progress = fh->write_progress;
#else
IGNORE(progress);
#endif
remove_file_from_chain();
#ifdef USE_PROGRESS_BAR
}
else
{
uint64_t p;
uint32_t b;
b = fh->written_to - start_written_to;
p = (fh->total_progress * (uint64_t)b) / fh->size;
fh->write_progress -= (uint32_t) p;
*progress = (uint32_t) p;
debugmem(( "partial write: %u bytes / %u = %08x progress\n", b, fh->size, *progress ));
#endif
}
debugmem(( "X\n" ));
return err;
} }
os_error *write_a_block( int *i_am_empty, int *that_finished_a_file )
os_error *write_a_block( BOOL *i_am_empty, BOOL *that_finished_a_file, uint32_t *progress )
{ {
os_error *err = int_write_a_block( i_am_empty, that_finished_a_file ); os_error *err = int_write_a_block( i_am_empty, that_finished_a_file, progress );
if ( *i_am_empty ) if ( *i_am_empty )
{ {
buffer_end += buffer_offset; buffer_end += buffer_offset;
buffer_offset = buffer_bottom = buffer_top = 0; buffer_offset = buffer_bottom = buffer_top = 0;
} }
return err; return err;
} }
void skip_file_write( void ) void skip_file_write( void )
{ {
if ( files_chain.forwards->forwards ) if ( files_chain.forwards->forwards )
{ {
skip_file( chain_link_Wrapper( files_chain.forwards )); skip_file( chain_link_Wrapper( files_chain.forwards ));
} }
} }
char *next_file_to_be_written( void ) char *next_file_to_be_written( void )
{ {
files_header *fh; files_header *fh;
if ( files_chain.forwards->forwards ) if ( files_chain.forwards->forwards )
{ {
fh = chain_link_Wrapper( files_chain.forwards ); fh = chain_link_Wrapper( files_chain.forwards );
return fh->destination_filename; return fh->destination_filename;
} }
else else
{ {
return NULL; return NULL;
} }
} }
char *next_file_to_be_read( void ) char *next_file_to_be_read( void )
{ {
files_header *fh = next_fh_to_read(); files_header *fh = next_fh_to_read();
if ( fh != NULL ) if ( fh != NULL )
return fh->source_filename; return fh->source_filename;
else else
return NULL; return NULL;
} }
void restart_file_read( void ) void restart_file_read( void )
{ {
files_header *fh = next_fh_to_read(); files_header *fh = next_fh_to_read();
#ifdef debugmem debugmem(( "restart_file_read: fh=&08X\n", (int)fh ));
dprintf( "restart_file_read: fh=&08X\n", (int)fh );
#endif
if ( fh != NULL ) if ( fh != NULL )
{ {
ensure_files_closed( fh ); ensure_files_closed( fh );
buffer_top -= fh->read_to; buffer_top -= fh->read_to;
if ( buffer_top < 0 ) buffer_bottom = buffer_top = buffer_offset = 0; if ( buffer_top < 0 ) buffer_bottom = buffer_top = buffer_offset = 0;
fh->read_to = 0; fh->read_to = 0;
fh->written_to = 0; fh->written_to = 0;
fh->write_state = write_not_started; fh->write_state = write_not_started;
} }
} }
void restart_file_write( void ) void restart_file_write( void )
{ {
files_header *fh = chain_link_Wrapper( files_chain.forwards ); files_header *fh = chain_link_Wrapper( files_chain.forwards );
#ifdef debugmem debugmem(( "restart_file_write: fh=&08X\n", (int)fh ));
dprintf( "restart_file_write: fh=&08X\n", (int)fh );
#endif if ( fh != NULL )
{
if ( fh != NULL ) /* Only restart file if we still have all of its contents so far.
* If we don't then we can't just read from the start because we might
* overwrite another file's data so just do nothing (== retry).
*/
int file_start = fh->start_of_buffer - fh->written_to;
if ( file_start >= 0 )
{ {
/* Only restart file if we still have all of its contents so far. ensure_files_closed( fh );
* If we don't then we can't just read from the start because we might fh->start_of_buffer = file_start;
* overwrite another file's data so just do nothing (== retry). buffer_bottom -= fh->written_to;
*/ fh->written_to = 0;
int file_start = fh->start_of_buffer - fh->written_to; fh->write_state = write_not_started;
if ( file_start >= 0 ) debugmem(( "restart_file_write: start_of_buffer=%08X, buffer_bottom=%08X\n", fh->start_of_buffer, buffer_bottom ));
{
ensure_files_closed( fh );
fh->start_of_buffer = file_start;
buffer_bottom -= fh->written_to;
fh->written_to = 0;
fh->write_state = write_not_started;
#ifdef debugmem
dprintf( "restarting write: start_of_buffer=%08X, buffer_bottom=%08X\n", fh->start_of_buffer, buffer_bottom );
#endif
}
} }
}
} }
int bytes_left_to_read( void ) uint32_t bytes_left_to_read( void )
{ {
files_header *fh = next_fh_to_read(); files_header *fh = next_fh_to_read();
if ( fh ) if ( fh )
{ {
return fh->size - fh->read_to; return fh->size - fh->read_to;
} }
else else
{ {
return 0; return 0;
} }
} }
int bytes_left_to_write( void ) uint32_t bytes_left_to_write( void )
{ {
files_header *fh; files_header *fh;
if ( files_chain.forwards->forwards ) if ( files_chain.forwards->forwards )
{ {
fh = chain_link_Wrapper( files_chain.forwards ); fh = chain_link_Wrapper( files_chain.forwards );
return fh->size - fh->written_to; return fh->size - fh->written_to;
} }
else else
{ {
return 0; return 0;
} }
} }
void copy_go_faster( int do_it ) void copy_go_faster( BOOL do_it )
{ {
if ( do_it ) if ( do_it )
{ {
/* /*
Go faster Go faster
*/ */
time_quanta = MaxTimeQuanta; /* centi-seconds */ time_quanta = MaxTimeQuanta; /* centi-seconds */
minimum_block_size = 15*1024; /* bytes: optimised for econet */ minimum_block_size = 15*1024; /* bytes: optimised for econet */
if ( src_block_size < minimum_block_size ) if ( src_block_size < minimum_block_size )
src_block_size = minimum_block_size; src_block_size = minimum_block_size;
if ( dest_block_size < minimum_block_size ) if ( dest_block_size < minimum_block_size )
dest_block_size = minimum_block_size; dest_block_size = minimum_block_size;
} }
else else
{ {
/* /*
Go slower Go slower
*/ */
time_quanta = NominalTimeQuanta; time_quanta = NominalTimeQuanta;
minimum_block_size = 512; minimum_block_size = 512;
} }
} }
...@@ -15,11 +15,9 @@ ...@@ -15,11 +15,9 @@
/* /*
Header file for initialise.c Header file for initialise.c
*/ */
#define wimp_MFilerSelectionDirectory 0x403 #define wimp_MFilerSelectionDirectory ((wimp_msgaction)0x403)
#define wimp_MFilerAddSelection 0x404 #define wimp_MFilerAddSelection ((wimp_msgaction)0x404)
#define wimp_MFilerAction 0x405 #define wimp_MFilerAction ((wimp_msgaction)0x405)
#define wimp_MFilerControlAction 0x406 #define wimp_MFilerControlAction ((wimp_msgaction)0x406)
#define wimp_MSETSLOT 0x400c5
os_error *initialise( action_environment *env, int argc, char *argv[] ); os_error *initialise( action_environment *env, int argc, char *argv[] );
...@@ -19,18 +19,18 @@ ...@@ -19,18 +19,18 @@
#define OPTIONS_H #define OPTIONS_H
/* The faster button appears on the main window */ /* The faster button appears on the main window */
#define UseFasterButton #define USE_FASTER_BUTTON
/* Are we using very long numbers in the boxes ? */ /* Use commas in the numbers */
#define USE_LONG_LONG
/* (only if long numbers) use commas in the numbers */
#define USE_COMMAS #define USE_COMMAS
/* Can we drag things to the window to perform more operations */ /* Percent complete estimate shown */
/* #define USE_LOAD_OPERATIONS */ #define USE_PROGRESS_BAR
/* Show completion in the title too */
#define USE_STATUS_IN_TITLE
/* Don't exempt some things - testing all */ /* Change dialogue box to red when fault occurs */
/* #define CONFIRM_MEANS_CONFIRM_ALL */ #undef USE_RED_ERROR
#endif #endif
...@@ -82,82 +82,83 @@ typedef struct ...@@ -82,82 +82,83 @@ typedef struct
typedef struct action_environment typedef struct action_environment
{ {
/* Current position in list of files in */ /* Current position in list of files in */
search_handle test_search; search_handle test_search;
/* wimplib handle onto the dialogue box */ /* wimplib handle onto the dialogue box */
dbox status_box; dbox status_box;
/* handle onto menu */ /* wimp handle of the window */
menu option_menu; int window_handle;
/* information regarding showing/hiding box in a delayed fashion */ /* handle onto menu */
int time_to_boxchange; menu option_menu;
int boxchange_direction;
/* numeric quantities for progress lines */ /* information regarding showing/hiding box in a delayed fashion */
#ifdef USE_LONG_LONG clock_t time_to_boxchange;
uintmax_t top_progress; int boxchange_direction;
uintmax_t bottom_progress;
#else
unsigned int top_progress;
unsigned int bottom_progress;
#endif
/* current overall operation (copying/counting/deleting etc) */ /* numeric quantities for progress lines */
actions_possible operation; uint64_t top_progress;
uint64_t bottom_progress;
#ifdef USE_PROGRESS_BAR
uint32_t progress;
#endif
/* next thing to try: next file; read some; set type of file etc */ /* current overall operation (copying/counting/deleting etc) */
next_action_state action; actions_possible operation;
/* new parameters for files (only used when relevant) */ /* next thing to try: next file; read some; set type of file etc */
int new_access; next_action_state action;
int new_type;
/* Things to happen when user presses a button */ /* new parameters for files (only used when relevant) */
button_actions button_actions; int new_access;
int new_type;
/* text on top line of info box */ /* Things to happen when user presses a button */
char *current_info; button_actions button_actions;
char *current_info_token;
/* used when counting finishes */ /* text on top line of info box */
char *selection_summary; char *current_info;
char *current_info_token;
/* infomation for copying files */ /* used when counting finishes */
char *destination_name; char *selection_summary;
int source_directory_name_length;
/* Record of locked files not deleted */ /* infomation for copying files */
int locked_not_deleted; char *destination_name;
int source_directory_name_length;
/* Mask to use when setting access on directories for NetFS (KLUDGE) */ /* Record of locked files not deleted */
int directory_access_setting_mask; uint32_t locked_not_deleted;
/* these indicate which switches apply */ /* Mask to use when setting access on directories for NetFS (KLUDGE) */
int verbose:1; uint32_t directory_access_setting_mask;
int confirm:1;
int force:1;
int access:1;
int looknewer:1;
int faster:1;
int faster_stuff_hidden:1;
/* indicates an error state */ /* these indicate which switches apply */
int in_error:1; int verbose:1;
int confirm:1;
int force:1;
int access:1;
int looknewer:1;
int faster:1;
int faster_stuff_hidden:1;
/* this flags that flexing memory has started */ /* indicates an error state */
int flex_memory:1; int in_error:1;
/* this flags that flexible memory is not needed */ /* this flags that flexing memory has started */
int disable_flex:1; int flex_memory:1;
/* this flags that a disc full error has already been notified */ /* this flags that flexible memory is not needed */
int disc_full_already:1; int disable_flex:1;
/* this flags that we are ignoring CVS files in Copy and CopyLocal */ /* this flags that a disc full error has already been notified */
int auto_skip_cvs:1; int disc_full_already:1;
} action_environment;
/* this flags that we are ignoring CVS files in Copy and CopyLocal */
int auto_skip_cvs:1;
} action_environment;
BOOL message_event_handler( wimp_eventstr *event, void *environment ); BOOL message_event_handler( wimp_eventstr *event, void *environment );
void option_menu_handler( action_environment *env, char *hit ); void option_menu_handler( action_environment *env, char *hit );
...@@ -167,23 +168,24 @@ void switch_to_reading( action_environment * ); ...@@ -167,23 +168,24 @@ void switch_to_reading( action_environment * );
void switch_to_writing( action_environment * ); void switch_to_writing( action_environment * );
void show_faster_stuff( action_environment *env ); void show_faster_stuff( action_environment *env );
void toggle_faster( action_environment *env ); void toggle_faster( action_environment *env );
extern void set_top_info_field_with_current_info(action_environment *env, char *token1, char *token2);
extern char *last_top_info_field; extern const char *last_top_info_field;
extern action_environment env; extern action_environment env;
extern int __root_stack_size; extern int __root_stack_size;
/* /*
Delays for displaying verbose box and removing non-verbose box Delays for displaying verbose box and removing non-verbose box
in 1/100ths of a second in 1/100ths of a second
*/ */
#define Display_Delay 0 #define Display_Delay 0
#define Remove_Delay 200 #define Remove_Delay 200
/* /*
Dialogue box fields Dialogue box fields
*/ */
#define Top_Info_Field 1
#define Bottom_Info_Path 2 #define Bottom_Info_Path 2
#define Top_Progress_Field 3 #define Top_Progress_Field 3
#define Bottom_Progress_Field 4 #define Bottom_Progress_Field 4
...@@ -195,11 +197,15 @@ extern int __root_stack_size; ...@@ -195,11 +197,15 @@ extern int __root_stack_size;
#define Misc_Button 10 #define Misc_Button 10
#define Skip_Button 11 #define Skip_Button 11
#define Error_Field 12 #define Error_Field 12
#define Bottom_Info_Leaf 15
#define Progress_Bar 16
#define Progress_Bar_BBox 15
/* 1 less than the space allocated for the icon's indirected string */
#define Top_Info_Field_Length 79
/* /*
Window names Window names
*/ */
#define Main_Window "FCount" #define MAIN_TEMPLATE_NAME "FCount"
#define QUERY_TEMPLATE_NAME "query"
#define Info_Field_Length 64
...@@ -14,10 +14,4 @@ ...@@ -14,10 +14,4 @@
*/ */
/* Big numbers in dboxes */ /* Big numbers in dboxes */
#include "Options.h" void dbox_setlongnumeric(dbox d, dbox_field f, uint64_t n);
#ifdef USE_LONG_LONG
void dbox_setlongnumeric(dbox d, dbox_field f, uintmax_t n);
#else
#define dbox_setlongnumeric(x,y,z) dbox_setnumeric(x,y,z);
#endif
...@@ -17,29 +17,30 @@ ...@@ -17,29 +17,30 @@
*/ */
#ifndef debug #ifndef debug
#ifdef debugtube #ifdef debugtube
#define debug #define debug
#else #else
#ifdef debugfile #ifdef debugfile
#define debug #define debug
#endif #endif
#endif #endif
#endif #endif
#ifdef debug #ifdef debug
#include "werr.h" #include "werr.h"
#define assert( e ) ((e) ? (void)0 : werr(1, "assert failed: '%s' in file %s at line %d", #e, __FILE__, __LINE__)) extern void dprintf( const char *str, ... );
#ifdef debugfile #ifdef debugfile
extern FILE *debugf; extern FILE *debugf;
#endif #endif
extern void dprintf( const char *str, ... ); #define IGNORE(x) (void)(x)
#define assert( e ) ((e) ? (void)0 : werr(1, "assert failed: '%s' in file %s at line %d", #e, __FILE__, __LINE__))
#else #else
#define IGNORE(x) (void)(x)
#define assert( ignore ) #define assert( ignore )
#endif #endif