/* Copyright 1996 Acorn Computers Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* Control the Filer's action window. This code compilers into a relocatable module which controls the Filer's action window. 0.00 08-May-89 JSR Copied from allfiles - a 'list all files matching pattern' utility. 0.01 09-May-89 JSR Incorporate into a wimp interface. 0.02 12-May-89 JSR Change into being a module. 0.03 31-May-89 JSR Change into being Filer Action Window. 0.04 20-Jun-89 JSR First round of bug fixes: Delete deletes a few before asking Setting access change of title Immediate display on verbose Force verbose on count Implement copy Local Implement FilerControlAction Handle pre-quit message Change button name Quiet instead of Quick Add stamp option Return directories when copying to ensure access etc gets set for them Init dboxquery for quit handling 0.05 29-Jun-89 JSR Bug fixes from FilerAct 0.01 release: Restart does not quit before writing out reread stuff. Handle help requests 0.06 04-Jul-89 JSR Remove const from strings. Do unsigned comparison of low 4 bytes of date stamp. 0.07 29-Sep-89 JSR Use overflowing_ memory allocation routines. Treat directories as being unstamped. Set time for doing doings to be twice that time already taken to do one doing, bounded to between Minimum_Doings_Time and Maximum_Doings_Time If an error happened when setting the access to enable a delete which failed, then report the access setting error, not the delete error. Make the top progress field keep up with the info field better when writing. Use standard module application generating wrapper to fix ctrl-shft-f12 bug. Display a summary of what was counted. Add find file. Fix handling of translation of rename into a copy-move for the first directory. Extend the functionality of copylocal to cope with non-leaf destinations. Adjust meaning of set access to allow 'leave alone' on access bits 0.08 16-Oct-89 JSR Correct setting of bottom info field to not overflow its fixed buffer when a long leaf name is encountered. Correct error handling so that skip is present. Reporting of locked errors whilst deleting improved. Only allow found directories to be opened. Only wimpt_complain on the first disc full. 0.09 19-Oct-89 JSR Don't switch to Open buttons when found directory is an application. Add control_action 2 to hide an operation Verbose applies to count Set window titles to conform to RISC_OS style. 0.10 13-Nov-89 JSR Ensure overflowing_free is used when next_nodename is used. Internationalise the text. 0.11 17-Nov-89 JSR Declare action_environment as being file global in scope. Previously the declaration of the function type button_function was assumed to do this, but it doesn't. Split into several parts. Fix bug whereby in set_bottom_info_field a small poo was purpetrated as the nul string terminator overflowed newfield. 0.12 04-Dec-89 JSR Add the Bad_RENAME case on failed rename. Relock un renamed locked files when force is on. Already exists errors on renames mapped to copy-moves. For NetFS owner write bit masked out on set acceses on directories (CLUDGE!). 0.13 10-Jan-90 JSR Set the bottom info field at the end of counting as during counting. Routines used locally only made static. Set the title of the query box on a prequit message to match that of the action window itself. 0.14 22-Jan-90 JSR Inhibit delete progress if a locked file isn't deleted. 0.22 16-Aug-91 PJC If start_operation fails, use werr rather than wimpt_noerr 0.30 05-Nov-93 SMC No longer uses red error text in error version of filer action window. */ #if 0 #define debugact #endif #include #include #include #include #include /* AMcC 22-Jul-94 include swis.h rather than arthur.h !! */ #include "swis.h" #include "os.h" #include "wimp.h" #include "wimpt.h" #include "werr.h" #include "win.h" #include "res.h" #include "resspr.h" #include "template.h" #include "msgs.h" #include "event.h" #include "dbox.h" #include "dboxquery.h" #include "flex.h" #include "heap.h" #include "bbc.h" #include "allerrs.h" #include "malloc+.h" #include "listfiles.h" #include "memmanage.h" #include "actionwind.h" #include "Initialise.h" #include "Buttons.h" #include "debug.h" #define Option_FilerAction_Verbose 0x00000001 #define Option_FilerAction_Confirm 0x00000002 #define Option_FilerAction_Force 0x00000004 #define Option_FilerAction_Newer 0x00000008 #define Option_FilerAction_Recurse 0x00000010 /* AMcC: 22-Jul-94 - Shouldn't be defined here * #define FilerAction_SendSelectedDirectory 0x88000 * #define FilerAction_SendSelectedFile 0x88001 * #define FilerAction_SendStartOperation 0x88002 */ #define FileChar_ManyAny '*' #define FileChar_Any '#' #define FileSystemNumber_NetFS 5 #define HELP_MESSAGE_CONTROL_NOBUTTON "1" #define HELP_MESSAGE_CONTROL "2" #define QUERY_TEMPLATE_NAME "query" /* A chain link structure */ typedef struct chain_link { struct chain_link *forwards; struct chain_link *backwards; /* somewhere to point at the structure in which this resides */ void *wrapper; } chain_link; typedef struct { chain_link link; char *buffer; } buffer_header; /* For c.modulewrap */ extern os_error *i_am_now_active( void ); #define Yes 1 #define No 0 #define Max_Invocation_Name_Length 20 /* AMcC: 22-Jul-94 - defined in swis.h * #define OS_ExitAndDie 0x50 */ /* * Field masks for date stamping */ #define DateStamped_Mask 0xfff00000 #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 */ action_environment env = {}; char *last_top_info_field = NULL; static int doings_time = (10*CLK_TCK)/100; #define Number_Of_Actions 10 #define Number_Of_Icon_Strings 5 #define Title_Text 0 #define Top_Progress_Line_Text 1 #define Bottom_Progress_Line_Text 2 #define Top_Info_Field_Text 3 #define Help_Message_Operation_Fillin 4 static char *icon_strings[ Number_Of_Actions ][ Number_Of_Icon_Strings ] = { /* title top progress bottom progress top info help action */ { "29", "30", "31", "32", "33" }, /* copying */ { "34", "30", "35", "36", "37" }, /* moving (renaming) */ { "38", "39", "40", "41", "42" }, /* deleting */ { "43", "44", "45", "46", "47" }, /* setting access */ { "48", "49", "50", "51", "52" }, /* settype */ { "53", "54", "55", "56", "57" }, /* count */ { "34", "30", "58", "32", "37" }, /* copy/moving */ { "29", "30", "31", "32", "33" }, /* copy local */ { "59", "60", "61", "62", "63" }, /* stamp */ { "64", "65", "66", "67", "68" } /* find */ }; static int show_when_faster[ Number_Of_Actions ][2] = { /* top progress bottom progress action */ { No, Yes }, /* copying */ { No, Yes }, /* moving (renaming) */ { Yes, Yes }, /* deleting */ { Yes, Yes }, /* setting access */ { Yes, Yes }, /* settype */ { No, No }, /* count */ { No, Yes }, /* copy/moving */ { No, Yes }, /* copy local */ { Yes, Yes }, /* stamp */ { Yes, No } /* find */ }; static char *action_prompt[] = { "69", "70", "71", "72", "73", "74", "75", "76", "77", "78" }; /* Establish a delayed switch on/off for the dbox. Delay is in centiseconds */ /*static*/ void switch_dbox_on_off( action_environment *env, int direction, int delay ) { env->time_to_boxchange = clock() + (delay * CLK_TCK)/100; env->boxchange_direction = direction; } /* a is wild b isn't */ static int caseless_wildcmp( const char *a, const char *b ) { int last_wildrover = -1; /* first wild char after last wildcard */ int last_realrover = -1; /* first real char after wildcard in this test sequence */ int wild_rover = 0; int real_rover = 0; int d; while ( (a[wild_rover] || b[real_rover]) ) { switch( a[wild_rover] ) { case FileChar_ManyAny: last_wildrover = ++wild_rover; /* Carry on after * in wildcard string */ 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 */ real_rover = ++last_realrover; /* test one character on */ } else { wild_rover++; real_rover++; } break; } } 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 */ static void set_bottom_info_field( action_environment *env, char *text ) { char *leaf; if ( text == NULL ) return; /* Split text into path and leafname */ leaf = strrchr( text, '.' ); if ( leaf != NULL ) { leaf += 1; if ( leaf - text > Info_Field_Length ) { 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 ) { dbox_setfield( env->status_box, Bottom_Info_Path, newpath ); dbox_setfield( env->status_box, Bottom_Info_Leaf, newleaf ); } } static void set_top_progress_field( action_environment *env, int value ) { env->top_progress = value; if ( !env->faster || show_when_faster[ env->operation ][ 0 ] ) dbox_setnumeric( env->status_box, Top_Progress_Field, value ); } static void switch_box_to_error( action_environment *env, os_error *err ) { wimp_openstr o; template *tplt = template_find( Main_Window ); int xw; int yw; dbox_setfield( env->status_box, Error_Field, err->errmess ); o.w = dbox_syshandle( env->status_box ); o.x = -tplt->window.ex.x0; o.y = -tplt->window.ex.y1; o.box = tplt->window.ex; o.behind = -1; 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 ); xw = xw/2 - (o.box.x1 + o.box.x0)/2; yw = yw/2 - (o.box.y1 + o.box.y0)/2; o.box.x0 += xw; o.box.y0 += yw; o.box.x1 += xw; o.box.y1 += yw; wimpt_noerr( wimp_open_wind( &o )); } static void switch_box_from_error( action_environment *env ) { wimp_wstate s; template *tplt = template_find( Main_Window ); int xw; int yw; 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); yw = (s.o.box.y1 - s.o.y) - (tplt->window.box.y1 - tplt->window.scy); s.o.x = tplt->window.scx; s.o.y = tplt->window.scy; s.o.box.x0 = tplt->window.box.x0 + xw; s.o.box.y0 = tplt->window.box.y0 + yw; s.o.box.x1 = tplt->window.box.x1 + xw; s.o.box.y1 = tplt->window.box.y1 + yw; wimpt_noerr( wimp_open_wind( &s.o )); } void switch_to_reading( action_environment *env ) { env->current_info = msgs_lookup( "32" ); env->current_info_token = "32"; set_bottom_info_field( env, next_file_to_be_read()); set_top_progress_field( env, bytes_left_to_read()); env->action = Check_Full_Reading; } /* Acknowledge a message */ static os_error *ack_message( wimp_eventstr *event ) { event->data.msg.hdr.your_ref = event->data.msg.hdr.my_ref; return wimp_sendmessage( wimp_EACK, &event->data.msg, event->data.msg.hdr.task ); } static int menus_greyed[ 3 ][ 5 ] = { { No, No, No, No, No }, { No, No, No, No, Yes }, { No, Yes, No, Yes, Yes } }; typedef enum {none, name, access, type } destination_type; typedef enum {mt_all, mt_notcopy, mt_information } menu_type; static struct start_up_details_str { int init_for_copy:1; destination_type dest; int return_dirs_last:1; int return_dirs_first:1; int recurse:1; int disable_flex:1; /* stops flex being enabled later */ int flex_now:1; /* is flex going now? */ int partition_is_directory:1; /* for listfiles - is a partition a dir or file */ menu_type men; } start_up_details[ 10 ] = { /* copy dest last? first? recurse no flex flex P==D? menu action */ { Yes, name, No, Yes, Yes, No, Yes, No, mt_all }, /* copying */ { No, name, No, Yes, No, No, No, No, mt_all }, /* moving (rename) */ { No, none, Yes, Yes, Yes, Yes, No, No, mt_notcopy }, /* deleting */ { No, access, No, Yes, Yes, Yes, No, Yes, mt_notcopy }, /* setting access */ { No, type, No, Yes, No, Yes, No, No, mt_notcopy }, /* settype */ { No, none, No, No, Yes, Yes, No, No, mt_information }, /* count */ { Yes, name, Yes, Yes, Yes, No, Yes, No, mt_all }, /* copying/moving */ { Yes, name, No, Yes, Yes, No, Yes, No, mt_all }, /* copy local */ { No, none, No, Yes, Yes, Yes, Yes, Yes, mt_notcopy }, /* stamp */ { No, name, No, Yes, Yes, Yes, Yes, Yes, mt_information } /* find */ }; static void reflect_menu_flags( action_environment *env ) { menu_setflags( env->option_menu, 1, env->faster, menus_greyed[ start_up_details[ env->operation ].men ][ 0 ] ); menu_setflags( env->option_menu, 2, env->confirm, menus_greyed[ start_up_details[ env->operation ].men ][ 1 ] ); menu_setflags( env->option_menu, 3, env->verbose, menus_greyed[ start_up_details[ env->operation ].men ][ 2 ] ); menu_setflags( env->option_menu, 4, env->force, menus_greyed[ start_up_details[ env->operation ].men ][ 3 ] ); menu_setflags( env->option_menu, 5, env->looknewer, menus_greyed[ start_up_details[ env->operation ].men ][ 4 ] ); } /* Operation has been specified, start doing it */ static os_error *start_operation( action_environment *env, actions_possible operation, int options, void *auxilliary_information ) { os_error *err; env->operation = 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 ] )); win_settitle( dbox_syshandle( env->status_box ), msgs_lookup( icon_strings[ operation ][ Title_Text ] )); env->top_progress = 0; env->bottom_progress = 0; dbox_setnumeric( env->status_box, Top_Progress_Field, env->top_progress ); dbox_setnumeric( env->status_box, Bottom_Progress_Field, env->bottom_progress ); 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; env->looknewer = (options & Option_FilerAction_Newer) != 0; env->disc_full_already = No; switch_buttons( env, &abort_pause_buttons ); if ( env->verbose ) { switch_dbox_on_off( env, 1, Display_Delay ); } env->current_info = msgs_lookup( icon_strings[ operation ][ Top_Info_Field_Text ] ); env->current_info_token = icon_strings[operation][Top_Info_Field_Text]; env->action = Next_File; if ( start_up_details[ env->operation ].init_for_copy ) { err = init_for_copying(); if ( err ) return err; } switch( start_up_details[ env->operation ].dest ) { case none: break; case name: /* 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: env->new_access = *(int *)auxilliary_information; break; case type: env->new_type = *(int *)auxilliary_information; #ifdef debugact dprintf( "new type is %d\n", env->new_type ); #endif break; default: break; } 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 ); 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_Counting: err = selection_summary( env->test_search, &env->selection_summary ); if ( err ) return err; /* drop through into... */ case Action_Finding: env->confirm = No; /* 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; env->locked_not_deleted = 0; break; case Action_Setting_Access: { os_regset r; 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 ); if ( err || first_nodename == NULL ) break; r.r[0] = 13; /* lookup FS */ r.r[1] = (int) first_nodename; r.r[2] = 0; /* truncate on . or : etc */ err = os_swix( OS_FSControl, &r ); 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 ); return NULL; } static void go_verbose( action_environment *env ) { wimp_wstate state; if ( wimp_get_wind_state( dbox_syshandle( env->status_box ), &state ) ) return; dbox_showstatic( env->status_box ); state.o.behind = -1; if ( wimp_open_wind( &state.o ) ) return; env->verbose = Yes; env->boxchange_direction = 0; } static void go_terse( action_environment *env ) { env->verbose = No; env->boxchange_direction = 0; if ( (event_getmask() & wimp_EMNULL) == 0 ) { dbox_hide( env->status_box ); } } /* Control the action in progress */ static void control_action( action_environment *env, wimp_eventstr *event ) { switch ( event->data.msg.data.words[0] ) { case 0: /* Acknowledge the message */ ack_message( event ); break; case 1: /* show window and bring it to the front */ go_verbose( env ); break; case 2: /* Turn verbose off - hide the window */ go_terse( env ); break; default: /* Do nothing implicitely */ break; } } /* Message processor */ BOOL message_event_handler( wimp_eventstr *event, void *environment ) { action_environment *env = environment; BOOL processed = No; switch( event->e ) { case wimp_ESEND: case wimp_ESENDWANTACK: processed = Yes; switch( event->data.msg.hdr.action ) { case wimp_MPREQUIT: { /* 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 */ 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( dboxquery( query_message ) ) { case dboxquery_YES: #ifdef debugact dprintf("Discard selected\n"); #endif if (!(size_of_prequit > sizeof(wimp_msghdr) && flags_of_prequit & 1)) { wimp_get_caret_pos( &event->data.key.c ); event->data.key.chcode = 0x1fc; /* ctrl/shft/f12 */ wimp_sendmessage( wimp_EKEY, (wimp_msgstr *)&event->data, sender ); #ifdef debugact 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: #ifdef debugact dprintf( "Slot(%d,%d) - T=%d\n", event->data.msg.data.words[0],event->data.msg.data.words[1], wimpt_task() ); #endif if ( !env->disable_flex ) { if ( event->data.msg.data.words[1] == wimpt_task() ) { if ( env->flex_memory && event->data.msg.data.words[0] >= 0 ) { action_slot( event->data.msg.data.words[0] ); } wimpt_noerr( ack_message( event )); } else { processed = No; } } break; case wimp_MHELPREQUEST: event->data.msg.hdr.your_ref = event->data.msg.hdr.my_ref; event->data.msg.hdr.action = wimp_MHELPREPLY; event->data.msg.hdr.size = 256; /* enough for all messages */ switch( event->data.msg.data.helprequest.m.i ) { case Abort_Button: case No_Skip_Button: case Yes_Retry_Button: 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; 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; case wimp_MFilerAddSelection: { 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; void *auxilliary_information; action = (actions_possible)event->data.msg.data.words[ 0 ]; options = event->data.msg.data.words[ 1 ]; auxilliary_information = &event->data.msg.data.words[ 2 ]; err = start_operation( env, action, options, auxilliary_information ); if (err) werr(TRUE, err->errmess); } break; case wimp_MFilerControlAction: control_action( env, event ); break; default: processed = No; break; } break; } return processed; } static void hide_faster_stuff( action_environment *env ) { if ( env->faster && !env->faster_stuff_hidden ) { dbox_setfield( env->status_box, Bottom_Info_Path, "" ); dbox_setfield( env->status_box, Bottom_Info_Leaf, "" ); if ( !show_when_faster[ env->operation ][ 0 ] ) dbox_setfield( env->status_box, Top_Progress_Field, "-" ); if ( !show_when_faster[ env->operation ][ 1 ] ) dbox_setfield( env->status_box, Bottom_Progress_Field, "-" ); env->faster_stuff_hidden = Yes; } } void show_faster_stuff( action_environment *env ) { if ( env->faster_stuff_hidden ) { dbox_setfield( env->status_box, Bottom_Info_Path, newpath ); dbox_setfield( env->status_box, Bottom_Info_Leaf, newleaf ); if ( !show_when_faster[ env->operation ][ 0 ] ) dbox_setnumeric( env->status_box, Top_Progress_Field, env->top_progress ); if ( !show_when_faster[ env->operation ][ 1 ] ) { char buf[20]; sprintf(buf,"%u",env->bottom_progress); dbox_setfield( env->status_box, Bottom_Progress_Field, buf ); } env->faster_stuff_hidden = No; } } void option_menu_handler( action_environment *env, char *hit ) { switch( hit[0] ) { case 1: /* faster */ env->faster = !env->faster; copy_go_faster( env->faster ); if ( env->faster ) { doings_time = CLK_TCK; /* 1 second */ hide_faster_stuff( env ); } else { doings_time = (10*CLK_TCK)/100; /* 1/10 second */ show_faster_stuff( env ); } break; case 2: /* confirm */ env->confirm = !env->confirm; break; case 3: /* verbose */ if ( env->verbose ) go_terse( env ); else go_verbose( env ); break; case 4: /* force */ env->force = !env->force; break; case 5: /* newer */ env->looknewer = !env->looknewer; break; default: break; } reflect_menu_flags( env ); } void switch_to_writing( action_environment *env ) { env->current_info = msgs_lookup( "82" ); env->current_info_token = "82"; set_bottom_info_field( env, next_file_to_be_written()); set_top_progress_field( env, bytes_left_to_write()); env->action = Check_Empty_Writing; } /* Create the destination file name from the source */ static os_error *create_destination_localfile( action_environment *env, char *source, char **destination ) { char *sourcegunge; char *sourceleaf = source + env->source_directory_name_length + 1; char *destleaf; char *temp; /* This takes source = and dest = making destn = or dest = making destn = */ /* sourcegunge points to the stuff past the source leaf (which is one of the selected items). */ if ( strchr( sourceleaf, '.' ) == 0 ) { sourcegunge = source + strlen( source ); } else { 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 ) { /* 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 ) return error( mb_malloc_failed ); strncpy( *destination, source, env->source_directory_name_length + 1 ); sprintf( *destination + env->source_directory_name_length + 1, "%s%s", env->destination_name, sourcegunge ); } return NULL; } /* Create the destination file name from the source */ static os_error *create_destination_filename( action_environment *env, char *source, char **destination ) { *destination = overflowing_malloc( strlen( source ) - env->source_directory_name_length + strlen( env->destination_name ) + 1 ); if ( !*destination ) return error( mb_malloc_failed ); sprintf( *destination, "%s%s", env->destination_name, &source[ env->source_directory_name_length ] ); return NULL; } /* Add next file to read list */ static os_error *test_add_to_read_list( action_environment *env, int *should_be_added ) { char *destination; char *source; os_filestr fileplace; os_error *err; int source_reload; int destination_reload; 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 )); } 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 ) != ObjectType_Directory ) { /* Get the destination's information */ fileplace.action = 5; /* read catalogue information */ fileplace.name = destination; err = os_file( &fileplace ); /* If an error happened which wasn't 'not found' then return with that error. 'not found' means datestamp checking need not happen. */ if ( err ) { if ( ( err->errnum & FileError_Mask ) != ErrorNumber_NotFound ) { overflowing_free( source ); overflowing_free( destination ); return err; } } 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( source ); *should_be_added = Yes; return NULL; } /* This actually adds the next file to the read list. */ static void add_to_read_list( action_environment *env, int *i_am_full ) { char *destination; 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, 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 ); overflowing_free( source ); switch_to_reading( env ); } /* Record more top progress */ static void more_top_progress( action_environment *env, int change ) { env->top_progress += change; set_top_progress_field( env, env->top_progress ); } /* 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 ] ) { char buf[20]; sprintf(buf,"%u",env->bottom_progress); dbox_setfield( env->status_box, Bottom_Progress_Field, buf ); } } /* Get the access of a file */ static os_error *get_access_to_file( char *filename, int *access ) { os_error *err; os_filestr fileplace; fileplace.action = 5; /* get file attributes */ fileplace.name = filename; err = os_file( &fileplace ); *access = fileplace.end; return err; } /* Set the access to any file */ static os_error *set_access_to_file( char *filename, int access ) { os_filestr fileplace; fileplace.action = 4; /* set file attributes */ fileplace.name = filename; fileplace.end = access; return os_file( &fileplace ); } /* Attempt to delete a node */ static os_error *delete_node(char *name) { os_filestr fileplace; fileplace.action = 6; /* delete object */ fileplace.name = name; return os_file( &fileplace ); } /* Set the access of next node */ static os_error *set_access( action_environment *env, int access ) { char *filename; os_error *err; err = next_nodename( env->test_search, &filename ); if ( err ) return err; err = set_access_to_file( filename, access ); overflowing_free( filename ); return err; } /* Stamp any file */ static os_error *stamp_file( char *filename ) { os_filestr fileplace; fileplace.action = 9; /* stamp file */ fileplace.name = filename; return os_file( &fileplace ); } /* Stamp next node */ static os_error *stamp( action_environment *env ) { char *filename; os_error *err; err = next_nodename( env->test_search, &filename ); if ( err ) return err; err = stamp_file( filename ); overflowing_free( filename ); return err; } /* Do a rename */ static os_error *riscos_rename( action_environment *env ) { os_error *err; os_regset r; char *source; char *destination; int should_be_added; test_add_to_read_list(env, &should_be_added); wimpt_noerr( next_nodename( env->test_search, &source )); if (!should_be_added) return 0; wimpt_noerr( create_destination_filename( env, source, &destination )); #ifdef debugact dprintf("riscos_rename: src = %s, dest = %s\n",source,destination); #endif r.r[0] = 25; /* rename */ r.r[1] = (int)source; r.r[2] = (int)destination; err = os_swix( OS_FSControl, &r ); overflowing_free( source ); overflowing_free( destination ); return err; } static os_error *Do_Next_File( action_environment *env ) { os_error *err; char *filename; int inhibit_confirm = No; 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 ) return err; set_bottom_info_field( env, filename ); overflowing_free( filename ); switch( env->operation ) { case Action_Copying: case Action_CopyLocal: env->action = Test_Add_To_Read_List; inhibit_confirm = Yes; break; case Action_Moving: env->action = Attempt_1st_Rename; break; case Action_CopyMoving: if ( objecttype_of_next_node( env->test_search ) == ObjectType_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; case Action_Deleting: if ( objecttype_of_next_node( env->test_search ) == ObjectType_Directory ) { 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: env->action = Attempt_Set_Access; break; case Action_Setting_Type: env->action = Attempt_Set_Type; break; case Action_Counting: more_top_progress( env, 1 ); more_bottom_progress( env, size_of_next_node( env->test_search ) ); break; case Action_Stamping: env->action = Attempt_Stamp; break; case Action_Finding: if ( !caseless_wildcmp( env->destination_name, name_of_next_node( env->test_search )) ) { last_top_info_field = msgs_lookup( "84" ); dbox_setfield( env->status_box, Top_Info_Field, last_top_info_field ); if ( (objecttype_of_next_node( env->test_search ) == ObjectType_Directory && name_of_next_node( env->test_search )[0] != '!') || objecttype_of_next_node( env->test_search ) == (ObjectType_Directory | ObjectType_File) ) { switch_buttons( env, &open_buttons ); } else { switch_buttons( env, &run_view_buttons ); } } /* 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 ); } break; default: break; } /* 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 ); last_top_info_field = msgs_lookup( action_prompt[ env->operation ] ); dbox_setfield( env->status_box, Top_Info_Field, last_top_info_field ); } } else { /* No more files */ if ( env->operation == Action_Copying || env->operation == Action_CopyMoving || env->operation == Action_CopyLocal ) { switch_to_writing( env ); } else if ( env->operation == Action_Counting ) { /* Change buttons, display dbox, clear unwanted fields etc */ switch_buttons( env, &ok_button ); dbox_setfield( env->status_box, Top_Info_Field, msgs_lookup( "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 ]; switch_buttons( env, &ok_button ); sprintf( top_field, msgs_lookup( "86" ), env->locked_not_deleted ); 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 ); } } return NULL; } static os_error *Do_Test_Add_To_Read_List( action_environment *env ) { os_error *err; int should_be_added; err = test_add_to_read_list( env, &should_be_added ); if ( err ) return err; if ( should_be_added ) { env->action = Add_To_Read_List; /* Confirm if necessary. */ 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; } return NULL; } static os_error *Do_Add_To_Read_List( action_environment *env ) { int i_am_full; add_to_read_list( env, &i_am_full ); if ( i_am_full ) switch_to_writing( env ); return NULL; } static os_error *Do_Check_Full_Reading( action_environment *env ) { os_error *err; int i_am_full; int need_another_file; int that_finished_a_file; err = read_a_block( &i_am_full, &need_another_file, &that_finished_a_file ); if ( err ) return err; if ( i_am_full ) { switch_to_writing( env ); } else if ( need_another_file ) { if ( another_node( env->test_search )) { env->action = Next_File; } else if ( next_file_to_be_written() == NULL ) { abort_operation( env ); } else { switch_to_writing( env ); } } else { set_top_progress_field( env, bytes_left_to_read()); if ( that_finished_a_file ) { set_bottom_info_field( env, next_file_to_be_read()); } } return NULL; } static os_error *Do_Check_Empty_Writing( action_environment *env ) { os_error *err; int i_am_empty; int that_finished_a_file; err = write_a_block( &i_am_empty, &that_finished_a_file ); if ( err ) return err; if ( i_am_empty ) { switch_to_reading( env ); } else if ( that_finished_a_file ) { if ( env->operation != Action_CopyMoving ) { if ( size_of_finished_file >= 0 ) { more_bottom_progress( env, 1 ); } set_bottom_info_field( env, next_file_to_be_written()); 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 { set_top_progress_field( env, bytes_left_to_write()); } return NULL; } static os_error *Do_Attempt_Rename( action_environment *env, int which_one ) { os_error *err; err = riscos_rename( env ); if ( err ) { switch ( err->errnum & FileError_Mask ) { case ErrorNumber_Locked: if ( which_one == 1 ) { env->action = Attempt_Unlock; err = NULL; } break; case ErrorNumber_NotSameDisc: case ErrorNumber_BadRename: case ErrorNumber_AlreadyExists: if ( which_one == 1 ) env->action = Convert_To_CopyMove; else env->action = Convert_To_CopyMove_After_Unlock; err = NULL; break; } } else { if ( which_one == 1 ) { more_bottom_progress( env, 1 ); env->action = Next_File; } else { env->action = Attempt_Relock; } } return err; } static os_error *Do_Attempt_Unlock( action_environment *env ) { os_error *err; char *filename; err = next_nodename( env->test_search, &filename ); if ( err ) return err; /* Ignore error as don't care if it fails */ (void)set_access_to_file( filename, attributes_of_next_node( env->test_search ) & ~Attribute_Locked ); overflowing_free( filename ); env->action = Attempt_2nd_Rename; return NULL; } /* Relock destination of rename after unlocking source */ static os_error *Do_Attempt_Relock( action_environment *env ) { os_error *err; char *source; char *destination; err = next_nodename( env->test_search, &source ); if ( err ) return err; err = create_destination_filename( env, source, &destination ); overflowing_free( source ); if ( err ) return err; /* Ignore error as don't care if it fails */ (void)set_access_to_file( destination, attributes_of_next_node( env->test_search ) ); overflowing_free( destination ); more_bottom_progress( env, 1 ); env->action = Next_File; return NULL; } static os_error *Do_Convert_To_CopyMove( action_environment *env, int after_unlock ) { os_error *err; char *filename; /* Relock the node if necessary, don't object if this 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 ); } 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 ); env->locked_not_deleted = 0; return err; } static os_error *Do_Attempt_Delete( action_environment *env ) { os_error *err; char *filename; int inhibit_progress = No; int prev_access; if ( env->operation != Action_CopyMoving ) { wimpt_noerr( next_nodename( env->test_search, &filename )); } else { filename = source_of_finished_file; } #ifdef debugact dprintf("Do_Attempt_Delete: filename = %s\n",filename); #endif /* 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 & ~Attribute_Locked); if ( err && (err->errnum & FileError_Mask) != ErrorNumber_NotFound ) return err; /* Retry deletion */ err = delete_node( filename ); } /* If it didn't work, cancel the error if its an ignorable error for this operation */ if ( err ) { /* 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 ) { 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 { /* Tell the file listing stuff we've deleted the node */ deleted_next_node( env->test_search, filename ); } if ( env->operation != Action_CopyMoving ) overflowing_free( filename ); if ( err ) return err; if ( env->operation != Action_CopyMoving ) { if ( !inhibit_progress ) { /* 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()); env->action = Check_Empty_Writing; } return NULL; } static os_error *Do_Attempt_Set_Access( action_environment *env ) { os_error *err; if ( objecttype_of_next_node( env->test_search ) != ObjectType_File ) { err = set_access( env, ((attributes_of_next_node( env->test_search) & (env->new_access >> 16) & 0xffff) | (env->new_access & ~(env->new_access >> 16) & 0xffff)) & env->directory_access_setting_mask ); if ( 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) ); if ( err ) return err; more_bottom_progress( env, 1 ); } env->action = Next_File; return NULL; } static os_error *Do_Attempt_Set_Type( action_environment *env ) { os_error *err; char *filename; os_filestr fileplace; if ( objecttype_of_next_node( env->test_search ) == ObjectType_Directory ) { more_top_progress( env, 1 ); } else { err = next_nodename( env->test_search, &filename ); if ( err ) return err; fileplace.action = 0x12; /* set file type */ fileplace.name = filename; fileplace.loadaddr = env->new_type; err = os_file( &fileplace ); overflowing_free( filename ); if ( err ) return err; more_bottom_progress( env, 1 ); } env->action = Next_File; return NULL; } static os_error *Do_Attempt_Stamp( action_environment *env ) { os_error *err; err = stamp( env ); /* 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; err = NULL; if ( objecttype_of_next_node( env->test_search ) == ObjectType_File ) more_bottom_progress( env, 1 ); else more_top_progress( env, 1 ); env->action = Next_File; return NULL; } /* --- Activity processor for null events --- */ static void null_event_activity( action_environment *env ) { os_error *err = NULL; char info_buffer[ Info_Field_Length + 15 ]; int end_time; end_time = clock() + doings_time; hide_faster_stuff( env ); do { if ( env->action == Abort_Operation ) { 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 ) { case Next_File: err = Do_Next_File( env ); break; case Test_Add_To_Read_List: err = Do_Test_Add_To_Read_List( env ); break; case Add_To_Read_List: err = Do_Add_To_Read_List( env ); break; case Check_Full_Reading: err = Do_Check_Full_Reading( env ); break; case Check_Empty_Writing: err = Do_Check_Empty_Writing( env ); break; case Attempt_1st_Rename: err = Do_Attempt_Rename( env, 1 ); break; case Attempt_Unlock: err = Do_Attempt_Unlock( env ); break; case Attempt_2nd_Rename: err = Do_Attempt_Rename( env, 2 ); break; case Attempt_Relock: err = Do_Attempt_Relock( env ); break; case Convert_To_CopyMove: err = Do_Convert_To_CopyMove( env, No ); break; case Convert_To_CopyMove_After_Unlock: err = Do_Convert_To_CopyMove( env, Yes ); break; case Attempt_Delete: err = Do_Attempt_Delete( env ); break; case Attempt_Set_Access: err = Do_Attempt_Set_Access( env ); break; case Attempt_Set_Type: err = Do_Attempt_Set_Type( env ); break; case Attempt_Stamp: 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 ) { 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 ) { 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 } } } /* --- NULL event handler for status box. --- */ BOOL idle_event_handler(dbox db, void *event, void *handle) { BOOL handled = No; db = db; /* keep the compiler quiet */ switch( ((wimp_eventstr *)event)->e ) { 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 ) { 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: case wimp_ESENDWANTACK: handled = message_event_handler( event, handle ); break; default: break; } return handled; } /* Fixed stack size !!! * 3.5k is the max required. * 2k is a bodge safety factor. */ int __root_stack_size = 3*1024+512+2*1024; extern int disable_stack_extension; /* This is the entry point for the Filer_Action module. */ int main( int argc, char *argv[] ) { disable_stack_extension = 1; wimpt_install_signal_handlers(); wimpt_noerr( initialise( &env, argc, argv )); while (TRUE) { event_process(); } return 0; }