commit a1c4a1f9ee1abbda67211533bdf6d777c5dd23cb Author: Justin Marshall Date: Thu Aug 6 08:03:49 2026 -0700 Initial commit diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..733f51f --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,974 @@ +cmake_minimum_required(VERSION 3.25) + +project(MicrosoftWordX64Port VERSION 0.2.0 LANGUAGES C CXX RC) + +if(NOT WIN32) + message(FATAL_ERROR "The Microsoft Word x64 port currently targets Windows only.") +endif() + +if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8) + message(FATAL_ERROR "This project must be configured for x64 (use: cmake --preset x64-debug).") +endif() + +set(MSWORD_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/..") +cmake_path(NORMAL_PATH MSWORD_ROOT) +set(MSWORD_BUILD_ROOT "${MSWORD_ROOT}/build") +set(MSWORD_BIN_ROOT "${MSWORD_ROOT}/bin") +# Reserved for the executable that will be linked from the original Opus +# source graph. The migration bootstrap must not use this product name. +set(MSWORD_PRODUCT_OUTPUT_NAME "WORD1" CACHE STRING + "Filename stem for the original-source Word x64 executable") + +file(MAKE_DIRECTORY "${MSWORD_BUILD_ROOT}" "${MSWORD_BIN_ROOT}") + +# Keep linked artifacts in the locations requested for this port. CMake's +# generated project and cache live under ../out (see CMakePresets.json). +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${MSWORD_BIN_ROOT}") +set(CMAKE_PDB_OUTPUT_DIRECTORY "${MSWORD_BUILD_ROOT}/pdb") +set(CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY "${MSWORD_BUILD_ROOT}/pdb") + +foreach(config Debug Release RelWithDebInfo MinSizeRel) + string(TOUPPER "${config}" config_upper) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${config_upper} "${MSWORD_BIN_ROOT}") + set(CMAKE_PDB_OUTPUT_DIRECTORY_${config_upper} "${MSWORD_BUILD_ROOT}/pdb/${config}") + set(CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_${config_upper} "${MSWORD_BUILD_ROOT}/pdb/${config}") +endforeach() + +set(MSWORD_BOOTSTRAP_SOURCES + port/winword_x64.cpp + port/legacy_asm_port.cpp + port/legacy_asm_port.h + port/winword_x64.rc + port/winword.manifest +) + +# This is a migration aid only. It is deliberately excluded from the default +# build and may never claim the final WORD1.exe product name: that name is +# reserved for the executable linked from the original Opus source graph. +add_executable(WINWORD_BOOTSTRAP WIN32 EXCLUDE_FROM_ALL ${MSWORD_BOOTSTRAP_SOURCES}) +target_compile_features(WINWORD_BOOTSTRAP PRIVATE cxx_std_20) +target_compile_definitions(WINWORD_BOOTSTRAP PRIVATE UNICODE _UNICODE WIN32_LEAN_AND_MEAN NOMINMAX) +target_include_directories(WINWORD_BOOTSTRAP PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/port") +target_link_libraries(WINWORD_BOOTSTRAP PRIVATE + comctl32 + comdlg32 + gdi32 + ole32 + shell32 + user32 +) + +if(MSVC) + target_compile_options(WINWORD_BOOTSTRAP PRIVATE /W4 /permissive- /utf-8 /EHsc /guard:cf) + # The application manifest is compiled as resource 1; disable MSVC's + # second auto-generated manifest to avoid a duplicate RT_MANIFEST entry. + target_link_options(WINWORD_BOOTSTRAP PRIVATE /DYNAMICBASE /HIGHENTROPYVA /NXCOMPAT /MANIFEST:NO) + set_property(TARGET WINWORD_BOOTSTRAP PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") +endif() + +set_target_properties(WINWORD_BOOTSTRAP PROPERTIES + OUTPUT_NAME "WINWORD_BOOTSTRAP" + RUNTIME_OUTPUT_DIRECTORY "${MSWORD_BUILD_ROOT}/bootstrap" + VS_GLOBAL_ROOTNAMESPACE "MicrosoftWordX64Port" + # The target uses only Windows system libraries. Disable Visual Studio's + # global vcpkg app-local hook so it does not invoke an unrelated pwsh.exe. + VS_GLOBAL_VcpkgApplocalDeps "false" +) +foreach(config Debug Release RelWithDebInfo MinSizeRel) + string(TOUPPER "${config}" config_upper) + set_target_properties(WINWORD_BOOTSTRAP PROPERTIES + RUNTIME_OUTPUT_DIRECTORY_${config_upper} "${MSWORD_BUILD_ROOT}/bootstrap/${config}" + ) +endforeach() + +# The original assembly remains in the repository for behavioral reference, +# but no .asm file is permitted to enter the native target. +get_target_property(winword_sources WINWORD_BOOTSTRAP SOURCES) +foreach(source IN LISTS winword_sources) + if(source MATCHES "\\.[aA][sS][mM]$") + message(FATAL_ERROR "Legacy assembly leaked into the x64 target: ${source}") + endif() +endforeach() + +file(GLOB_RECURSE LEGACY_ASSEMBLY CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.asm") +set(LEGACY_ASSEMBLY_RELATIVE) +foreach(assembly_file IN LISTS LEGACY_ASSEMBLY) + file(RELATIVE_PATH relative_path "${CMAKE_CURRENT_SOURCE_DIR}" "${assembly_file}") + cmake_path(CONVERT "${relative_path}" TO_CMAKE_PATH_LIST relative_path NORMALIZE) + list(APPEND LEGACY_ASSEMBLY_RELATIVE "${relative_path}") +endforeach() +list(SORT LEGACY_ASSEMBLY_RELATIVE) + +# Extract the explicit source paths from the C++ disposition table and compare +# names, not merely counts. Removing one module and adding another cannot pass. +file(READ "${CMAKE_CURRENT_SOURCE_DIR}/port/legacy_asm_port.cpp" ASM_PORT_SOURCE) +string(REGEX MATCHALL "AssemblyPortEntry\\{\"[^\"]+\\.asm\"" ASM_PORT_ROWS "${ASM_PORT_SOURCE}") +set(ASM_PORT_PATHS) +foreach(port_row IN LISTS ASM_PORT_ROWS) + string(REGEX REPLACE "AssemblyPortEntry\\{\"([^\"]+)\"" "\\1" port_path "${port_row}") + list(APPEND ASM_PORT_PATHS "${port_path}") +endforeach() +list(SORT ASM_PORT_PATHS) + +list(LENGTH LEGACY_ASSEMBLY_RELATIVE LEGACY_ASSEMBLY_COUNT) +if(NOT LEGACY_ASSEMBLY_COUNT EQUAL 59 OR + NOT "${LEGACY_ASSEMBLY_RELATIVE}" STREQUAL "${ASM_PORT_PATHS}") + message(FATAL_ERROR + "The assembly-port manifest does not exactly match the legacy source tree " + "(${LEGACY_ASSEMBLY_COUNT} modules found). Update port/legacy_asm_port.cpp." + ) +endif() + +add_custom_target(legacy_sources SOURCES ${LEGACY_ASSEMBLY}) +set_target_properties(legacy_sources PROPERTIES FOLDER "Legacy reference (not compiled)") + +# Start of the real product engine. Every source in this target is from the +# original Opus tree; compatibility code supplies platform services only. +set(OPUS_SDK_ROOT "$ENV{ProgramFiles\(x86\)}/Windows Kits/10") +set(OPUS_WINDOWS_SDK_HEADER + "${OPUS_SDK_ROOT}/Include/${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}/um/Windows.h") +if(NOT EXISTS "${OPUS_WINDOWS_SDK_HEADER}") + message(FATAL_ERROR "Could not locate the Windows SDK header: ${OPUS_WINDOWS_SDK_HEADER}") +endif() +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/generated/original") +configure_file( + port/original/opus_windows_sdk.h.in + "${CMAKE_CURRENT_BINARY_DIR}/generated/original/opus_windows_sdk.h" + @ONLY +) + +# MERGEELX writes a fixed hidden-screen payload in addition to the dialog EL +# tables. Preserve that original payload directly from Microsoft's generator +# source. The archive lacks the Dialog Editor executable that converted its +# .des inputs to MERGEELX's intermediate .elx format, so an explicit inert EL +# table boundary remains until that missing compiler stage is replaced. +set(OPUS_GENERATED_ELXINFO + "${CMAKE_CURRENT_BINARY_DIR}/generated/original/elxinfo.h") +add_custom_command( + OUTPUT "${OPUS_GENERATED_ELXINFO}" + COMMAND powershell -NoProfile -ExecutionPolicy Bypass + -File "${CMAKE_CURRENT_SOURCE_DIR}/cmake/GenerateElxStid.ps1" + -InputPath "${CMAKE_CURRENT_SOURCE_DIR}/OpusEtAl/tools/src/mergeelx.c" + -OutputPath "${OPUS_GENERATED_ELXINFO}" + DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/GenerateElxStid.ps1" + "${CMAKE_CURRENT_SOURCE_DIR}/OpusEtAl/tools/src/mergeelx.c" + VERBATIM +) +add_custom_target(opus_generated_elxinfo DEPENDS "${OPUS_GENERATED_ELXINFO}") +set_target_properties(opus_generated_elxinfo PROPERTIES + FOLDER "Original Opus x64/generated" +) + +# Rebuild the command constants from Microsoft's checked-in command compiler +# and resource sources. The tool runs natively on x64 but preserves MKCMD's +# original 16-bit serialized word layout. +add_executable(opus_mkcmd_tool EXCLUDE_FROM_ALL + OpusEtAl/tools/src/mkcmd.c +) +target_compile_definitions(opus_mkcmd_tool PRIVATE OPUS_X64_TOOL) +target_include_directories(opus_mkcmd_tool PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/OpusEtAl/tools/src" +) +if(MSVC) + target_compile_options(opus_mkcmd_tool PRIVATE /J /W3 /wd4996) +endif() +set_target_properties(opus_mkcmd_tool PROPERTIES + FOLDER "Original Opus x64/build tools" + RUNTIME_OUTPUT_DIRECTORY "${MSWORD_BUILD_ROOT}/tools" + VS_GLOBAL_VcpkgApplocalDeps "false" +) +foreach(config Debug Release RelWithDebInfo MinSizeRel) + string(TOUPPER "${config}" config_upper) + set_target_properties(opus_mkcmd_tool PROPERTIES + RUNTIME_OUTPUT_DIRECTORY_${config_upper} "${MSWORD_BUILD_ROOT}/tools/${config}" + ) +endforeach() + +# Preserve Microsoft's original BITAPP resource conversion step. These +# native x64 tool builds consume the checked-in Win16 .cur files and emit the +# same byte initializers that SCREEN2.C historically included. +add_executable(opus_bitapp_tool EXCLUDE_FROM_ALL + OpusEtAl/tools/src/bitapp.c +) +target_compile_definitions(opus_bitapp_tool PRIVATE OPUS_X64_TOOL) +target_include_directories(opus_bitapp_tool PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/OpusEtAl/tools/src" +) +if(MSVC) + target_compile_options(opus_bitapp_tool PRIVATE /J /W3 /wd4996) +endif() +set_target_properties(opus_bitapp_tool PROPERTIES + FOLDER "Original Opus x64/build tools" + RUNTIME_OUTPUT_DIRECTORY "${MSWORD_BUILD_ROOT}/tools" + VS_GLOBAL_VcpkgApplocalDeps "false" +) +foreach(config Debug Release RelWithDebInfo MinSizeRel) + string(TOUPPER "${config}" config_upper) + set_target_properties(opus_bitapp_tool PROPERTIES + RUNTIME_OUTPUT_DIRECTORY_${config_upper} "${MSWORD_BUILD_ROOT}/tools/${config}" + ) +endforeach() + +set(OPUS_GENERATED_COMMAND_DIR + "${CMAKE_CURRENT_BINARY_DIR}/generated/original") + +set(OPUS_CURSOR_RESOURCE_NAMES + styname + mic + help + cross + vertout + horzout + prvwcrs +) +set(OPUS_GENERATED_CURSOR_FILES) +foreach(cursor_name IN LISTS OPUS_CURSOR_RESOURCE_NAMES) + set(cursor_source "${CMAKE_CURRENT_SOURCE_DIR}/Opus/resource/${cursor_name}.cur") + set(cursor_header "${OPUS_GENERATED_COMMAND_DIR}/${cursor_name}.hc") + add_custom_command( + OUTPUT "${cursor_header}" + COMMAND "$" "${cursor_source}" "${cursor_header}" + DEPENDS opus_bitapp_tool "${cursor_source}" + COMMENT "Converting original Opus cursor ${cursor_name}.cur with BITAPP" + VERBATIM + ) + list(APPEND OPUS_GENERATED_CURSOR_FILES "${cursor_header}") +endforeach() +add_custom_target(opus_generated_cursors + DEPENDS ${OPUS_GENERATED_CURSOR_FILES} +) +set_target_properties(opus_generated_cursors PROPERTIES + FOLDER "Original Opus x64/build tools" +) + +# Recreate the checked-out build's embedded icon/cursor/bitmap C headers +# using Microsoft's original BITAPP source. These headers were intermediate +# build products and are not present in the source archive. +set(OPUS_BITAPP_BITMAP_HEADERS + 8hdr.hb 8otlpat.hb 8outline.hg 8pageico.hb 8paralig.hg + 8ribbon.hg 8rulmark.hg 8rultgls.hg 8scrptpo.hg + chdr.hb cotlpat.hb coutline.hg cpageico.hb cparalig.hg + cribbon.hg crulmark.hg crultgls.hg cscrptpo.hg + ehdr.hb eotlpat.hb eoutline.hg epageico.hb eparalig.hg + eribbon.hg erulmark.hg erultgls.hg escrptpo.hg + shdr.hb showvis.hb sotlpat.hb soutline.hg spageico.hb + sparalig.hg sribbon.hg srulmark.hg srultgls.hg sscrptpo.hg + vhdr.hb votlpat.hb voutline.hg vpageico.hb vparalig.hg + vribbon.hg vrulmark.hg vrultgls.hg vscrptpo.hg +) +set(OPUS_BITAPP_FIGURE_HEADERS + mopus.hi mword.hi mwhires.hc split.hc column.hc +) +set(OPUS_GENERATED_EMBEDDED_RESOURCES) +foreach(resource_header IN LISTS OPUS_BITAPP_BITMAP_HEADERS OPUS_BITAPP_FIGURE_HEADERS) + get_filename_component(resource_stem "${resource_header}" NAME_WE) + get_filename_component(resource_extension "${resource_header}" EXT) + if(resource_extension STREQUAL ".hi") + set(resource_source_extension ".ico") + elseif(resource_extension STREQUAL ".hc") + set(resource_source_extension ".cur") + else() + set(resource_source_extension ".bmp") + endif() + set(resource_source + "${CMAKE_CURRENT_SOURCE_DIR}/Opus/resource/${resource_stem}${resource_source_extension}") + set(resource_output + "${OPUS_GENERATED_COMMAND_DIR}/${resource_header}") + if(resource_extension STREQUAL ".hg") + set(bitapp_gray_flag /g) + else() + set(bitapp_gray_flag) + endif() + add_custom_command( + OUTPUT "${resource_output}" + COMMAND "$" ${bitapp_gray_flag} + "${resource_source}" "${resource_output}" + DEPENDS opus_bitapp_tool "${resource_source}" + COMMENT "Regenerating original Opus resource header ${resource_header}" + VERBATIM + ) + list(APPEND OPUS_GENERATED_EMBEDDED_RESOURCES "${resource_output}") +endforeach() +add_custom_target(opus_generated_embedded_resources + DEPENDS ${OPUS_GENERATED_EMBEDDED_RESOURCES} +) +set_target_properties(opus_generated_embedded_resources PROPERTIES + FOLDER "Original Opus x64/generated" +) + +# DIBAPP itself is not present in the archive. This native compatibility +# tool preserves its build boundary by extracting the original OS/2 +# BITMAPCOREHEADER scan lines into the BMDS3 aggregate format consumed by +# Microsoft's rcbmp13/23/43 modules. +add_executable(opus_dibapp_tool EXCLUDE_FROM_ALL + port/tools/opus_dibapp_tool.cpp +) +target_compile_features(opus_dibapp_tool PRIVATE cxx_std_20) +if(MSVC) + target_compile_options(opus_dibapp_tool PRIVATE /W4 /permissive-) +endif() +set_target_properties(opus_dibapp_tool PROPERTIES + FOLDER "Original Opus x64/build tools" + RUNTIME_OUTPUT_DIRECTORY "${MSWORD_BUILD_ROOT}/tools" + VS_GLOBAL_VcpkgApplocalDeps "false" +) +foreach(config Debug Release RelWithDebInfo MinSizeRel) + string(TOUPPER "${config}" config_upper) + set_target_properties(opus_dibapp_tool PROPERTIES + RUNTIME_OUTPUT_DIRECTORY_${config_upper} "${MSWORD_BUILD_ROOT}/tools/${config}" + ) +endforeach() + +file(GLOB OPUS_DIB_RESOURCE_INPUTS CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/Opus/resource/*.dib") +set(OPUS_GENERATED_DIB_RESOURCE_FILES) +foreach(dib_input IN LISTS OPUS_DIB_RESOURCE_INPUTS) + get_filename_component(dib_stem "${dib_input}" NAME_WE) + set(dib_output "${OPUS_GENERATED_COMMAND_DIR}/${dib_stem}.hb") + add_custom_command( + OUTPUT "${dib_output}" + COMMAND "$" "${dib_input}" "${dib_output}" + DEPENDS opus_dibapp_tool "${dib_input}" + COMMENT "Converting original ${dib_stem}.dib resource" + VERBATIM + ) + list(APPEND OPUS_GENERATED_DIB_RESOURCE_FILES "${dib_output}") +endforeach() +add_custom_target(opus_generated_dib_resources + DEPENDS ${OPUS_GENERATED_DIB_RESOURCE_FILES} +) +set_target_properties(opus_generated_dib_resources PROPERTIES + FOLDER "Original Opus x64/generated" +) + +set(OPUS_GENERATED_COMMAND_FILES + "${OPUS_GENERATED_COMMAND_DIR}/opuscmd.h" + "${OPUS_GENERATED_COMMAND_DIR}/IBCM.H" + "${OPUS_GENERATED_COMMAND_DIR}/RGBCM.H" + "${OPUS_GENERATED_COMMAND_DIR}/OPUSCMD2.H" + "${OPUS_GENERATED_COMMAND_DIR}/OPUSMENU.H" + "${OPUS_GENERATED_COMMAND_DIR}/MENUHELP.TXT" + "${OPUS_GENERATED_COMMAND_DIR}/menuhelp.h" + "${OPUS_GENERATED_COMMAND_DIR}/opuscmd.asm" + "${OPUS_GENERATED_COMMAND_DIR}/opuscmd_native.inc" +) +add_custom_command( + OUTPUT ${OPUS_GENERATED_COMMAND_FILES} + COMMAND "${CMAKE_COMMAND}" -E copy_if_different + "${CMAKE_CURRENT_SOURCE_DIR}/Opus/resource/opuscmd.cmd" + "${OPUS_GENERATED_COMMAND_DIR}/opuscmd.cmd" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different + "${CMAKE_CURRENT_SOURCE_DIR}/Opus/resource/keys.cmd" + "${OPUS_GENERATED_COMMAND_DIR}/keys.cmd" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different + "${CMAKE_CURRENT_SOURCE_DIR}/Opus/resource/menus.cmd" + "${OPUS_GENERATED_COMMAND_DIR}/menus.cmd" + COMMAND "${CMAKE_COMMAND}" -E copy + "${CMAKE_CURRENT_SOURCE_DIR}/Opus/resource/ibcm.rel" + "${OPUS_GENERATED_COMMAND_DIR}/IBCM.H" + COMMAND "$" + -T@13 -s../../../src/Opus/dlg/ opuscmd keys menus + COMMAND "${CMAKE_COMMAND}" + -DINPUT=${OPUS_GENERATED_COMMAND_DIR}/MENUHELP.TXT + -DOUTPUT=${OPUS_GENERATED_COMMAND_DIR}/menuhelp.h + -P "${CMAKE_CURRENT_SOURCE_DIR}/cmake/GenerateMenuHelpHeader.cmake" + DEPENDS + opus_mkcmd_tool + Opus/resource/opuscmd.cmd + Opus/resource/keys.cmd + Opus/resource/menus.cmd + Opus/resource/ibcm.rel + Opus/dlg/elx.txt + cmake/GenerateMenuHelpHeader.cmake + WORKING_DIRECTORY "${OPUS_GENERATED_COMMAND_DIR}" + COMMENT "Regenerating original Opus command tables with MKCMD" + VERBATIM +) +add_custom_target(opus_generated_commands + DEPENDS ${OPUS_GENERATED_COMMAND_FILES} +) +set_target_properties(opus_generated_commands PROPERTIES + FOLDER "Original Opus x64/build tools" +) + +# Rebuild the EL dialog range/parse tables with Microsoft's original MKDLG +# source. dlgcheck.h was a generated build artifact and is not checked into +# this archive. +add_executable(opus_mkdlg_tool EXCLUDE_FROM_ALL + OpusEtAl/tools/src/mkdlg.c +) +if(MSVC) + target_compile_options(opus_mkdlg_tool PRIVATE /J /W3 /wd4996) +endif() +set_target_properties(opus_mkdlg_tool PROPERTIES + FOLDER "Original Opus x64/build tools" + RUNTIME_OUTPUT_DIRECTORY "${MSWORD_BUILD_ROOT}/tools" + VS_GLOBAL_VcpkgApplocalDeps "false" +) +foreach(config Debug Release RelWithDebInfo MinSizeRel) + string(TOUPPER "${config}" config_upper) + set_target_properties(opus_mkdlg_tool PROPERTIES + RUNTIME_OUTPUT_DIRECTORY_${config_upper} "${MSWORD_BUILD_ROOT}/tools/${config}" + ) +endforeach() +file(GLOB OPUS_DIALOG_ELX CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/Opus/dlg/*.elx") +set(OPUS_GENERATED_DLGCHECK + "${OPUS_GENERATED_COMMAND_DIR}/dlgcheck.h") +add_custom_command( + OUTPUT "${OPUS_GENERATED_DLGCHECK}" + COMMAND "$" + "@elx.txt" "${OPUS_GENERATED_DLGCHECK}" + DEPENDS opus_mkdlg_tool ${OPUS_DIALOG_ELX} Opus/dlg/elx.txt + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/Opus/dlg" + COMMENT "Regenerating original Opus dialog validation tables with MKDLG" + VERBATIM +) +add_custom_target(opus_generated_dlgcheck + DEPENDS "${OPUS_GENERATED_DLGCHECK}" +) +set_target_properties(opus_generated_dlgcheck PROPERTIES + FOLDER "Original Opus x64/generated" +) + +add_executable(opus_mergeelx_tool EXCLUDE_FROM_ALL + OpusEtAl/tools/src/mergeelx.c +) +target_include_directories(opus_mergeelx_tool PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/OpusEtAl/tools/src" +) +if(MSVC) + target_compile_options(opus_mergeelx_tool PRIVATE /J /W3 /wd4996) +endif() +set_target_properties(opus_mergeelx_tool PROPERTIES + FOLDER "Original Opus x64/build tools" + RUNTIME_OUTPUT_DIRECTORY "${MSWORD_BUILD_ROOT}/tools" + VS_GLOBAL_VcpkgApplocalDeps "false" +) +foreach(config Debug Release RelWithDebInfo MinSizeRel) + string(TOUPPER "${config}" config_upper) + set_target_properties(opus_mergeelx_tool PROPERTIES + RUNTIME_OUTPUT_DIRECTORY_${config_upper} "${MSWORD_BUILD_ROOT}/tools/${config}" + ) +endforeach() + +add_library(opus_original_engine STATIC + Opus/command.c + Opus/command2.c + Opus/annot.c + Opus/cmd.c + Opus/cmd2.c + Opus/cmd3.c + Opus/cmdcore.c + Opus/cmdwnd.c + Opus/curswin.c + Opus/CLIPBORD.C + Opus/CLIPBRD2.C + Opus/compare.c + Opus/create.c + Opus/CREATE2.C + Opus/EDIT.C + Opus/disp1.c + Opus/dispbrc.c + Opus/dispspec.c + Opus/dialog1.c + Opus/dialog2.c + Opus/dialog3.c + Opus/dialog4.c + Opus/dlglook1.c + Opus/dlglook2.c + Opus/dlgrec.c + Opus/dlgmisc.c + Opus/dlgopen.c + Opus/dlgdoc.c + Opus/edmacro.c + Opus/search.c + Opus/replace.c + Opus/srchfmt.c + Opus/tabs.c + Opus/catalog.c + Opus/customiz.c + Opus/toc.c + Opus/sort.c + Opus/index1.c + Opus/index2.c + Opus/merge.c + Opus/renum.c + Opus/insfield.c + Opus/dlgtable.c + Opus/dlghyph.c + Opus/etcmd.c + Opus/docman1.c + Opus/docman2.c + Opus/print2.c + Opus/ddeclnt.c + Opus/ddesub.c + Opus/DDESRVR.C + Opus/DLBENUM.C + Opus/eldde.c + Opus/eldlg.c + Opus/elfile.c + Opus/elmisc.c + Opus/elmisc2.c + Opus/elsubs.c + Opus/elsubs3.c + Opus/elsubs2.c + Opus/FILE2.C + Opus/ffcrypt.c + Opus/ffread.c + Opus/fieldcr.c + Opus/fieldclc.c + Opus/FIELDCMD.C + Opus/fieldfmt.c + Opus/fieldprs.c + Opus/fieldsc2.c + Opus/fieldspc.c + Opus/fltexp.c + Opus/filecvt.c + Opus/filewin.c + Opus/formula.c + Opus/formatsp.c + Opus/fieldsp.c + Opus/fieldpic.c + Opus/glsy.c + Opus/help.c + Opus/hddwin.c + Opus/GRSPEC.C + Opus/grbit.c + Opus/grswath.c + Opus/grtiff.c + Opus/initwin.c + Opus/init2.c + Opus/interp/corout.c + Opus/interp/elcore.c + Opus/interp/elinit.c + Opus/interp/exp.c + Opus/interp/main.c + Opus/interp/sym.c + Opus/interp/to.c + Opus/idle.c + Opus/LOADFONT.C + Opus/iconbar1.c + Opus/iconbar2.c + Opus/iconbar3.c + Opus/menu.c + Opus/menuhelp.c + Opus/mathapi.c + Opus/wordtech/inssubs.c + Opus/wordtech/insert.c + Opus/open.c + Opus/openrare.c + Opus/outwin.c + Opus/pic.c + Opus/PIC2.C + Opus/pictdrag.c + Opus/prompt.c + Opus/preview.c + Opus/print.c + Opus/print1.c + Opus/prvw2.c + Opus/raremsg.c + Opus/recorder.c + Opus/res.c + Opus/rsb.c + Opus/util2.c + Opus/rulerdrw.c + Opus/rulrib.c + Opus/RTFIN.C + Opus/RTFOUT.C + Opus/RTFRARE.C + Opus/rtfsubs.c + Opus/rtftrans.c + Opus/rcinit.c + Opus/rcbmp1.c + Opus/rcbmp2.c + Opus/rcbmp3.c + Opus/rcbmp4.c + Opus/rcbmp13.c + Opus/rcbmp23.c + Opus/rcbmp43.c + Opus/save.c + Opus/savetext.c + Opus/SCREEN2.C + Opus/statline.c + Opus/style.c + Opus/stylesub.c + Opus/strtbl.c + Opus/splitter.c + Opus/SYSCHG.C + Opus/quit.c + Opus/wproc.c + Opus/wwact.c + Opus/wwchange.c + Opus/token.c + Opus/vars.c + Opus/wordtech/clsplc.c + Opus/wordtech/banter.c + Opus/wordtech/block.c + Opus/wordtech/curskeys.c + Opus/wordtech/disp2.c + Opus/wordtech/disp3.c + Opus/wordtech/disptbl.c + Opus/wordtech/editsub.c + Opus/wordtech/editspec.c + Opus/wordtech/error.c + Opus/wordtech/fetch.c + Opus/wordtech/fetch1.c + Opus/wordtech/fetch2.c + Opus/wordtech/fetchtb.c + Opus/wordtech/footnote.c + Opus/wordtech/format.c + Opus/wordtech/hdd.c + Opus/wordtech/hyph.c + Opus/wordtech/ihdd.c + Opus/wordtech/layout.c + Opus/wordtech/layout1.c + Opus/wordtech/layout2.c + Opus/wordtech/outline.c + Opus/wordtech/layoutap.c + Opus/wordtech/pagevw.c + Opus/wordtech/printsub.c + Opus/wordtech/prcsubs.c + Opus/wordtech/savefast.c + Opus/wordtech/scroll.c + Opus/wordtech/select.c + Opus/wordtech/selectsp.c + Opus/wordtech/sttb.c + Opus/wordtech/stysubs.c + Opus/wordtech/selecttb.c + Opus/wordtech/tablecmd.c + Opus/wordtech/tableins.c + Opus/wordtech/tablesub.c + Opus/wordtech/undo.c + Opus/SPELL.C + Opus/spelcore.c + port/original/opus_asm_layout2.cpp + port/original/opus_asm_file2.cpp + port/original/opus_asm_filewin.cpp + port/original/opus_asm_math.cpp + port/original/opus_asm_natinit_format.cpp + port/original/opus_asm_graphics.cpp + port/original/opus_asm_fetch3.cpp + port/original/opus_asm_prompt.cpp + port/original/opus_asm_misc.cpp + port/original/opus_asm_movecmds.c + port/original/opus_asm_fetch_adapters.cpp + port/original/opus_asm_display_adapters.cpp + port/original/opus_asm_plc_adapters.cpp + port/original/opus_asm_resn2_adapters.cpp + port/original/opus_asm_native_adapters.cpp + port/original/opus_asm_wproc.cpp + port/original/opus_x64_segment_anchors.c +) +add_dependencies(opus_original_engine + opus_generated_commands + opus_generated_cursors + opus_generated_embedded_resources + opus_generated_dib_resources + opus_generated_dlgcheck + opus_generated_elxinfo +) +set_source_files_properties(Opus/wordtech/fetch2.c PROPERTIES + COMPILE_DEFINITIONS CC +) +set_source_files_properties(Opus/wordtech/fetch.c Opus/wordtech/fetch1.c Opus/wordtech/format.c Opus/wordtech/inssubs.c Opus/wordtech/fetchtb.c Opus/wordtech/editspec.c Opus/wordtech/layout.c PROPERTIES + COMPILE_DEFINITIONS DEBUGORNOTWIN +) +set_source_files_properties(Opus/wordtech/clsplc.c PROPERTIES + COMPILE_DEFINITIONS DEBUGORNOTWIN +) +set_source_files_properties(Opus/wordtech/layout1.c Opus/wordtech/layout2.c PROPERTIES + COMPILE_DEFINITIONS DEBUGORNOTWIN +) +set_source_files_properties(Opus/wordtech/disp2.c PROPERTIES + COMPILE_DEFINITIONS DEBUGORNOTWIN +) +set_source_files_properties(Opus/wordtech/disptbl.c PROPERTIES + COMPILE_DEFINITIONS DEBUGORNOTWIN +) +set_source_files_properties(Opus/disp1.c PROPERTIES + COMPILE_DEFINITIONS "NOASM;OPUS_X64_DISPLAY_C" +) +set_source_files_properties(Opus/CLIPBORD.C Opus/CLIPBRD2.C Opus/CREATE2.C Opus/DDESRVR.C Opus/DLBENUM.C Opus/EDIT.C Opus/FIELDCMD.C Opus/FILE2.C Opus/GRSPEC.C Opus/LOADFONT.C Opus/PIC2.C Opus/RTFIN.C Opus/RTFOUT.C Opus/RTFRARE.C Opus/SCREEN2.C Opus/SPELL.C Opus/SYSCHG.C PROPERTIES LANGUAGE C) +set(OPUS_ORIGINAL_INCLUDE_DIRS + "${CMAKE_CURRENT_BINARY_DIR}/generated/original" + "${CMAKE_CURRENT_SOURCE_DIR}/port/original" + "${CMAKE_CURRENT_SOURCE_DIR}/Opus/wordtech" + "${CMAKE_CURRENT_SOURCE_DIR}/Opus/lib" + "${CMAKE_CURRENT_SOURCE_DIR}/Opus/dlg" + "${CMAKE_CURRENT_SOURCE_DIR}/Opus/resource" + "${CMAKE_CURRENT_SOURCE_DIR}/Opus" +) +target_compile_definitions(opus_original_engine PRIVATE + WIN + WIN23 + CRLF + NONATIVE + OPUS_X64 + NOMINMAX +) +target_include_directories(opus_original_engine PRIVATE ${OPUS_ORIGINAL_INCLUDE_DIRS}) +if(MSVC) + # /J preserves the original compiler's unsigned-char default. Do not use + # the C++ compiler for K&R-era original C translation units. + target_compile_options(opus_original_engine PRIVATE /J /W3 /wd4005 /Gy) +endif() +set_target_properties(opus_original_engine PROPERTIES + FOLDER "Original Opus x64" + ARCHIVE_OUTPUT_DIRECTORY "${MSWORD_BUILD_ROOT}/lib" +) +foreach(config Debug Release RelWithDebInfo MinSizeRel) + string(TOUPPER "${config}" config_upper) + set_target_properties(opus_original_engine PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY_${config_upper} "${MSWORD_BUILD_ROOT}/lib/${config}" + ) +endforeach() + +add_library(opus_x64_runtime STATIC + port/original/opus_original_chupper.c + port/original/opus_elx_dispatch.cpp + port/original/opus_startup_diagnostics.cpp + port/original/opus_win16_platform.cpp + port/original/opus_x64_heap.cpp + port/original/opus_x64_layout.c + port/original/opus_asm_fetchn2.cpp + port/original/opus_asm_resn.cpp + port/original/opus_asm_resn_core.cpp + port/original/opus_asm_resn_plc.cpp + port/original/opus_asm_resn2.cpp + port/original/opus_asm_resn2_access.cpp + port/original/opus_asm_resn2_pl.cpp + port/original/opus_asm_resn2_sttb.cpp + port/original/opus_asm_sttb.cpp + port/original/opus_asm_search.cpp + port/original/opus_sdm_cab.cpp + port/original/opus_sdm_runtime.cpp +) +target_compile_features(opus_x64_runtime PRIVATE cxx_std_20) +target_compile_definitions(opus_x64_runtime PRIVATE + WIN + WIN23 + CRLF + NONATIVE + OPUS_X64 + NOMINMAX +) +target_include_directories(opus_x64_runtime PRIVATE ${OPUS_ORIGINAL_INCLUDE_DIRS}) +if(MSVC) + # Opus was built with unsigned plain characters; the byte-oriented string + # and international-character assembly routines depend on that behavior. + target_compile_options(opus_x64_runtime PRIVATE /J /W4 /permissive-) +endif() +set_target_properties(opus_x64_runtime PROPERTIES + FOLDER "Original Opus x64/runtime" + ARCHIVE_OUTPUT_DIRECTORY "${MSWORD_BUILD_ROOT}/lib" + VS_GLOBAL_VcpkgApplocalDeps "false" +) +foreach(config Debug Release RelWithDebInfo MinSizeRel) + string(TOUPPER "${config}" config_upper) + set_target_properties(opus_x64_runtime PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY_${config_upper} "${MSWORD_BUILD_ROOT}/lib/${config}" + ) +endforeach() + +add_executable(opus_original_sttb_test + Opus/wordtech/sttb.c + port/original/opus_original_sttb_test.c +) +target_compile_definitions(opus_original_sttb_test PRIVATE + WIN WIN23 CRLF NONATIVE OPUS_X64 NOMINMAX +) +target_include_directories(opus_original_sttb_test PRIVATE ${OPUS_ORIGINAL_INCLUDE_DIRS}) +target_link_libraries(opus_original_sttb_test PRIVATE opus_x64_runtime user32) +if(MSVC) + target_compile_options(opus_original_sttb_test PRIVATE /J /W3 /wd4005) +endif() +set_target_properties(opus_original_sttb_test PROPERTIES + FOLDER "Original Opus x64/tests" + RUNTIME_OUTPUT_DIRECTORY "${MSWORD_BUILD_ROOT}/tests" + VS_GLOBAL_VcpkgApplocalDeps "false" +) +foreach(config Debug Release RelWithDebInfo MinSizeRel) + string(TOUPPER "${config}" config_upper) + set_target_properties(opus_original_sttb_test PROPERTIES + RUNTIME_OUTPUT_DIRECTORY_${config_upper} "${MSWORD_BUILD_ROOT}/tests/${config}" + ) +endforeach() + +add_executable(opus_original_plc_test + Opus/wordtech/clsplc.c + port/original/opus_asm_plc_adapters.cpp + port/original/opus_original_plc_test.c +) +target_compile_definitions(opus_original_plc_test PRIVATE + WIN WIN23 CRLF NONATIVE OPUS_X64 NOMINMAX +) +target_include_directories(opus_original_plc_test PRIVATE ${OPUS_ORIGINAL_INCLUDE_DIRS}) +target_link_libraries(opus_original_plc_test PRIVATE opus_x64_runtime user32) +if(MSVC) + target_compile_options(opus_original_plc_test PRIVATE /J /W3 /wd4005) +endif() +set_target_properties(opus_original_plc_test PROPERTIES + FOLDER "Original Opus x64/tests" + RUNTIME_OUTPUT_DIRECTORY "${MSWORD_BUILD_ROOT}/tests" + VS_GLOBAL_VcpkgApplocalDeps "false" +) +foreach(config Debug Release RelWithDebInfo MinSizeRel) + string(TOUPPER "${config}" config_upper) + set_target_properties(opus_original_plc_test PROPERTIES + RUNTIME_OUTPUT_DIRECTORY_${config_upper} "${MSWORD_BUILD_ROOT}/tests/${config}" + ) +endforeach() + +add_executable(opus_sdm_cab_test + port/original/opus_sdm_cab_test.cpp +) +target_compile_features(opus_sdm_cab_test PRIVATE cxx_std_20) +target_compile_definitions(opus_sdm_cab_test PRIVATE + WIN WIN23 CRLF NONATIVE OPUS_X64 NOMINMAX +) +target_include_directories(opus_sdm_cab_test PRIVATE ${OPUS_ORIGINAL_INCLUDE_DIRS}) +target_link_libraries(opus_sdm_cab_test PRIVATE opus_x64_runtime user32) +if(MSVC) + target_compile_options(opus_sdm_cab_test PRIVATE /J /W4 /permissive-) +endif() +set_target_properties(opus_sdm_cab_test PROPERTIES + FOLDER "Original Opus x64/tests" + RUNTIME_OUTPUT_DIRECTORY "${MSWORD_BUILD_ROOT}/tests" + VS_GLOBAL_VcpkgApplocalDeps "false" +) +foreach(config Debug Release RelWithDebInfo MinSizeRel) + string(TOUPPER "${config}" config_upper) + set_target_properties(opus_sdm_cab_test PROPERTIES + RUNTIME_OUTPUT_DIRECTORY_${config_upper} "${MSWORD_BUILD_ROOT}/tests/${config}" + ) +endforeach() + +add_executable(opus_original_command_test + port/original/opus_original_command_test.c +) +add_dependencies(opus_original_command_test opus_generated_commands) +target_include_directories(opus_original_command_test PRIVATE + "${OPUS_GENERATED_COMMAND_DIR}" + "${CMAKE_CURRENT_SOURCE_DIR}/Opus" +) +if(MSVC) + target_compile_options(opus_original_command_test PRIVATE /W4) +endif() +set_target_properties(opus_original_command_test PROPERTIES + FOLDER "Original Opus x64/tests" + RUNTIME_OUTPUT_DIRECTORY "${MSWORD_BUILD_ROOT}/tests" + VS_GLOBAL_VcpkgApplocalDeps "false" +) +foreach(config Debug Release RelWithDebInfo MinSizeRel) + string(TOUPPER "${config}" config_upper) + set_target_properties(opus_original_command_test PROPERTIES + RUNTIME_OUTPUT_DIRECTORY_${config_upper} "${MSWORD_BUILD_ROOT}/tests/${config}" + ) +endforeach() + +# Future product executables link this original-source archive and inherit the +# translated assembly/native-handle runtime at the library boundary. +target_link_libraries(opus_original_engine PUBLIC opus_x64_runtime user32) + +# Product executable for Visual Studio's Startup Item list. The Unicode entry +# adapter converts the modern process command line, then transfers control to +# Microsoft's original Opus WinMain and its original window/message loop. +add_executable(WORD1 WIN32 + port/original/opus_original_startup_probe.cpp + port/word1.rc + port/winword.manifest +) +add_dependencies(WORD1 opus_original_engine) +target_compile_features(WORD1 PRIVATE cxx_std_20) +target_compile_definitions(WORD1 PRIVATE + WIN WIN23 CRLF NONATIVE OPUS_X64 NOMINMAX UNICODE _UNICODE +) +target_link_libraries(WORD1 PRIVATE opus_original_engine opus_x64_runtime user32 dbghelp) +if(MSVC) + target_compile_options(WORD1 PRIVATE /J /W3 /wd4005 /utf-8) + target_link_options(WORD1 PRIVATE /DYNAMICBASE /HIGHENTROPYVA /NXCOMPAT /MANIFEST:NO) +endif() +set_target_properties(WORD1 PROPERTIES + FOLDER "Original Opus x64/product" + OUTPUT_NAME "${MSWORD_PRODUCT_OUTPUT_NAME}" + VS_GLOBAL_VcpkgApplocalDeps "false" +) + +# Diagnostic executable that force-links the same original startup graph as +# WORD1 without product resources. It remains useful as an all-symbol gate. +add_executable(opus_original_startup_probe EXCLUDE_FROM_ALL WIN32 + port/original/opus_original_startup_probe.cpp +) +add_dependencies(opus_original_startup_probe opus_original_engine) +target_compile_features(opus_original_startup_probe PRIVATE cxx_std_20) +target_compile_definitions(opus_original_startup_probe PRIVATE + WIN WIN23 CRLF NONATIVE OPUS_X64 NOMINMAX UNICODE _UNICODE +) +target_link_libraries(opus_original_startup_probe PRIVATE opus_original_engine opus_x64_runtime user32 dbghelp) +set_target_properties(opus_original_startup_probe PROPERTIES + FOLDER "Original Opus x64/port probes" + RUNTIME_OUTPUT_DIRECTORY "${MSWORD_BUILD_ROOT}/probes" + VS_GLOBAL_VcpkgApplocalDeps "false" +) +foreach(config Debug Release RelWithDebInfo MinSizeRel) + string(TOUPPER "${config}" config_upper) + set_target_properties(opus_original_startup_probe PROPERTIES + RUNTIME_OUTPUT_DIRECTORY_${config_upper} "${MSWORD_BUILD_ROOT}/probes/${config}" + ) +endforeach() + +add_executable(opus_original_strtbl_test + Opus/strtbl.c + port/original/opus_original_strtbl_test.cpp +) +target_compile_definitions(opus_original_strtbl_test PRIVATE + WIN WIN23 CRLF NONATIVE OPUS_X64 NOMINMAX +) +target_include_directories(opus_original_strtbl_test PRIVATE ${OPUS_ORIGINAL_INCLUDE_DIRS}) +target_link_libraries(opus_original_strtbl_test PRIVATE user32) +if(MSVC) + target_compile_options(opus_original_strtbl_test PRIVATE /J /W3 /wd4005) +endif() +set_target_properties(opus_original_strtbl_test PROPERTIES + FOLDER "Original Opus x64/tests" + RUNTIME_OUTPUT_DIRECTORY "${MSWORD_BUILD_ROOT}/tests" + VS_GLOBAL_VcpkgApplocalDeps "false" +) +foreach(config Debug Release RelWithDebInfo MinSizeRel) + string(TOUPPER "${config}" config_upper) + set_target_properties(opus_original_strtbl_test PROPERTIES + RUNTIME_OUTPUT_DIRECTORY_${config_upper} "${MSWORD_BUILD_ROOT}/tests/${config}" + ) +endforeach() + +add_executable(opus_x64_runtime_test + port/original/opus_x64_runtime_test.cpp + port/original/opus_x64_layout_test_fixture.c +) +target_compile_features(opus_x64_runtime_test PRIVATE cxx_std_20) +target_compile_definitions(opus_x64_runtime_test PRIVATE + WIN WIN23 CRLF NONATIVE OPUS_X64 NOMINMAX +) +target_include_directories(opus_x64_runtime_test PRIVATE ${OPUS_ORIGINAL_INCLUDE_DIRS}) +target_link_libraries(opus_x64_runtime_test PRIVATE opus_x64_runtime user32 gdi32) +set_target_properties(opus_x64_runtime_test PROPERTIES + FOLDER "Original Opus x64/tests" + RUNTIME_OUTPUT_DIRECTORY "${MSWORD_BUILD_ROOT}/tests" + VS_GLOBAL_VcpkgApplocalDeps "false" +) +foreach(config Debug Release RelWithDebInfo MinSizeRel) + string(TOUPPER "${config}" config_upper) + set_target_properties(opus_x64_runtime_test PROPERTIES + RUNTIME_OUTPUT_DIRECTORY_${config_upper} "${MSWORD_BUILD_ROOT}/tests/${config}" + ) +endforeach() + +enable_testing() +add_test(NAME opus_original_strtbl_test COMMAND $) +add_test(NAME opus_x64_runtime_test COMMAND $) +add_test(NAME opus_original_sttb_test COMMAND $) +add_test(NAME opus_original_plc_test COMMAND $) +add_test(NAME opus_original_command_test COMMAND $) +add_test(NAME word1_port_smoke_test COMMAND $ --self-test) diff --git a/src/CMakePresets.json b/src/CMakePresets.json new file mode 100644 index 0000000..9f6de8e --- /dev/null +++ b/src/CMakePresets.json @@ -0,0 +1,45 @@ +{ + "version": 6, + "cmakeMinimumRequired": { + "major": 3, + "minor": 25, + "patch": 0 + }, + "configurePresets": [ + { + "name": "x64", + "hidden": true, + "generator": "Visual Studio 17 2022", + "architecture": { + "value": "x64", + "strategy": "set" + }, + "binaryDir": "${sourceDir}/../out", + "cacheVariables": { + "CMAKE_INTERMEDIATE_DIR_STRATEGY": "SHORT" + } + }, + { + "name": "x64-debug", + "displayName": "Word x64 Debug", + "inherits": "x64" + }, + { + "name": "x64-release", + "displayName": "Word x64 Release", + "inherits": "x64" + } + ], + "buildPresets": [ + { + "name": "x64-debug", + "configurePreset": "x64-debug", + "configuration": "Debug" + }, + { + "name": "x64-release", + "configurePreset": "x64-release", + "configuration": "Release" + } + ] +} diff --git a/src/Opus/13353412 b/src/Opus/13353412 new file mode 100644 index 0000000..1b8b845 --- /dev/null +++ b/src/Opus/13353412 @@ -0,0 +1,1313 @@ +/* S C R E E N 2 . C */ +/* This routine sets up the screen position used by Word relative to the +current device. */ + +#define NOGDICAPMASKS +#define NOVIRTUALKEYCODES +#define NOWINMESSAGES +#define NOWINSTYLES +#define NOCLIPBOARD +#define NOCTLMGR +#define NOMENUS + +#include "word.h" +DEBUGASSERTSZ /* WIN - bogus macro for assert string */ +#include "heap.h" +#include "ch.h" +#include "disp.h" +#include "screen.h" +#include "props.h" +#include "doc.h" +#include "format.h" +#include "scc.h" +#include "print.h" +#include "resource.h" +#include "file.h" +#include "layout.h" +#include "message.h" +#include "prompt.h" +#include "sel.h" +#include "debug.h" +#include "sdmdefs.h" +#include "sdmver.h" +#include "sdm.h" + +/* G L O B A L S */ +struct SCI vsci; + +/* BMI: { hbm, dxs, dys, fDiscardable, idcbMax, dxpEach } */ + + struct BMI vbmiEmpty = { + NULL, 0, 0, fFalse, 0, 0 }; + + +/* following array describes bitmaps */ +#ifdef WIN23 + /* pointer to one of the arrays below */ + struct BMI *mpidrbbmi; + /* win 2 bitmaps */ + struct BMI mpidrbbmi2 [] = { + { NULL, dxpChVis, dypChVis, fFalse, + idcbMaxChVis, dxpChVisEach }, + /* idrbChVis */ + + { NULL, dxpOtlPat*idcbMaxOtlPat,dypOtlPat2,fFalse, + idcbMaxOtlPat,dxpOtlPat }, + /*idrbOtlPat */ + + { NULL, 0, 0, fFalse, idcbMaxScrptPos*2, 0 }, + /* idrbScrptPos */ + { NULL, 0, 0, fFalse, idcbMaxRulerToggles*2, 0 }, + /* idrbRulerToggles */ + { NULL, 0, 0, fFalse, idcbMaxRulerMarks*2, 0 }, + /* idrbRulerMarks */ + { NULL, 0, 0, fFalse, idcbMaxRibbon*2, 0 }, + /* idrbRibbon */ + { NULL, 0, 0, fFalse, idcbMaxHdrIconBar, 0 }, + /* idrbHdrIconBar */ + { NULL, 0, 0, fFalse, idcbMaxOutlineIcnBr*2, 0 }, + /* idrbOutlineIcnBr */ + { NULL, 0, 0, fFalse, idcbMaxPageview, 0 }, + /* idrbPageview */ + { NULL, 0, 0, fFalse, idcbMaxRulerAlign*2, 0 }, + /* idrbRulerAlign */ +}; + /* win 3 bitmaps */ + struct BMI mpidrbbmi3 [] = { + { NULL, dxpChVis, dypChVis, fFalse, + idcbMaxChVis, dxpChVisEach }, + /* idrbChVis */ + + { NULL, dxpOtlPat*idcbMaxOtlPat,dypOtlPat3,fFalse, + idcbMaxOtlPat,dxpOtlPat }, + /*idrbOtlPat */ + + { NULL, 0, 0, fFalse, idcbMaxScrptPos, 0 }, + /* idrbScrptPos */ + { NULL, 0, 0, fFalse, idcbMaxScrptPos, 0 }, + /* idrbIScrptPos */ + { NULL, 0, 0, fFalse, idcbMaxRulerToggles, 0 }, + /* idrbRulerToggles */ + { NULL, 0, 0, fFalse, idcbMaxRulerToggles, 0 }, + /* idrbIRulerToggles */ + { NULL, 0, 0, fFalse, idcbMaxRulerMarks, 0 }, + /* idrbRulerMarks */ + { NULL, 0, 0, fFalse, idcbMaxRibbon, 0 }, + /* idrbRibbon */ + { NULL, 0, 0, fFalse, idcbMaxRibbon, 0 }, + /* idrbIRibbon */ + { NULL, 0, 0, fFalse, idcbMaxHdrIconBar, 0 }, + /* idrbHdrIconBar */ + { NULL, 0, 0, fFalse, idcbMaxOutlineIcnBr, 0 }, + /* idrbOutlineIcnBr */ + { NULL, 0, 0, fFalse, idcbMaxPageview, 0 }, + /* idrbPageview */ + { NULL, 0, 0, fFalse, idcbMaxRulerAlign, 0 }, + /* idrbRulerAlign */ + { NULL, 0, 0, fFalse, idcbMaxRulerAlign, 0 }, + /* idrbIRulerAlign */ +}; + +#else + struct BMI mpidrbbmi [] = { + { NULL, dxpChVis, dypChVis, fFalse, + idcbMaxChVis, dxpChVisEach }, + /* idrbChVis */ + + { NULL, dxpOtlPat*idcbMaxOtlPat,dypOtlPat,fFalse, + idcbMaxOtlPat,dxpOtlPat }, + /*idrbOtlPat */ + + { NULL, 0, 0, fFalse, idcbMaxScrptPos*2, 0 }, + /* idrbScrptPos */ + { NULL, 0, 0, fFalse, idcbMaxRulerToggles*2, 0 }, + /* idrbRulerToggles */ + { NULL, 0, 0, fFalse, idcbMaxRulerMarks*2, 0 }, + /* idrbRulerMarks */ + { NULL, 0, 0, fFalse, idcbMaxRibbon*2, 0 }, + /* idrbRibbon */ + { NULL, 0, 0, fFalse, idcbMaxHdrIconBar, 0 }, + /* idrbHdrIconBar */ + { NULL, 0, 0, fFalse, idcbMaxOutlineIcnBr*2, 0 }, + /* idrbOutlineIcnBr */ + { NULL, 0, 0, fFalse, idcbMaxPageview, 0 }, + /* idrbPageview */ + { NULL, 0, 0, fFalse, idcbMaxRulerAlign*2, 0 }, + /* idrbRulerAlign */ +}; + +#endif /* WIN23 */ + +int vfRestartDisplay=fFalse; +long dtickCaret = 0; +struct DCIB *vpdcibDisplayFli; +struct DRDL vdrdlDisplayFli; /* dl and dr info used in DisplayFli */ +int vdbmgDevice; /* indicates which set of bitmaps to use. +This varies depending on the target device resolution */ + + +/* E X T E R N A L S */ +extern struct PREF vpref; +extern struct SEL selCur; +extern struct WWD **hwwdCur; +extern struct SCC vsccAbove; +extern struct DOD **mpdochdod[]; +extern struct SCI vsci; +extern struct PRI vpri; +extern struct FLI vfli; +extern struct STTB **vhsttbFont; +extern int vlm; +extern int vwWinVersion; +extern HCURSOR vhcPrvwCross; +extern HCURSOR vhcRecorder; +extern HCURSOR vhcHelp; +extern HCURSOR vhcOtlCross; +extern HCURSOR vhcOtlVert; +extern HCURSOR vhcOtlHorz; +extern HCURSOR vhcStyWnd; +extern int vflm; +extern struct FTI vfti; +extern struct FTI vftiDxt; +extern struct MERR vmerr; +extern struct BMI vbmiEmpty; +extern BOOL vfSccVert; +extern int vfInitializing; +extern struct FCE rgfce[ifceMax]; +extern HANDLE vhInstance; +extern int docMac; +extern CHAR szNone[]; + +extern struct WWD **mpwwhwwd[]; + + +/* C o n n e c t t o F T i bits */ + +#define cftScreen 0 +#define cftPrinter 1 +#define cftIC 2 +#define cftForce 4 /* force creation */ + + +/* A l l o c H d c P r i n t e r */ +/* attempt to validate vpri.hdc */ +/* fIC tells whether we should make a DC or an IC (an IC is an information + context, effectively a cheaper DC that can't draw but can supply font + widths and device caps. */ + +/* %%Function:AllocHdcPrinter %%Owner:bryanl */ +AllocHdcPrinter( fIC ) +int fIC; +{ + if (vpri.hdc != NULL && fIC == vpri.fIC) + return; + + Assert( vpri.hdc == NULL ); /* better be true or we'll be forgetting to free the old */ + +/* no printer is specified in the user's WIN.INI */ + if (vpri.hszPrDriver == NULL) + return; + +/* create the DC (or IC) */ + ShrinkSwapArea(); + StartUMeas( umCreatePrinterDC ); /* profile the creation of the DC */ + if (fIC) + { + /* HACK: Pscript on None rips on 2nd CreateIC call in Win 2.xx */ + if (vwWinVersion < 0x0300 && FEqNcSz(*vpri.hszPrPort, szNone) && + FEqNcSz(*vpri.hszPrDriver, SzSharedKey("PSCRIPT",pscript))) + return; + vpri.hdc = CreateIC ( (LPSTR) **vpri.hszPrDriver, (LPSTR) **vpri.hszPrinter, + (LPSTR) **vpri.hszPrPort, (LPSTR) NULL ); + } + else + { +/* can't print if printer is connected to "None" */ + if (FEqNcSz(*vpri.hszPrPort, szNone)) + return; + vpri.hdc = CreateDC ( (LPSTR) **vpri.hszPrDriver, (LPSTR) **vpri.hszPrinter, + (LPSTR) **vpri.hszPrPort, (LPSTR) NULL ); + } + StopUMeas( umCreatePrinterDC ); + GrowSwapArea(); + +/* Grab device pixel-per-inch constants for this printer */ + + if (vpri.hdc == NULL) + { +#ifdef BRYANL + CommSzSz(SzFrame("Printer DC Allocation Failed!!"),SzFrame("")); +#endif /* BRYANL */ + return; + } + LogGdiHandle(vpri.hdc, 1085); + + vpri.fIC = fIC; + +/* Set the size of the paper and a few other values for this printer. */ + PrinterMetrics(); + +/* The printer may have changed in such a way that its fonts have changed + (i.e. portrait to landscape). We must re-initialize our list of fonts. */ + if (vpri.hsttbPaf == hNil) + FillHsttbPaf( &vpri.hsttbPaf ); + + GetPrintEnv(); + if (!vpri.fHaveEnv && vpri.hprenv != hNil) + { + int doc; + struct DOD *pdod, **hdod; + + for (doc = docMinNormal; doc < docMac; doc++) + { + hdod = mpdochdod[doc]; + if (hdod == hNil) + continue; + pdod = *hdod; + if (pdod->fMother) + { + struct FIB fib; + + pdod->fEnvDirty = TRUE; + /* new file? dirty! */ + if (pdod->fn == fnNil || !PfcbFn(pdod->fn)->fHasFib) + continue; + + /* get fib */ + FetchFib(pdod->fn, &fib, pn0); + if (fib.cbPrEnv != 0) + pdod->fEnvDirty = FEnvDirty(pdod->fn, fib.fcPrEnv, fib.cbPrEnv); + } + } + } + vpri.fHaveEnv = TRUE; + GetPubCharInfo(); +} + + +/* G e t P u b C h a r I n f o */ +/* See if printer supports publishing characters */ +/* Sets vpri.fSupportPubChars depending on result of SETCHARSET Escape. */ +/* %%Function:GetPubCharInfo %%Owner:tonykr */ +GetPubCharInfo() +{ + int wCharSet = 1; + + Assert(vpri.hdc != NULL); + if (Escape(vpri.hdc, SETCHARSET, NULL, (LPINT)&wCharSet,(LPINT)NULL)) + { /* Driver supports special pub chars escape */ + vpri.fSupportPubChars = fTrue; + wCharSet = 0; + Escape(vpri.hdc, SETCHARSET, NULL, (LPINT)&wCharSet, (LPINT)NULL); + } + else + vpri.fSupportPubChars = fFalse; +} + + +/* D i s c o n n e c t F r o m F t i */ +/* if any device is connected to pfti, disconnect it. This means + freeing DC's, fonts, etc. */ + +/* %%Function:DisconnectFromFti %%Owner:bryanl */ +DisconnectFromFti( pfti ) +struct FTI *pfti; +{ + struct FTI **ppfti; + + if (vsci.pfti == pfti) + ppfti = &vsci.pfti; + else if (vpri.pfti == pfti) + ppfti = &vpri.pfti; + else + return; /* nothing is connected to FTI */ + + if (pfti->pfce != NULL) + FreeFontsPfti( pfti ); + *ppfti = NULL; + if (pfti->fPrinter) + { + FreeHdcPrinter(); + pfti->fTossedPrinterDC = fFalse; + } + + pfti->hfont = NULL; +} + + +/* F r e e H d c P r i n t e r */ + +/* %%Function:FreeHdcPrinter %%Owner:bryanl */ +FreeHdcPrinter() +{ + + +#ifdef BMCACHE + extern struct BMCACHE vBMCache; +#endif /* BMCACHE */ + + + + if (vpri.hdc) + { + UnlogGdiHandle(vpri.hdc, 1085); + DeleteDC( vpri.hdc ); + vpri.hdc = NULL; + } + + + +#ifdef BMCACHE + /* Free the cached bitmap because it was stretched for the display to + reflect its appearance on the printer. */ + + if (vBMCache.ca.doc != docNil) + FreeBitmapCache(); +#endif /* BMCACHE */ + + +} + + +/* %%Function:FReviveTossedPrinterDC %%Owner:bryanl */ +EXPORT FReviveTossedPrinterDC( pfce ) +struct FCE *pfce; +{ + Assert( vpri.pfti ); + Assert( vpri.pfti->fTossedPrinterDC ); + + Assert( vlm != lmPrint ); +#ifdef BRYANL + CommSzSz(SzFrame("Reviving tossed printer DC"),SzFrame("")); +#endif + AllocHdcPrinter( fTrue ); + if (vpri.hdc != NULL) + { + vpri.pfti->fTossedPrinterDC = fFalse; + return fTrue; + } + else + { +#ifdef DFONT + CommSzSz(SzFrame("Could not revive tossed printer DC"),szEmpty); +#endif /* DFONT */ + SetErrorMat(matMem); +/* Printer DC is not available. We are only using it as a reference for + display as print anyway; just return an FCID with ibstFontNil; this will + tell the screen request to get the system font. Width is a problem, + so we just use that of the system font, mapped to the screen. */ + + pfce->fcidActual.ibstFont = ibstFontNil; +/* following line is for safety and for the benefit of consistency checks */ + pfce->hfont = GetStockObject( DEVICEDEFAULT_FONT ); + pfce->dxpWidth = NMultDiv( vsci.dxpTmWidth, + vfli.dxuInch, vfli.dxsInch ); + pfce->fFixedPitch = fTrue; + vmerr.fPrintEmerg = fTrue; + return fFalse; + } +} + + + +#ifdef DEBUG +struct BMSI + { + int dxpSrc; + int dypSrc; + int dxpDest; + int dypDest; +#ifdef WIN23 +} mpidrbbmsi [idrbMax3]; +#else +} mpidrbbmsi [idrbMax]; +#endif /* WIN23 */ +#endif /* DEBUG */ +HANDLE HFromIbmds0(); /* in rcinit.c */ +HANDLE HFromIbmds1(); /* in rcbmp1.c */ +HANDLE HFromIbmds2(); /* in rcbmp2.c */ +HANDLE HFromIbmds3(); /* in rcbmp3.c */ +HANDLE HFromIbmds4(); /* in rcbmp4.c */ +#ifdef WIN23 +HANDLE HFromIbmds13(); /* in rcbmp1.c */ +HANDLE HFromIbmds23(); /* in rcbmp2.c */ +HANDLE HFromIbmds43(); /* in rcbmp4.c */ +#endif /* WIN23 */ +csconst struct EDBMG +{ + int dIdrbIbms; + PFN pfnLoad; +} + + +#ifdef WIN23 +dndbmg2[] = + +{ + { -1, HFromIbmds4 }, + /* dbmg8514 */ + { 8, HFromIbmds3 }, + /* dbmgSigma */ + { -1, HFromIbmds2 }, + /* dbmgVGA */ + { -1, HFromIbmds1 }, + /* dbmgEGA */ + { -1, HFromIbmds3 }, + /* dbmgCGA */ +}, +dndbmg3[] = + +{ + { -1, HFromIbmds43 }, + /* dbmg8514 */ + { -1, HFromIbmds23 }, + /* dbmgVGA */ + { -1, HFromIbmds13 }, + /* dbmgEGA */ +}; +#else +dndbmg[] = + +{ + { -1, HFromIbmds4 }, + /* dbmg8514 */ + { 8, HFromIbmds3 }, + /* dbmgSigma */ + { -1, HFromIbmds2 }, + /* dbmgVGA */ + { -1, HFromIbmds1 }, + /* dbmgEGA */ + { -1, HFromIbmds3 }, + /* dbmgCGA */ +}; +#endif /* WIN23 */ + + +/* F L o a d R e s o u r c e I d r b */ +/* FLoadResourceIdrb + + Inputs: + idrb resource id for bitmap + + mpidrbbmi [idrb] must be filled out as follows: + + bmi.dxp, bmi.dyp: desired size of bitmap. it will be + stretched to fit if necessary + + hdcCompat an hdc to use as the basis + for compatible DC creation + + Outputs: pbmi->hbm: handle of bitmap created + + Return Value: fTrue on success,fFalse on failure +*/ + +/* %%Function:FLoadResourceIdrb %%Owner:bryanl */ +FLoadResourceIdrb( idrb ) +int idrb; +{ + extern int vdbmgDevice; + struct BMI *pbmi; + BITMAP bm; + HBITMAP hbmSrc = NULL, hbmDest = NULL; + HDC hdcSrc = NULL, hdcDest = NULL; + +#ifdef WIN23 + int sbmSrc, sbmDest; + HDC hdcCompat = NULL; + if (vsci.fWin3Visuals) + hdcCompat = GetDC(NULL); /* get a screen DC for color bitmaps */ + if (hdcCompat == NULL) /* else a memory DC for mono bitmaps */ + hdcCompat = vsci.mdcdScratch.hdc; + Assert(hdcCompat != NULL); + Assert(idrb >= 0 && idrb < (vsci.fWin3Visuals ? idrbMax3 : idrbMax2)); +#else + Assert(idrb >= 0 && idrb < idrbMax); +#endif /* WIN23 */ + pbmi = &mpidrbbmi [idrb]; + + Assert( pbmi->dxp ); + Assert( pbmi->dyp ); + + if (pbmi->hbm) + return fTrue; + + /* following Assert is necessary because visi bitmap must load + during initialization, so we don't try to do it later when + filling the screen cache, when the scratchDC is spoken for */ + + Assert( vfInitializing || (idrb != idrbChVis) ); + +/* actually it is loaded in initwin.c.... */ + Assert(idrb != idrbChVis); + +/* be sure we have a source and destination DC, for stretching and graying */ + if (!FSetPmdcdPbmi( &vsci.mdcdScratch, &vbmiEmpty )) + goto LFail; + hdcDest = vsci.mdcdScratch.hdc; + Assert( hdcDest ); + +#ifdef WIN23 + if (vsci.fWin3Visuals) + sbmDest = SetStretchBltMode(hdcDest, COLORONCOLOR); +#endif /* WIN23 */ + +/* get the bitmap */ +#ifdef WIN23 + if (vsci.fWin3Visuals) + { + Assert(vdbmgDevice <= dbmgLast3); + hbmSrc = (*dndbmg3[vdbmgDevice].pfnLoad)(hdcCompat, idrb+dndbmg3[vdbmgDevice].dIdrbIbms); + } + else + { + Assert(vdbmgDevice <= dbmgLast2); + hbmSrc = (*dndbmg2[vdbmgDevice].pfnLoad)(idrb+dndbmg2[vdbmgDevice].dIdrbIbms); + } +#else + Assert(vdbmgDevice <= dbmgLast); + hbmSrc = (*dndbmg[vdbmgDevice].pfnLoad)(idrb+dndbmg[vdbmgDevice].dIdrbIbms); +#endif /* WIN23 */ + + if (hbmSrc == NULL) + goto LFail; + +/* get source bitmap size */ + GetObject( hbmSrc, sizeof (BITMAP), (LPSTR) &bm ); + +/* determine if we have to change its size */ + if (pbmi->dxp != bm.bmWidth || pbmi->dyp != bm.bmHeight) + { + + Scribble(15, 'X'); + +#ifdef DCSRC + CommSz(SzShared("have to stretchblt!\r\n")); +#endif /* DCSRC */ + +/* get a source DC */ + if (!FSetPmdcdPbmi( &vsci.mdcdBmp, &vbmiEmpty )) + goto LFail; + hdcSrc = vsci.mdcdBmp.hdc; + Assert( hdcSrc && hdcDest ); +#ifdef WIN23 /* REVIEW */ + if (vsci.fWin3Visuals) + sbmSrc = SetStretchBltMode(hdcSrc, COLORONCOLOR ); +#endif /* WIN23 */ + +/* select bitmap into source, gray brush into destination */ + if (SelectObject( hdcDest, GetStockObject(GRAY_BRUSH)) == NULL) + goto LFail; + if (SelectObject( hdcSrc, hbmSrc ) == NULL) + goto LFail; + +/* create destination bitmap & select it into dest DC */ +#ifdef WIN23 + /* for memory DC's, the bitmap type is mono by default. + We need to create hbmDest compatible with a color + screenDC to get a color bitmap. + */ + if ((hbmDest = CreateCompatibleBitmap( hdcCompat, pbmi->dxp, + pbmi->dyp )) == NULL) +#else + if ((hbmDest = CreateCompatibleBitmap( hdcDest, pbmi->dxp, + pbmi->dyp )) == NULL) +#endif /* WIN23 */ + goto LFail; + LogGdiHandle(hbmDest, 1027); + if (SelectObject( hdcDest, hbmDest ) == NULL) + goto LFail; + +/* note: StretchBlt (hdcDest, xpDest, ypDest, dxpDest, dypDest, + hdcSrc, xpSrc, ypSrc, dxpSrc, dypSrc, rop); */ + + StretchBlt (hdcDest, 0, 0, pbmi->dxp, pbmi->dyp, + hdcSrc, 0, 0, bm.bmWidth, bm.bmHeight, + ROP_S); + + pbmi->hbm = hbmDest; + +/* make sure the pbmi's of the mdcd's are correct */ + SelectObject( vsci.mdcdBmp.hdc, vbmiEmpty.hbm ); + UnlogGdiHandle(hbmSrc, -1); + DeleteObject( hbmSrc ); + Scribble(15, ' '); + } + +/* already the right size, just select into correct DC */ + else + { + SelectObject(hdcDest, hbmSrc); + pbmi->hbm = hbmSrc; + } + + vsci.mdcdScratch.pbmi = pbmi; + SetTextColor( vsci.mdcdScratch.hdc, RGB( 0,0,0 ) ); +#ifdef WIN23 + if (vsci.fWin3Visuals) + { + if (hdcSrc) + SetStretchBltMode(hdcSrc, sbmSrc); + SetStretchBltMode(hdcDest, sbmDest); + } +#endif /* WIN23 */ + +#ifdef DEBUG + mpidrbbmsi[idrb].dxpSrc = bm.bmWidth; + mpidrbbmsi[idrb].dypSrc = bm.bmHeight; + mpidrbbmsi[idrb].dxpDest = pbmi->dxp; + mpidrbbmsi[idrb].dypDest = pbmi->dyp; +#endif /* DEBUG */ +#ifdef WIN23 + if (hdcCompat != vsci.mdcdScratch.hdc) + ReleaseDC(NULL, hdcCompat); +#endif /* WIN23 */ + return fTrue; + +LFail: + +#ifdef DCSRC + CommSzNum(SzShared("FLoadResourceIdrb: failing: idrb = "), idrb); +#endif /* DCSRC */ + +/* make sure the pbmi's of the mdcd's are correct */ + if (hdcDest) + { + SelectObject( vsci.mdcdScratch.hdc, vbmiEmpty.hbm ); +#ifdef WIN23 + if (vsci.fWin3Visuals) + { + SetStretchBltMode(hdcDest, sbmDest); + } +#endif /* WIN23 */ + } + if (hdcSrc) + { + SelectObject( vsci.mdcdBmp.hdc, vbmiEmpty.hbm ); +#ifdef WIN23 + if (vsci.fWin3Visuals) + { + SetStretchBltMode(hdcSrc, sbmSrc); + } +#endif /* WIN23 */ + } + if (hbmSrc) + { + UnlogGdiHandle(hbmSrc, -1); + DeleteObject( hbmSrc ); + } + if (hbmDest) + { + UnlogGdiHandle(hbmDest, 1027); + DeleteObject( hbmDest ); + } +#ifdef WIN23 + if (hdcCompat != vsci.mdcdScratch.hdc) + ReleaseDC(NULL, hdcCompat); +#endif /* WIN23 */ + return fFalse; +} + + +#ifdef DEBUG +/* %%Function:CmdDumpBitmapSizes %%Owner:bryanl */ +CMD CmdDumpBitmapSizes(pcmb) +CMB *pcmb; +{ + extern int vdbmgDevice; + int idrb; +#ifdef WIN23 + int idrbMax = (vsci.fWin3Visuals ? idrbMax3 : idrbMax2); +#endif /* WIN23 */ + struct CA ca; + SetWholeDoc(docScrap, PcaSetNil(&ca)); + ScrapSz(SzShared("--------------- Bitmap sizing data ---------------")); + ScrapCRLF(); + ScrapSzNum(SzShared("vdbmgDevice = "), vdbmgDevice); + ScrapCRLF(); + for (idrb = 0; idrb < idrbMax; idrb++) + { + ScrapSzNum(SzShared("Sizing information: idrb = "), idrb); + ScrapSzNum(SzShared("\tdxpSrc = "), mpidrbbmsi[idrb].dxpSrc); + ScrapSzNum(SzShared("\tdypSrc = "), mpidrbbmsi[idrb].dypSrc); + ScrapCRLF(); + ScrapSzNum(SzShared("\tdxpDest = "), mpidrbbmsi[idrb].dxpDest); + ScrapSzNum(SzShared("\tdypDest = "), mpidrbbmsi[idrb].dypDest); + ScrapCRLF(); + ScrapCRLF(); + } + ScrapSz(SzShared("--------------- System Metrics -----------------")); + ScrapCRLF(); + ScrapSzNum(SzShared("\tcxIcon = "), GetSystemMetrics(SM_CXICON)); + ScrapSzNum(SzShared("\tcyIcon = "), GetSystemMetrics(SM_CYICON)); + ScrapCRLF(); + ScrapSzNum(SzShared("\tcxCursor = "), GetSystemMetrics(SM_CXCURSOR)); + ScrapSzNum(SzShared("\tcyCursor = "), GetSystemMetrics(SM_CYCURSOR)); + ScrapCRLF(); + ChangeClipboard(); + SetPromptMst(mstDbgBmpSize, pdcmPmt+pdcmCreate+pdcmRestOnInput); + return cmdOK; +} + + +#endif /* DEBUG */ + + +/* %%Function:FreePbmi %%Owner:bryanl */ +FreePbmi( pbmi ) +struct BMI *pbmi; + { /* Free bitmap in passed BMI structure if any; set size to 0. + Caller is responsible for assuring that the bitmap is not selected + into any DC. */ +#ifdef WIN23 + int idrbMax = (vsci.fWin3Visuals ? idrbMax3 : idrbMax2); +#endif /* WIN23 */ + + if (pbmi->hbm != NULL) + { +/* Avoid locked object RIPs; assure bitmap not selected into mem DC */ + if (vsci.mdcdScratch.pbmi->hbm == pbmi->hbm) + FSetPmdcdPbmi( &vsci.mdcdScratch, &vbmiEmpty ); + if (vsci.mdcdBmp.pbmi->hbm == pbmi->hbm) + FSetPmdcdPbmi( &vsci.mdcdBmp, &vbmiEmpty ); + + UnlogGdiHandle(pbmi->hbm, -1); +#ifdef DEBUG + Assert( DeleteObject( pbmi->hbm ) != NULL ); +#else + DeleteObject( pbmi->hbm ); +#endif + pbmi->hbm = NULL; + } + +/* keep size for resource bitmaps; it will be used if they have to be reloaded */ + if (!(pbmi >= mpidrbbmi && pbmi < &mpidrbbmi [idrbMax])) + pbmi->dxp = pbmi->dyp = 0; +} + + +/* P R I N T E R M E T R I C S */ +/* Fetch metrics for current printer */ +/* %%Function:PrinterMetrics %%Owner:bryanl */ +PrinterMetrics() +{ + int wEsc = DRAWPATTERNRECT; + struct PT ptPage; + + if (vpri.pfti == NULL || vpri.hdc == NULL) + return; + + /* Get default text color for printer */ + vpri.rgbText = GetTextColor(vpri.hdc); + vpri.fColor = GetDeviceCaps(vpri.hdc, NUMCOLORS) > 2; + + /* Get the page size */ + vpri.dxpPrintable = GetDeviceCaps( vpri.hdc, HORZRES ); + vpri.dypPrintable = GetDeviceCaps( vpri.hdc, VERTRES ); + if (!Escape( vpri.hdc, GETPHYSPAGESIZE, 0, (LPSTR) NULL, (LPSTR) &ptPage )) + { + /* The printer won't tell us it page size; we'll have to settle + for the printable area. */ + vpri.dxpRealPage = vpri.dxpPrintable; + vpri.dypRealPage = vpri.dypPrintable; + } + else + { + vpri.dxpRealPage = ptPage.xp; + vpri.dypRealPage = ptPage.yp; + } + + /* Determine the offset of the printable area on the page. */ + if (!Escape( vpri.hdc, GETPRINTINGOFFSET, 0, (LPSTR) NULL, (LPSTR) &vpri.ptUL )) + { + /* The printer won't tell us what the offset is; assume the + printable area is centered on the page. */ + vpri.ptUL.xp = (uns)(ptPage.xp - vpri.dxpPrintable) >> 1; + vpri.ptUL.yp = (uns)(ptPage.yp - vpri.dypPrintable) >> 1; + } + + /* store printer scaling factor, if any */ + vpri.ptScaleFactor.xp = vpri.ptScaleFactor.yp = 0; /* default */ + + if (GetDeviceCaps( vpri.hdc, RASTERCAPS ) & RC_SCALING) + Escape( vpri.hdc, GETSCALINGFACTOR, 0, (LPSTR) NULL, + (LPSTR) (LPPOINT) &vpri.ptScaleFactor ); + + vpri.dxmmRealPage = GetDeviceCaps(vpri.hdc, HORZSIZE); + vpri.dymmRealPage = GetDeviceCaps(vpri.hdc, VERTSIZE); + vfli.dxuInch = vpri.dxuInch = GetDeviceCaps(vpri.hdc, LOGPIXELSX); + vfli.dyuInch = vpri.dyuInch = GetDeviceCaps(vpri.hdc, LOGPIXELSY); + + /* find out whether print driver supports rules */ + vpri.fDPR = Escape(vpri.hdc, QUERYESCSUPPORT, sizeof(int), + (int far *)&wEsc, (LPSTR)0) > 0; +#ifdef BRYANL + { + int rgw [2]; + + rgw [0] = vfli.dxuInch; + rgw [1] = vfli.dyuInch; + CommSzRgNum( SzShared("dxuInch, dyuInch: "), rgw, 2 ); + } +#endif +} + + +#ifdef NOTUSED +/* F E X P A N D P B M I */ +/* %%Function:FExpandPbmi %%Owner:NOTUSED */ +FExpandPbmi( pbmi, dxp, dyp ) +struct BMI *pbmi; +int dxp; +int dyp; + { /* Expand bitmap described by passed bmi structure to be at least + { dxp, dyp } in size. Return TRUE if we were able to do this, + FALSE if not. The fields of *pbmi reflect, on return, the + size of the bitmap actually in *pbmi */ + + HDC hdc; + + if (pbmi->dxp >= dxp && pbmi->dyp >= dyp) + { /* bitmap is already big enough */ + Assert( pbmi->hbm != NULL || (dxp == 0 && dyp == 0) ); + return fTrue; + } + +/* Free existing bitmap if any */ + + if (pbmi->dxp != 0) + { + Assert( pbmi->hbm != NULL ); + + UnlogGdiHandle(pbmi->hbm); /* NOTUSED routine */ +#ifdef DEBUG + Assert( DeleteObject( pbmi->hbm ) != NULL ); +#else + DeleteObject( pbmi->hbm ); +#endif + } +#ifdef DEBUG + else + { + Assert( pbmi->dyp == 0 ); + } +#endif /* DEBUG */ + +/* Create a new bitmap of the size given */ + + Assert( vsci.hdcScratch ); + + if (FRareT( reExpandPbmi, (pbmi->hbm = pbmi->fDiscardable ? + CreateDiscardableBitmap( vsci.hdcScratch, dxp, dyp ) : + CreateCompatibleBitmap( vsci.hdcScratch, dxp, dyp ))) == NULL) + { + pbmi->dxp = pbmi->dyp = 0; + return fFalse; + } + LogGdiHandle(pbmi->hbm, ????); /* NOTUSED */ + + pbmi->dxp = dxp; + pbmi->dyp = dyp; + return fTrue; +} + + +#endif /* NOTUSED */ + + +/* G E T P R I N T E N V */ +/* Stores handle to current print environment in vpri */ +/* %%Function:GetPrintEnv %%Owner:bryanl */ +NATIVE GetPrintEnv() +{ + int cchEnv, cwEnv; + + if (vpri.hszPrinter == hNil || vpri.hszPrPort == hNil || vpri.hszPrDriver == hNil) + goto LFreePrenv; + + cchEnv = GetEnvironment((LPSTR) *vpri.hszPrPort, 0L, ichMaxProfileSz); + if (cchEnv == 0) + goto LFreePrenv; + + cwEnv = (cchEnv + 1) / 2; + + /* REVIEW cslbug : native bug */ + {{ /* !NATIVE - GetPrintEnv */ + if (vpri.hprenv == hNil) + { + if ((vpri.hprenv = HAllocateCw(cwEnv)) == hNil) + return; + } + else if (!FChngSizeHCw(vpri.hprenv, cwEnv, TRUE /* fShrink */)) + {{ + goto LFreePrenv; + }} /* !NATIVE - GetPrintEnv */ + }} + + GetEnvironment((LPSTR) *vpri.hszPrPort, (LPSTR) *vpri.hprenv, cchEnv); + + /* if odd # of chars in env, ensure last byte of last word isn't random */ + if (cchEnv % 2) + { + char *pch = *vpri.hprenv + cchEnv; + *pch = 0; + } + return; + + LFreePrenv: + FreePh(&vpri.hprenv); +} + + +/* F R E E F O N T S P F T I */ +/* %%Function:FreeFontsPfti %%Owner:bryanl */ +FreeFontsPfti( pfti ) +struct FTI *pfti; +{ + struct FCE *pfce; + + if (pfti == NULL) + return; + ResetFont( pfti->fPrinter ); + for ( pfce = pfti->pfce; pfce != NULL; pfce = pfce->pfceNext ) + { + Assert( pfce->fPrinter == pfti->fPrinter ); + FreeHandlesOfPfce( pfce ); + } + + pfti->pfce = NULL; +} + + +/* F R E E H A N D L E S O F P F C E */ +/* %%Function:FreeHandlesOfPfce %%Owner:bryanl */ +EXPORT FreeHandlesOfPfce( pfce ) +struct FCE *pfce; +{ + Assert(pfce); + Assert(pfce >= &rgfce[0] && pfce <= &rgfce[ifceMax-1]); + + if (pfce->hfont == NULL) + return; + +#ifdef DFONT + CommSzNum(SzFrame("Deleting font: "), pfce->hfont); +#endif /* DFONT */ + + if (pfce->hfont != hfontSpecNil) + { + UnlogGdiHandle(pfce->hfont, -1); + DeleteObject(pfce->hfont); + } + pfce->hfont = NULL; + + if (!pfce->fFixedPitch) + { + FreeHq( pfce->hqrgdxp ); + pfce->hqrgdxp = hqNil; + } +} + + + + + +/* FtcValidateFont */ +/* **** +* Description: does the verification of a font name for which +* we have a string, but no family +* returns the ftc for the font or wNinch for gray (null string) +* or valNil for errors +* This routine assume that there is an sz at pffn->szFfn, but that the +* rest of the ffn may be bogus, so it sets up the rest. +** **** */ + +/* %%Function:FtcValidateFont %%Owner:bryanl */ +int FtcValidateFont(pffn) +struct FFN *pffn; +{ + int cch; + CHAR *pch; + int fEnum; + int ftc; + + cch = CchSz (pffn->szFfn); /* cch includes null terminator */ + cch = CchStripString( pffn->szFfn, cch - 1 ) + 1; + + pffn -> ffid = FF_DONTCARE; + pffn -> cbFfnM1 = CbFfnFromCchSzFfn(cch) - 1; + + /* test for all blanks or null string */ + for (pch = pffn->szFfn; *pch == ' '; pch++, cch--) + ; + if (cch <= 1) /* just null term? */ + ftc = wNinch; /* gray return value */ + else + { + /* Get ibst of font name, adding to master table if necessary. Get the + ftc of the font by searching in mpfctibstFont, adding a new ftc + if needed, then apply the desired sprm. This returns a valid ftc or + valNil in case of failure to add to the table. + */ + + ftc = FtcChkDocFfn(selCur.doc, pffn); + } /* if */ + + if (FRareT(reRibbon, (ftc == valNil))) + SetErrorMat(matMem); + + return (ftc); + +} /* FtcValidateFont */ + + + +/* **** +-+utility+-+opus **** */ +/* **** +* Description: Get ibst of font name, adding to master table if +* necessary. Get the ftc of the font by searching in mpftcibstFont, +* adding a new ftc if needed +** **** */ + +/* %%Function:FtcChkDocFfn %%Owner:bryanl */ +FtcChkDocFfn(doc, pffn) +int doc; +struct FFN *pffn; +{ + int ibst; + + /* 1. search vhsttbFont for the font name string, adding it if not found */ + + if ((ibst = IbstFindSzFfn( vhsttbFont, pffn)) == iNil) + { /* Font is not already in table -- add it */ + + if ((ibst = IbstAddStToSttb( vhsttbFont, pffn )) == iNil || + vmerr.fMemFail) + return ftcDefault; + } + + + /* 2. Find mapped ftc, if any, or add new ftc and map it to + ibst. + */ + return (FtcFromDocIbst(doc, ibst)); +} + + +/* **** +-+utility+-+opus **** */ +/* **** +* Description: Given ibst of font, get the ftc of the font by +* searching in mpftcibstFont, adding a new ftc if needed +** **** */ + +/* %%Function:FtcFromDocIbst %%Owner:bryanl */ +FtcFromDocIbst(doc, ibst) +int doc; +int ibst; +{ + int ftc; + struct DOD *pdod; + int cbMac; + int cbMax; + IBSTFONT (**hmpftcibstFont)[]; + + if (ibst == ibstFontDefault) + return (ftcDefault); + + /* 1. is there already an ftc mapping to ibst? */ + + pdod = PdodMother( doc ); + for ( ftc = 1; ftc < pdod->ftcMac; ftc++ ) + if (ibst == (**pdod->hmpftcibstFont) [ftc]) + return (ftc); + + /* 2. Need to add a new ftc and map it to ibst */ + + /* Local copies used to avoid heap movement problems */ + hmpftcibstFont = pdod->hmpftcibstFont; + Assert( sizeof (IBSTFONT) == 1 ); + cbMac = pdod->ftcMac; + cbMax = pdod->ftcMax; + if (!FAssureHcb( &hmpftcibstFont, cbMac + sizeof (IBSTFONT), &cbMac, &cbMax )) + { + return (valNil); /* Not enough room -- bail out */ + } + + pdod = PdodMother( doc ); + (**hmpftcibstFont) [ftc = pdod->ftcMac++] = ibst; + pdod->ftcMax = cbMax; + Assert( pdod->ftcMax >= pdod->ftcMac ); + Assert( hmpftcibstFont == pdod->hmpftcibstFont ); + + return (ftc); +} + + +/* **** +-+utility+-+opus **** */ +/* **** +* Description: Set the document's font tables to their default value. +** **** */ +/* %%Function:ResetDocFonts %%Owner:bryanl */ +ResetDocFonts(doc) +int doc; +{ + /* done for docScrap when filling its font table. Set the doc's + hmpftcibst to default values */ + + struct DOD *pdod; + + pdod = PdodMother(doc); + + if (pdod->ftcMac == ftcMinUser) + return; + + Assert (pdod->hmpftcibstFont != hNil); + + if (!FChngSizeHCw( pdod->hmpftcibstFont, CwFromCch(ftcMinUser), fTrue /*fShrink*/)) + { + Assert (fFalse); /* bryan says shrinking will never fail */ + return; + } + + pdod = PdodMother(doc); /* reset after heap movement */ + + pdod->ftcMax = pdod->ftcMac = ftcMinUser; + (**pdod->hmpftcibstFont) [0] = ibstFontDefault; /* Tms Rmn */ + (**pdod->hmpftcibstFont) [1] = ibstFontDefault + 1; /* Symbol */ + (**pdod->hmpftcibstFont) [2] = ibstFontDefault + 2; /* Helv */ +} + + + +/* F A S S U R E H C B */ + +/* %%Function:FAssureHCb %%Owner:bryanl */ +FAssureHCb( ph, cb, pcbMac, pcbMax ) +int ***ph; +int cb; +int *pcbMac; +int *pcbMax; + { /* Inputs: *ph -- a handle + *pcbMax - amount of space currently allocated to handle + (0 iff *ph is NULL) + cb -- amount of space desired in handle + Outputs: *ph -- if successful, a handle with cb bytes of space + else hNil + *pcbMac -- if successful, == cb, else unchanged or 0 + *pcbMax -- amount of space allocated to handle on return + + Return: fTrue if we returned with at least cb bytes of space in the + handle; fFalse if we tried to grow/allocate it and failed. +*/ + +/* easy case, already have enough space */ + + if (cb <= *pcbMax) + { + *pcbMac = cb; + return fTrue; + } + + if (*pcbMax > 0) + { + Assert( *ph != hNil ); + + if (!FChngSizeHCb( *ph, cb, fFalse /*fShrink*/)) + /* leave ph, mac and max unchanged */ + return fFalse; + } + else + { + Assert( *ph == hNil ); + + if (FNoHeap( *ph = HAllocateCb( cb ))) + { + *pcbMac = *pcbMax = 0; + return fFalse; + } + } + + *pcbMax = *pcbMac = cb; + return fTrue; +} + + + +csconst struct RCDS rgrcds[] = +{ +#include "styname.hc" +#include "mic.hc" +#include "help.hc" +#include "cross.hc" +#include "vertout.hc" +#include "horzout.hc" +#include "prvwcrs.hc" +}; + + +csconst HCURSOR * mpircdsphc[] = +{ + &vhcStyWnd, + &vhcRecorder, + &vhcHelp, + &vhcOtlCross, + &vhcOtlVert, + &vhcOtlHorz, + &vhcPrvwCross +}; + + + +/* H L O A D O U R R E S O U R C E */ +/* %%Function:HLoadRes1 %%Owner:bryanl */ +HANDLE HLoadRes1(i) +int i; +{ + HANDLE h; + LPSTR lpch; + + Assert(i >= ircdsNonCoreMin); + + i -= ircdsNonCoreMin; + + if ((h = OurGlobalAlloc(GMEM_MOVEABLE, (long)(uns)rgrcds[i].cb)) == NULL) + { + SetErrorMat(matMem); + return NULL; + } + + lpch = GlobalLock(h); + bltbx((LPSTR)rgrcds[i].rgchBits, lpch, rgrcds[i].cb); + GlobalUnlock(h); + return h; +} + + +/* %%Function:FAssureIrcds %%Owner:bryanl */ +BOOL FAssureIrcds(ircds) +int ircds; +{ + int i = ircds-ircdsNonCoreMin; + if (*mpircdsphc[i] != NULL) + return fTrue; + + return (*mpircdsphc[i] = (vsci.fUseResCursors ? + LoadCursor(vhInstance, ircds+1) : HLoadRes1(ircds))) != NULL; +} + + +/* %%Function:FreeIrcds %%Owner:bryanl */ +FreeIrcds(ircds) +{ + int i = ircds-ircdsNonCoreMin; + HANDLE h; + if ((h = *mpircdsphc[i]) == NULL) + Assert(fFalse); + + else if (!vsci.fUseResCursors) + { + GlobalFree(h); + *mpircdsphc[i] = NULL; + } +} + + diff --git a/src/Opus/CLIPBORD.C b/src/Opus/CLIPBORD.C new file mode 100644 index 0000000..656ff55 --- /dev/null +++ b/src/Opus/CLIPBORD.C @@ -0,0 +1,900 @@ + +/* clipbord.c -- Cut/Paste to clipboard */ + +#define NOVIRTUALKEYCODES +#define NOWINSTYLES +#define NOGDICAPMASKS +#define NOSYSMETRICS +#define NOMENUS +#define NOCTLMGR +#define NOFONT +#define NOPEN +#define NOBRUSH +#define NOCOMM +#define NOWNDCLASS +#include "word.h" +DEBUGASSERTSZ /* WIN - bogus macro for assert string */ +#include "doc.h" +#include "props.h" +#include "sel.h" +#include "pic.h" +#include "file.h" +#include "disp.h" +#include "screen.h" +#include "prm.h" +#include "opuscmd.h" +#include "debug.h" +#include "format.h" + +#include "field.h" +#include "ch.h" +#include "error.h" + + + +extern struct SEL selCur; /* Current selection */ +extern int vfSeeSel; +extern struct DOD **mpdochdod[]; +extern struct PAP vpapFetch; +extern CP vcpLimParaCache; +extern CP vcpFirstParaCache; +extern struct UAB vuab; +extern struct FCB (**hpfnfcb)[]; +extern struct MERR vmerr; +extern HWND vhwndApp; /* handle to parent's window */ +extern struct SAB vsab; +extern struct STTB **vhsttbFont; +extern struct PREF vpref; +extern int cfRTF; +extern int cfLink; + +extern CHAR HUGE *vhpchFetch; +extern struct CHP vchpFetch; +extern struct CA caPara; +extern CP vcpFetch; +extern int fnFetch; +extern struct PIC vpicFetch; +extern int wwCur; +extern int vwWinVersion; + +#ifdef NOTUSED +/* %%Function: CmdClear %%Owner: notused */ + +CMD CmdClear() /* not implemented [yet?][ever?] */ +{ + + Assert(fFalse); + + return cmdOK; +} + + +#endif + +/* %%Function: CmdCopy %%Owner: bobz */ + +CMD CmdCopy(pcmb) +CMB *pcmb; +{ /* COPY command: copy selection to clipboard */ + CMD cmd = cmdOK; + + if (selCur.fBlock) + { + /* use FDelCkBlockOk to test for partial fields + in block, which are disallowed */ + if (!FDelCkBlockOk(rpkNil, NULL)) + return cmdError; + } + + if (!FSetUndoBefore(bcmCopy, uccCopy)) + return cmdCancelled; + + vsab.doc = docNil; + + if (selCur.fTable) + cmd = CmdCopyTable(&selCur, docScrap); + else if (selCur.fBlock) + ClBlockSelToScrap(); + else + CmdCopy1(&selCur, &selCur.ca); + + SetUndoAfter(NULL); + + return cmd; +} + + +/* C M D C O P Y 1 */ +/* just sets the scrap to a plain sel */ +/* %%Function: CmdCopy1 %%Owner: bobz */ + +CmdCopy1(psel, pca) +struct SEL *psel; /* describes state of txt in pca */ +struct CA *pca; /* text to be copied */ +{ + struct CA caT; + + SetWholeDoc(docScrap, pca); + AssureNestedPropsCorrect(PcaSetWholeDoc(&caT, docScrap), fTrue); + vsab.docStsh = DocMother(pca->doc); + vsab.fFormatted = PdodDoc(vsab.docStsh)->fFormatted; + vsab.fMayHavePic = PdodMother(vsab.docStsh)->fMayHavePic; + vsab.caCopy = *pca; /* for (dde) Link format */ + vsab.fTable = fFalse; + /* Need to see if we copied part of a table cell. If so, the + fInTable flag needs to be turned off */ + if (psel->fWithinCell) + ApplyTableProps(PcaSetWholeDoc(&caT, docScrap), fFalse); + ChangeClipboard(); /* Force repaint of clipboard display & + Set ownership. also sets vsab.fPict */ +} + + +#ifdef DEBUG +int vTestClip = 0; +#endif /* DEBUG */ + +/* C M D P A S T E */ +/* paste command on the edit menu +*/ +/* %%Function: CmdPaste %%Owner: bobz */ + +CMD CmdPaste(pcmb) +CMB *pcmb; +{ + HWND hWndClipOwner; + struct CHP chpSel; + struct CA caScrap; + struct CA caPaste; + struct CA caRM; + struct CA caT; + CMD cmd; + BOOL fAddPara = fFalse; + CP cpFirst; + + StartLongOp(); /* Put up an hourglass */ + +/* We assume multiple Opus instances are not possible - paste cannot + work between instances of Opus */ + +#ifdef DEBUG + /* a slimy way to let us test RTF clipboard stuff and let us use + slapWnd to put stuff into the clipboard. If true, we will + paste out of the clipboard even though we put it there ourselves. + */ + if (vTestClip) + goto ForceClipRead; +#endif /* DEBUG */ + + + if ( (hWndClipOwner = GetClipboardOwner()) != vhwndApp ) + { +#ifdef DEBUG +ForceClipRead: +#endif + if (!FReadExtScrap()) /* clipbrd contents --> docScrap */ + { + SetErrorMat( matLow ); + cmd = cmdError; + goto PasteEnd; + } + } + +/* docScrap now has clipboard contents; paste them in */ + + /* Here we reoprt and error if we try to paste into a block selection. + We are specifically not pasting into a block because it can be + really disorienting, especially if autodelete is on. We + generally do not autodelete blocks, but require explicit + deletion. You can paste a block into a normal selection, + however. (We could, I suppose, turn the block to an insert + point then paste, but the autodelete case would be strange. (bz) */ + + if (!DcpCa(PcaSetWholeDoc( &caScrap, docScrap)) || + selCur.fBlock && !selCur.fTable) + { + ErrorEid(eidInvalidSelection, "CmdPaste"); + cmd = cmdError; + goto PasteEnd; + } + + + PcaPoint(&caRM, selCur.doc, selCur.ca.cpFirst); + /* Are we pasting to a table?? */ + if (selCur.fWithinCell || selCur.fTable) + { +LTablePaste: + cmd = CmdPasteToTable(); + goto PasteEnd; + } + else if (vsab.fTable && vpref.fAutoDelete && (selCur.cpFirst == cp0 || + FInTableDocCp(selCur.doc, selCur.cpFirst-1)) && + FInTableDocCp(selCur.doc, selCur.cpLim)) + { + ErrorEid(eidCantPasteTableInTable, "CmdPaste"); + cmd = cmdError; + goto PasteEnd; + } + else if (!vpref.fAutoDelete && FInTableDocCp(selCur.doc, selCur.cpFirst)) + { + /* selection begins in a table and contains text outside the table */ + TurnOffSel(&selCur); + SelectIns(&selCur, selCur.cpFirst); + goto LTablePaste; + } + else if (vsab.fBlock) + { + cmd = CmdPasteBlock(); + goto PasteEnd; + } + else + { +#ifdef DAVIDBO + CommSzNum(SzShared("\tBefore doc:\t"), caRM.doc); + CommSzLong(SzShared("\tBefore cpFirst:\t"), caRM.cpFirst); + CommSzLong(SzShared("\tBefore cpLim:\t"), caRM.cpLim); +#endif /* DAVIDBO */ + if (!FSetUndoBefore(bcmPaste, uccPaste)) + return cmdCancelled; + TurnOffSel(&selCur); + if ((cmd = CmdAutoDelete(&caRM)) != cmdOK) + goto PasteEnd; + if (!vsab.fFormatted) /* save current char props to apply + to inserted text */ + { + GetSelCurChp(fFalse); + chpSel = selCur.chp; + } + + if (FInTableDocCp(docScrap, cp0)) + { + if (!FEopBeforePca(PcaPoint(&caT, selCur.doc, cpFirst = selCur.cpFirst))) + { + cmd = cmdNoMemory; + goto PasteEnd; + } + + if (caT.cpFirst != cpFirst) + { + fAddPara = fTrue; + selCur.cpFirst += ccpEop; + if (selCur.fIns) + selCur.cpLim += ccpEop; + } + } + + /* must do after selCur adjusted for fAddPara */ + PcaSetDcp( &caPaste, selCur.doc, selCur.cpFirst, DcpCa( &caScrap )); + + /* do not pass &selCur.ca; AdjustCp might munge it */ + caT = selCur.ca; + + if (!FReplaceCpsRM( &caT, &caScrap )) + { + cmd = cmdNoMemory; + goto PasteEnd; + } + +#ifdef DCLIPPIC + if (vsab.fPict) + { + CachePara(selCur.doc, selCur.cpFirst); + FetchCp(selCur.doc, selCur.cpFirst, fcmProps); + CommSzRgNum(SzShared("vchpFetch after insert pic repl cps : "), &vchpFetch, cwCHP); + } +#endif + if (vsab.fFormatted) + { + CopyStylesFonts( vsab.docStsh != docNil ? vsab.docStsh : docScrap, + caPaste.doc, caPaste.cpFirst, DcpCa( &caPaste ) ); + } + else /* picture or unformatted text from clipboard */ + { + int cb; + CHAR grpprl[cbMaxGrpprl]; + struct CHP chpT; + + /* copy char looks. + compute difference: chpT is StandardChp, which + docScrap got when data was read in from clipboard. + chpSel was the previous selection props. + Express difference as grpprl. + Apply grpprl. + picture notes: + for a picture, the char props are standard except for + fSpec and fcPic being set. If we also add in the + current properties at the insert location now, we don't + have to special case the picture when we want char props + and the pic is the start or total of a selection. + */ + StandardChp(&chpT); + /* cb == 0 if no differences */ + if (cb = CbGrpprlFromChp(&grpprl, &chpSel, &chpT)) + ApplyGrpprlCa(grpprl, cb, &caPaste); + } + } + + /* this will make saves be native if formerly plain */ + if (vsab.fPict) + PdodDoc(selCur.doc)->fFormatted = fTrue; + if (vsab.fMayHavePic) + PdodMother(selCur.doc)->fMayHavePic = fTrue; + +/* "Go back" points before and after the insertion */ + SelectIns( &selCur, caPaste.cpFirst ); + PushInsSelCur(); + + AssureNestedPropsCorrect(&caPaste, fTrue); + SelectPostDelete(caPaste.cpLim); + PushInsSelCur(); + caRM.cpLim += DcpCa(&caScrap) + (fAddPara ? ccpEop : 0); +#ifdef DAVIDBO + CommSzNum(SzShared("\tAfter doc:\t"), caRM.doc); + CommSzLong(SzShared("\tAfter cpFirst:\t"), caRM.cpFirst); + CommSzLong(SzShared("\tAfter cpLim:\t"), caRM.cpLim); +#endif /* DAVIDBO */ + SetUndoAfter(&caRM); + + cmd = cmdOK; + +PasteEnd: + EndLongOp(fFalse /* fAll */); + /* this will clear out any eop weirdnesses that would reset + vfSeeSel + */ + UpdateWw( wwCur, fFalse /* fAbortOk*/); + vfSeeSel = fTrue; + return cmd; +} + + +/* %%Function: DestroyClip %%Owner: bobz */ + + +DestroyClip() + { /* Handles WM_DESTROYCLIPBOARD message. We are being notified that + the clipboard is being emptied & we don't need to keep its + contents around anymore. */ + struct CA ca; + + if (vsab.fDontDestroyClip) + return; + + vsab.fOwnClipboard = fFalse; + + /* Clear out the scrap document */ + SetWholeDoc(docScrap, PcaSetNil(&ca)); + + /* Disable UNDO operations that require the clipboard */ + /* should only care about copy and cut, which change the clipboard state */ + if (vuab.bcm == bcmCut || vuab.bcm == bcmCopy) + SetUndoNil(); +} + + + +/* %%Function: ChangeClipboard %%Owner: bobz */ + + + +ChangeClipboard() +{ /* Mark clipboard as changed. If we are not the owner of the clipboard, */ + /* make us the owner (via EmptyClipboard). The EmptyClipboard call */ + /* will result in a WM_DESTROYCLIPBOARD message being sent to the */ + /* owning instance. The CloseClipboard call will result in a */ + /* WM_DRAWCLIPBOARD message being sent to the clipboard viewer. */ + /* If the clipboard viewer is CLIP.EXE, we will get a WM_PAINTCLIPBOARD */ + /* message */ + /* Added 10/8/85 by BL: If docScrap is empty, relinquish ownership */ + /* of the clipboard */ + + // for more sense in reading +#define CF_UNRENDERABLE CF_TIFF + + int cf = CF_UNRENDERABLE; + CP cpMacScrap = CpMacDocEdit(docScrap); + struct CA caT; + int mm; + BOOL fDIBInMetafile = fFalse; + +#ifdef DEBUG + /* used for testing paste - forces us to paste in from clipboard + even if we owned it. Set in SlapWnd and for debugging, turned off when + we load something into the clipboard. + */ + vTestClip = 0; +#endif /* DEBUG */ + + + /* we want all fields in the scrap to be consistent with the vpref + values so we can safely put pictures into the clipboard in CF_TEXT + format. DO this here, sice both cut and paste go through this routine. + */ + + ClearFDifferFltg (docScrap, fltgAll); + + if (!OpenClipboard( vhwndApp )) + { /* Couldn't open the clipboard, wipe out contents & disable UNDO */ + /* a bit harsh huh? */ /* perhaps, but if we can't open the clipbord + we are in an indeterminite state; better to wipe out contents + and be in a known state */ + DestroyClip(); + return; + } + +/* We want to clear out previous data formats in the clipboard. + Unfortunately, the only way to do this is to call EmptyClipboard(), + which has the side effect of calling us with a WM_DESTROYCLIP + message. We use this primitive global comunication to prevent + docScrap from being wiped out in DestroyClip() */ + + vsab.fDontDestroyClip = fTrue; + EmptyClipboard(); + vsab.fDontDestroyClip = fFalse; + +/* Re-validate vsab.fPict (in case a docScrap edit changed what it + should be) */ + + vsab.fPict = FPicRenderable(docScrap, cp0, cpMacScrap, &mm); + /* if ca is a rejected pic type,(flase return but + mm != MM_NIL) set cf to CF_UNRENDERABLE, which + will be rejected below + */ + if (!vsab.fPict) + cf = (mm == MM_NIL ? CF_TEXT : CF_UNRENDERABLE); + else + { + // just a warning. We will ignore other types + Assert (mm == MM_BITMAP || mm < MM_META_MAX || + mm == MM_DIB); + + switch (mm) + { + default: + // note: if not recognized, cf left at CF_UNRENDERABLE and ignored + if (mm < MM_META_MAX) + { + if (!FDIBInMetafile()) + cf = CF_METAFILEPICT; + else + fDIBInMetafile = fTrue; + } + break; + case MM_BITMAP: + cf = CF_BITMAP; + break; + } + + } + + +#ifdef BZ + CommSzNum(SzShared("vsab.fPict "), vsab.fPict); + CommSzNum(SzShared("renderable mm "), mm); + CommSzNum(SzShared("cf "), cf); +#endif /* BZ */ + + + vsab.fOwnClipboard = (cpMacScrap != cp0); + if (vsab.fOwnClipboard) + { /* only set handles if we really have something in docScrap */ + SetClipboardData( CF_OWNERDISPLAY, NULL ); + /* don't put out cf_tiff or other rejected pic types, or + rtf or link for any of those types + */ + if (cf != CF_UNRENDERABLE || fDIBInMetafile) + { + SetClipboardData( cfRTF, NULL ); /* always avail */ + if (fDIBInMetafile) + { + SetClipboardData( CF_METAFILEPICT, NULL ); + SetClipboardData( CF_DIB, NULL ); + if (vwWinVersion >= 0x0300) + SetClipboardData( CF_BITMAP, NULL); + } + else + SetClipboardData( cf, NULL ); + /* can only link if we can still get at the source w/a bookmark */ + if (FCanLinkScrap ()) + SetClipboardData( cfLink, NULL ); + } + + } + + CloseClipboard(); +} + + +#ifdef NOTUSED +/* %%Function: FSameClassHwndSz %%Owner: notused */ + +FSameClassHwndSz( hwnd, szClass ) +HWND hwnd; +CHAR szClass[]; + { /* Compare the Class name of hWnd with szClass; return TRUE + if they match, FALSE otherwise. */ + +#define cchClassMax 40 /* longest class name (for compare purposes) */ + + CHAR rgchWndClass[ cchClassMax ]; + int cbCopied; + + /* Count returned by GetClassName does not include terminator */ + /* But, the count passed in to it does. */ + cbCopied = GetClassName( hwnd, (LPSTR) rgchWndClass, cchClassMax ) + 1; + if (cbCopied <= 1) + return FALSE; + + rgchWndClass[ cbCopied - 1 ] = '\0'; + + return FEqNcSz( rgchWndClass, szClass ); +} + + +#endif /* NOTUSED */ + + + +/* F C A N L I N K S C R A P */ +/* Return true if the data in doc scrap can be Paste-Linked to. + Conditions: must have a non-empty range in a displayed mother + document. +*/ +/* %%Function: FCanLinkScrap %%Owner: bobz */ + +FCanLinkScrap () +{ + return vsab.doc != docNil && vsab.cpFirst < vsab.cpLim + && PdodDoc (vsab.doc)->fMother && + WwDisp(vsab.doc,wwNil,fFalse) != wwNil; +} + + + +/* The following was previously in clipdisp.c */ + +extern struct FLI vfli; +extern struct SAB vsab; +extern struct SCI vsci; +extern CHAR stEmpty[]; + + + +int vwwClipboard=wwNil; +int vmwClipboard=mwNil; + +int NEAR FGetClipboardDC( void ); +int NEAR ReleaseClipboardDC( void ); + + +#ifdef OPUS_X64 +csconst char stFmtTextCs[] = + { 19, 'W', 'o', 'r', 'd', ' ', 'F', 'o', 'r', 'm', 'a', 't', 't', 'e', + 'd', ' ', 'T', 'e', 'x', 't' }; +#else +csconst char stFmtTextCs[] = StKey("Word Formatted Text",WordFormattedText); +#endif + +/* %%Function: PaintClipboard %%Owner: bobz */ + + +PaintClipboard( hwnd, hps ) +HWND hwnd; +HANDLE hps; +{ /* Paint portion of clipboard window indicated by hps */ + + LPPAINTSTRUCT lpps; + struct WWD *pwwd; + + if (vwwClipboard == wwNil) + { + ReportSz("Warning - PaintClipboard with vwwClipBoard nil ignored"); + return; + } + +/* Must set the scroll bar range each time we get a PAINT message; + CLIPBRD.EXE resets it when it gets WM_DRAWCLIPBOARD */ + + pwwd = PwwdWw(vwwClipboard); + Assert( pwwd->hwnd == hwnd ); + SetScrollRange( pwwd->hwnd, SB_VERT, 0, dqMax-1, TRUE ); + SetScrollRange( pwwd->hwnd, SB_HORZ, 0, vsci.xpRightMax, FALSE ); +/* 0 size followed by non-0 size means clipboard app may have been + taken down, then re-created; so, reset the scroll bars to + what they should be. */ + SyncSbHor(vwwClipboard); + SetElevWw(vwwClipboard); + pwwd = PwwdWw(vwwClipboard); + + if ( (lpps = (LPPAINTSTRUCT)GlobalLockClip( hps )) != NULL ) + { + HDC hdc = lpps->hdc; + struct RC rcT; + + rcT.xpLeft = lpps->rcPaint.left; + rcT.ypTop = lpps->rcPaint.top; + rcT.xpRight = lpps->rcPaint.right; + rcT.ypBottom = lpps->rcPaint.bottom; + GlobalUnlock( hps ); + if (FSetDcAttribs( pwwd->hdc = hdc, dccDoc )) + { /* Paint the clipboard */ + InvalWwRc(vwwClipboard, &rcT); + UpdateWw( vwwClipboard, fFalse /*fAbortOK*/ ); + } + /* BLOCK workaround windows RIP by deselecting our objects */ + { + HDC hdc = PwwdWw(vwwClipboard)->hdc; + Assert(hdc != NULL); + SelectObject(hdc, GetStockObject(SYSTEM_FONT)); + SelectObject(hdc, GetStockObject(WHITE_BRUSH)); + SelectObject(hdc, GetStockObject(BLACK_PEN)); + } + + } + + /* Since the DC is no longer good, we'll set it to NULL */ + PwwdWw(vwwClipboard)->hdc = NULL; +} + + +/* %%Function: SizeClipboard %%Owner: bobz */ + + +SizeClipboard( hwnd, hrc ) +HWND hwnd; +HANDLE hrc; +{ /* Set clipboard window to be the rect in hRC */ + /* If rectangle is 0 units high or wide, this means we're losing the + necessity for display until the next size message */ + LPRECT lprc; + struct RC rc; + struct WWD *pwwd; + + if ( (lprc = (LPRECT)GlobalLockClip( hrc )) == NULL ) + return; + rc.xpLeft = lprc->left; + rc.ypTop = lprc->top; + rc.xpRight = lprc->right; + rc.ypBottom = lprc->bottom; + GlobalUnlock( hrc ); + +/* NULL rectangle means no more displaying until we get a nonnull size */ + + if (FValidateWwClipboard(hwnd)) + { + pwwd = PwwdWw( vwwClipboard ); + if (FEmptyRc(&rc)) + pwwd->dqElevator = 0; + else + { + pwwd->rcwDisp = rc; + if (pwwd->xhScroll < 0) + pwwd->rcwDisp.xwLeft += dxwSelBarSci; + RcToDrc(&pwwd->rcwDisp, &PdrGalley(pwwd)->drcl); + PdrGalley(pwwd)->drcl.xl = PdrGalley(pwwd)->drcl.yl = 0; + TrashWw( vwwClipboard ); +/* 0 size followed by non-0 size means clipboard app may have been + taken down, then re-created; so, reset the scroll bars to + what they should be. */ + SyncSbHor(vwwClipboard); + SetElevWw(vwwClipboard); + } + } +} + + +/* %%Function: VScrollClipboard %%Owner: bobz */ + + +VScrollClipboard( hwnd, sbMessage, posNew ) +HWND hwnd; +int sbMessage; +int posNew; +{ + struct WWD *pwwd; + int dypPage; + CP cpMac, cpT; + + if (vwwClipboard == wwNil) + { + Assert( fFalse ); + return; + } + + Assert( PwwdWw(vwwClipboard)->hwnd == hwnd ); + + if (!FGetClipboardDC()) + /* Unable to create clipboard device context */ + return; + + pwwd = PwwdWw(vwwClipboard); + switch ( sbMessage ) + { + case SB_THUMBPOSITION: + cpMac = CpMacDoc( PdrGalley(pwwd)->doc ); + cpT = cpMac > cpMax / (dqMax - 1) + ? (cpMac / (dqMax - 1)) * posNew + : (cpMac * posNew) / (dqMax - 1); + ThumbToCp(vwwClipboard, CpMin(cpT, cpMac-ccpEop), fFalse, fFalse, 0); + break; + + case SB_LINEUP: + ScrollDown( vwwClipboard, vsci.dysMinAveLine, vsci.dysMacAveLine ); + break; + break; + case SB_LINEDOWN: + ScrollUp( vwwClipboard, vsci.dysMinAveLine, vsci.dysMacAveLine ); + break; + case SB_PAGEUP: + case SB_PAGEDOWN: + dypPage = pwwd->ywMac - pwwd->ywMin; + if (dypPage > vsci.dysMacAveLine) + dypPage -= vsci.dysMacAveLine; + (*(sbMessage == SB_PAGEUP ? ScrollDown : ScrollUp)) + ( vwwClipboard, dypPage, dypPage + vsci.dysMacAveLine - vsci.dysMinAveLine ); + break; + } + + UpdateWw( vwwClipboard, fFalse ); + ReleaseClipboardDC(); +} + + +/* %%Function: HScrollClipboard %%Owner: bobz */ + + + +HScrollClipboard( hwnd, sbMessage, posNew ) +HWND hwnd; +int sbMessage; +int posNew; +{ + + struct WWD *pwwd; + int dxpWw; + int xpScroll; + int xpThumb; + + if (vwwClipboard == wwNil) + { + Assert( fFalse ); + return; + } + + Assert( PwwdWw(vwwClipboard)->hwnd == hwnd ); + + if (!FGetClipboardDC()) + /* Unable to create clipboard device context */ + return; + + pwwd = PwwdWw(vwwClipboard); + dxpWw = pwwd->xwMac - pwwd->xwMin; + xpScroll = abs(DxpScrollHorizWw(vwwClipboard)); + + switch (sbMessage) + { + case SB_LINEUP: /* line left */ + if (xpScroll == 0) + Beep(); + else if (vsci.dxpMinScroll > xpScroll) + /* scroll to zero */ + ScrollRight(vwwClipboard, xpScroll); + else + /* normal scroll */ + ScrollRight(vwwClipboard, vsci.dxpMinScroll); + break; + case SB_LINEDOWN: /* line right */ + ScrollLeft( vwwClipboard, vsci.dxpMinScroll ); + break; + case SB_PAGEUP: /* page left */ + ScrollRight( vwwClipboard, min((dxpWw>>1),xpScroll) ); + break; + case SB_PAGEDOWN: /* page right */ + ScrollLeft( vwwClipboard, dxpWw>>1 ); + break; + case SB_THUMBPOSITION: + xpThumb = NMultDiv(posNew, + vsci.xpRightMax - DxOfRc(&pwwd->rcwDisp), + vsci.xpRightMax); + xpScroll = xpThumb + pwwd->xhScroll; + if (xpScroll > 0) + ScrollLeft(vwwClipboard, xpScroll); + else + ScrollRight(vwwClipboard, -xpScroll); + break; + } + + UpdateWw( vwwClipboard, fFalse ); + ReleaseClipboardDC(); +} + + +/* A s k C b F o r m a t N a m e */ +/* %%Function: AskCBFormatName %%Owner: bobz */ + +AskCBFormatName( lpchName, cchNameMac ) +LPCH lpchName; +int cchNameMac; + { /* Copy the format name for the current contents of the clipboard + (of which we are the owner) to lpchName, copying no more than + cchNameMac characters */ + + int cchCopy; + + Assert( vsab.fOwnClipboard ); + + /* Don't give a format name for pictures; the name is covered by the + standard types */ + + if (!vsab.fPict) + { + if ((cchCopy=*stFmtTextCs) >= cchNameMac) + cchCopy = cchNameMac-1; + + bltbx((LPSTR)stFmtTextCs+1, (LPSTR)lpchName, cchCopy); + lpchName[cchCopy] = 0; + } +} + + +/* F G e t C l i p b o a r d D C */ +/* %%Function: FGetClipboardDC %%Owner: bobz */ + +int NEAR FGetClipboardDC() + { /* Get a DC for the clipboard window. Leave it in rgwwd [wwClipboard]. + Select in the background brush for appropriate color behavior. + return TRUE if all is well, FALSE if something went wrong */ + + struct WWD *pwwd; + + if (vwwClipboard == wwNil) + return fFalse; + + pwwd = PwwdWw(vwwClipboard); + if ((pwwd->hdc = GetDC( pwwd->hwnd )) == NULL) + return fFalse; + + if (!FSetDcAttribs( pwwd->hdc, dccDoc )) + { + ReleaseClipboardDC(); + return fFalse; + } + + return fTrue; +} + + +/* R e l e a s e C l i p b o a r d D C */ +/* %%Function: ReleaseClipboardDC %%Owner: bobz */ + +int NEAR ReleaseClipboardDC() +{ + struct WWD *pwwd; + + Assert( vwwClipboard != wwNil ); + pwwd = PwwdWw(vwwClipboard); + ReleaseDC( pwwd->hwnd, pwwd->hdc ); + pwwd->hdc = NULL; +} + + +/* %%Function: FValidateWwClipboard %%Owner: bobz */ + + +int FValidateWwClipboard( hwnd ) +HWND hwnd; +{ + struct SELS sels; + + if (vwwClipboard == wwNil) + { + sels.ca.doc = docNil; + if (!FCreateMw( docScrap, wkClipboard, &sels, NULL)) + return fFalse; + Assert( vwwClipboard != wwNil && vmwClipboard != mwNil ); + } + + PwwdWw(vwwClipboard)->hwnd = hwnd; + return fTrue; +} + diff --git a/src/Opus/CLIPBRD2.C b/src/Opus/CLIPBRD2.C new file mode 100644 index 0000000..b7cc134 --- /dev/null +++ b/src/Opus/CLIPBRD2.C @@ -0,0 +1,2305 @@ +/* Clipbrd2.c -- less frequently used clipboard routines */ + +#define NOVIRTUALKEYCODES +#define NOWINSTYLES +#define NOGDICAPMASKS +#define NOSYSMETRICS +#define NOMENUS +#define NOCTLMGR +#define NOFONT +#define NOPEN +#define NOBRUSH +#define NOSCROLL +#define NOCOMM +#define NOWNDCLASS +#include "word.h" +DEBUGASSERTSZ /* WIN - bogus macro for assert string */ +#include "doc.h" +#include "props.h" +#include "sel.h" +#include "pic.h" +#include "file.h" +#include "disp.h" +#include "prm.h" +#include "format.h" +#include "dde.h" +#include "field.h" +#include "ch.h" +#include "inter.h" +#include "fkp.h" +#include "winddefs.h" +#include "screen.h" +#include "debug.h" +#include "error.h" +#include "message.h" +#include "ff.h" +#include "grstruct.h" +#include "resource.h" + +#ifdef PROTOTYPE +#include "clipbrd2.cpt" +#endif /* PROTOTYPE */ + +extern char (**vhgrpchr)[]; +extern struct SEL selCur; /* Current selection */ +extern struct DOD **mpdochdod[]; +extern CP vcpLimParaCache; +extern struct MERR vmerr; +extern HWND vhwndApp; /* handle to parent's window */ +extern HWND vhwndCBT; +extern struct SAB vsab; +extern struct PREF vpref; +extern struct WWD **hwwdCur; +extern struct FLI vfli; +extern CHAR rgchEop[]; +extern int cfRTF; +extern int cfPrPic; +extern int cfLink; +extern struct PAP vpapFetch; +extern struct FKPD vfkpdText; +extern int vdocScratch; + +extern CHAR HUGE *vhpchFetch; +extern CP vcpFetch; +extern struct CHP vchpFetch; +extern BOOL vfSingleApp; +extern struct PIC vpicFetch; +extern FC vfcFetchPic; /* fc of last fetched pe */ +extern int fnFetch; +extern char szEmpty[]; +extern struct SCI vsci; +extern int vwWinVersion; +extern int wwCur; + +extern LPCH LpchIncr(); + +VOID BuildMFRecordForDIB(struct MFHDRDIBMF *, struct WINMRTAG *, unsigned long, int, int); +int CbDIBHeader(LPBITMAPINFOHEADER); +#define WIDTHBYTES(i) (((i)+31)/32*4) /* ULONG aligned ! */ + +/* %%Function: CchReadLineExt %%Owner: bobz */ + + +CchReadLineExt( lpch, cbRead, rgch, pfEol) +LPCH lpch; +int cbRead; +CHAR rgch[]; +int *pfEol; +{ /* Read from lpch to the next eol or null terminator, whichever comes first */ + /* Return number of bytes read (max is 255) and whether there is a eol at end */ + /* The count does not include the null terminator, but does include the eol */ + + CHAR *pch; + + bltbx( lpch, (LPCH) rgch, cbRead ); + rgch[ cbRead ] = 0; /* Null terminate the string (so index will work) */ + + if (*pfEol = ((pch=index(rgch,chEol)) != NULL)) + { /* FOUND EOL */ + return (pch - rgch + 1); + } + else + { /* NO EOL */ + return CchSz(rgch) - 1; + } +} + + +/* %%Function: FRenderFormat %%Owner: bobz */ + + +FRenderFormat( cf ) +int cf; +{ /* Render clipboard data in format specified by cf */ + + BOOL fRet = fTrue; + CP cpMac = CpMacDocEdit(docScrap); + + Assert (cf != CF_OWNERDISPLAY); + + if (FCanWriteCf (cf, docScrap, cp0, cpMac, fFalse /*fRestrictRTF */)) + if ( !(fRet = FWriteExtScrap (cf)) ) + ErrorEid( eidClipNoRender, " RenderFormat" ); + return (fRet); +} + + +/* %%Function: FRenderAll %%Owner: bobz */ + + +FRenderAll(ac) + { /* Opus is going away, and we are the owners of the clipboard. + Render the contents of the clipboard in as many formats as + we know. Returns false if we failed to render some format + and the user says do not throw away the clipboard. */ + + CP cpMac = CpMacDoc( docScrap ) - ccpEop; + + int cf = cfNil; + int id; + BOOL fRet = fTrue; + + Assert (vsab.fOwnClipboard); + if ( (cpMac == cp0) || !vsab.fOwnClipboard) + { /* We are not the clipboard owner OR the scrap is empty: + no actions required */ + return fTrue; + } + /* do you want to render this biggie? */ + /* pic will usually take a while to render */ + /* later version bz may want better dialog that allows selective + abandonment of clipboard formats */ + + if (cpMac > 1024L || vsab.fPict) + { + switch (ac) + { + case acSaveAll: + case acQuerySave: + id = IdMessageBoxMstRgwMb(mstSaveLargeClip, + NULL, MB_DEFNOQUESTION); + break; + + case acSaveNoQuery: + id = IDYES; + break; + + case acNoSave: + id = IDNO; + break; + } + + if (id == IDCANCEL) + return(fFalse); /* cause quit to be abandoned */ + else if (id == IDNO) + return(fTrue); /* no render, but continue quit */ + /* YES continues to do rendering. */ + } + + /* Get the handle for the highest-priority type available */ + + if (OpenClipboard( vhwndApp )) + { + StartLongOp(); + + /* We want to clear out previous data formats in the clipboard. + Unfortunately, the only way to do this is to call EmptyClipboard(), + which has the side effect of calling us with a WM_DESTROYCLIP + message. We use this primitive global comunication to prevent + docScrap from being wiped out in DestroyClip() */ + + vsab.fDontDestroyClip = fTrue; + EmptyClipboard(); + vsab.fDontDestroyClip = fFalse; + + while ((cf = CfNextCf(cf,fFalse)) != cfNil) + { + if (FCanWriteCf(cf, docScrap, cp0, cpMac, fTrue /*fRestrictRTF */)) + { + if (!FWriteExtScrap(cf)) + { + /* avoid other out of memory messages */ + if (vmerr.fMemFail) + vmerr.mat = matNil; + if (IdMessageBoxMstRgwMb(mstClipLarge, NULL, + MB_OKCANCEL|MB_ICONQUESTION) == IDOK) + { + fRet = fTrue; + break; /* out of while loop */ + } + else + { + fRet = fFalse; + break; + } + } + } + } + CloseClipboard(); + EndLongOp (fFalse /* fAll */); + } + return (fRet); +} + + + +/* F W R I T E E X T S C R A P */ +/* Write the scrap to the clipboard in format cf. +*/ +/* %%Function: FWriteExtScrap %%Owner: bobz */ + +FWriteExtScrap(cf) +int cf; +{ + + HANDLE h; + int fBlankPic = fFalse; + + Assert(vsab.fOwnClipboard); + + /* render in format cf */ + h = HDataWriteDocCps (cf, docScrap, cp0, + CpMacDoc (docScrap) - cchEop, 0, &fBlankPic); + + if (h != NULL) + /* data sucessfully written */ + { + SetClipboardData(cf, h); + return fTrue; + } + else if (fBlankPic) /* no data, but ok */ + { + return fTrue; + } + else + return fFalse; +} + + + + + +/* H D A T A W R I T E D O C C P S */ +/* Write data from doc [cpFirst:cpLim) to a windows global handle. Prepend + to that handle cpInitial bytes. Write in format cf. Return NULL if + operation cannot be completed for what ever reason. +*/ +/* %%Function: HDataWriteDocCps %%Owner: bobz */ + + +HDataWriteDocCps (cf, doc, cpFirst, cpLim, cbInitial, pfBlankPic) +int cf, doc; +CP cpFirst, cpLim; +int cbInitial; +int *pfBlankPic; /* set true if an empty picture; else ignored */ + +{ + struct CA ca; + + AssureLegalSel (PcaSet(&ca, doc, cpFirst, cpLim)); + switch (cf) + { + case CF_TEXT: + + return HWriteText (ca.doc, ca.cpFirst, ca.cpLim, cbInitial); + + case CF_BITMAP: + case CF_METAFILEPICT: + case CF_DIB: + return HWritePict (ca.doc, ca.cpFirst, ca.cpLim, cbInitial, + pfBlankPic, cf); + + default: + if (cf == cfRTF) + return HWriteRTF (ca.doc, ca.cpFirst, ca.cpLim, cbInitial); + else if (cf == cfLink && FCanLinkScrap()) + { + Assert (doc == docScrap && cbInitial == 0); + return HRenderClipLink (); + } + else + return NULL; + } +} + + + +/* H W R I T E T E X T */ +/* Write doc, cpFirst:cpLim to a windows handle in plain text format. + Plain text format is generated by doing successive FormatLines and + adding CRLF pairs at the end of each. cbInitial is data prepended to + the handle's data for use by DDE (& DDE only). + + Note we try to allocate fairly big chunks, but a least enough for + data and terminating null. +*/ +/* %%Function: HWriteText %%Owner: bobz */ + + +HWriteText (doc, cpFirst, cpLim, cbInitial) +int doc; +CP cpFirst, cpLim; +int cbInitial; + +{ + + int wAlloc = cbInitial ? GMEM_DDE : GMEM_MOVEABLE; + HANDLE h = hNil; + HANDLE hT; + LPCH lpch; + CP cpNow=cpFirst; + int cLine = 0; + struct WWD *pwwd; + GRPFVISI grpfvisi; + LONG lcbMac = 0; /* amount used */ + LONG lcbMax = 0; /* amount allocated */ + BOOL fTableCell; + int cchEopT; + + if (!FAssureHCbGlob( &h, (long)(1+cbInitial), wAlloc, &lcbMac, &lcbMax) ) + goto Failed; + + /* Set up view preferences for rendered text in wwTemp */ + + grpfvisi.w = 0; + grpfvisi.fvisiCondHyphens = fTrue; + grpfvisi.grpfShowResults = ~0; + grpfvisi.fNoShowPictures = fTrue; + grpfvisi.fForceField = fTrue; + grpfvisi.flm = FlmDisplayFromFlags( vpref.fDisplayAsPrint, vpref.fPageView, vpref.fDraftView); + PwwdWw(wwTemp)->grpfvisi = grpfvisi; + LinkDocToWw( doc, wwTemp, wwNil ); + + while (cpNow < cpLim) + { + int dcpLine; + + fTableCell = fFalse; + + /* Format a line of text for the screen */ + + FormatLine( wwTemp, doc, cpNow ); + dcpLine = vfli.ichMac; + + /* Put the chars + a CRLF into the handle */ + + if (vfli.cpMac > cpLim) + /* do not copy unwanted portions of the line */ + dcpLine = IchFromCpVfli (cpLim); + + /* check for tables */ + else if (vfli.fSplatBreak && vfli.chBreak == chTable) + { + CachePara(doc, cpNow); + if (vpapFetch.fTtp) /* End-of-row marker */ + { + if (lcbMac - 1 > cbInitial) /* back over preceding tab */ + lcbMac--; + dcpLine = 0; + } + else + fTableCell = fTrue; + } + + dcpLine = CchSanitizeRgch(vfli.rgch, dcpLine, ichMaxLine /* sizeof vfli.rgch */, fTrue /*fSpecToCRLF*/); + if (fTableCell) + vfli.rgch[dcpLine-1] = chTab; + + /* extra byte for null at end already allocated */ + if (!FAssureHCbGlob(&h, (LONG) (lcbMac + dcpLine + + (cchEopT = (fTableCell ? 0 : cchEop))), wAlloc, &lcbMac, &lcbMax)) + goto Failed; + + if ((lpch=GlobalLockClip( h )) == NULL) + goto Failed; + + bltbx( (LPCH) vfli.rgch, lpch+lcbMac-dcpLine-cchEopT-1, dcpLine ); + if (!fTableCell) + { + bltbx( (LPCH) rgchEop, lpch+lcbMac-cchEop-1, cchEop ); + cLine++; + } + + Assert (vfli.cpMac > cpNow); + cpNow = vfli.cpMac; + GlobalUnlock( h ); + } + + /* SUCCEEDED! NULL-terminate the string before returning the handle */ + + /* now realloc to free up any extra allocated memory */ + hT = h; + if (lcbMax != lcbMac) + { + Assert (lcbMax > lcbMac); + if ((h = OurGlobalReAlloc( h, (LONG) (lcbMac), wAlloc )) == NULL) + { + h = hT; /* this should never happen */ + goto Failed; + } + } + + if ((lpch = GlobalLock( h )) == NULL) + goto Failed; + + if (cLine == 1 && !fTableCell) + /* Special case: < 1 line, do not terminate w/ CRLF */ + /* Back up over crlf already written */ + lcbMac -= cchEop; + + lpch [lcbMac-1] = '\0'; + GlobalUnlock( h ); + + InvalFli(); + + return h; + +Failed: + + if (h != NULL) + GlobalFree( h ); + + InvalFli(); + + return NULL; +} + + + +/* H W R I T E P I C T */ +/* Write doc, cpFirst:cpLim to a windows handle in bitmap or metafile + format. + cbInitial is data prepended to + the handle's data for use by DDE (& DDE only). +*/ +/* %%Function: HWritePict %%Owner: bobz */ + + +HWritePict (doc, cpFirst, cpLim, cbInitial, pfBlankPic, cf) +int doc; +CP cpFirst, cpLim; +int cbInitial; +int *pfBlankPic; /* set true if an empty picture; else ignored */ +int cf; /* requested clipboard format */ + +{ + + extern LPCH LpchIncr(); + + int wAlloc = cbInitial ? GMEM_DDE : GMEM_MOVEABLE; + HANDLE hData = NULL; + HANDLE hDataDescriptor = NULL; + HANDLE hReturn = NULL; + LPCH lpch; + FC fc, fcMacPic; + long cfcPic; + long lcbCur; + int cLine = 0; + int wPrefT; + char rgch[256]; + struct CA caT; + CP cpImport; + int mm; /* mapping mode */ + FC fcFetchPic; + BOOL fDIBInMf = fFalse; + + /* for import field, vcpFetch will end up being cpImport */ + + AssertDo(FCaIsGraphics(PcaSet(&caT, doc, cpFirst, cpLim), + fvcResults, &cpImport)); + + /* load in the picture prefix to find length */ + Assert(*vhpchFetch == chPicture && vchpFetch.fSpec); + /* FetchPe will set vchpFetch.fnPic to fnFetch bz */ + + /* fill PIC structure vpicFetch */ + + FetchPe(&vchpFetch, doc, vcpFetch); + /* size of pic bytes */ + cfcPic = vpicFetch.lcb - vpicFetch.cbHeader; + + if (cfcPic == 0L) + /* no pain, no gain */ + { + *pfBlankPic = fTrue; + return(NULL); + } + + if (cf == CF_DIB) + { + // we can render a DIB if it is one of those that are embedded + // in a metafile + if (FDIBInMetafile()) + { + /* DIB is embedded in a metafile, have to extract it out */ + /* set up cfcPic, fcFetchPic correctly */ + cfcPic -= (cbMFHDRDIBMF + cbWINMRTAG); /* total overhead of meta records */ + fcFetchPic = vfcFetchPic + cbMFHDRDIBMF; /* advance to beyond the meta hdr record */ + mm = MM_DIB; + } + else + goto Failed; + } + else if (cf == CF_BITMAP && vwWinVersion >= 0x0300 && FDIBInMetafile()) + { + // we can also render a bitmap from those metafile that embed a DIB + // but we only want to do that under win 3.x because win 2 does not + // have the API to do so + fDIBInMf = fTrue; + cfcPic -= (cbMFHDRDIBMF + cbWINMRTAG); /* total overhead of meta records */ + fcFetchPic = vfcFetchPic + cbMFHDRDIBMF; /* advance to beyond the meta hdr record */ + mm = MM_BITMAP; + } + else + { + /* init mm and fcFetchPic normally */ + mm = vpicFetch.mfp.mm; + fcFetchPic = vfcFetchPic; + } + + hData = GlobalAlloc2( wAlloc, cfcPic ); + if (hData == NULL) + goto Failed; + if ((lpch = GlobalLock (hData)) == NULL) + goto Failed; + + /* pull pic bytes out of fn, fc */ + + fcMacPic = fcFetchPic + cfcPic; + for (fc = fcFetchPic ; fc < fcMacPic; + fc += lcbCur, lpch = LpchIncr(lpch, (unsigned)lcbCur)) + { + FetchPeData(fc, (char HUGE *)rgch, + /* using CpMin for missing lmin */ + lcbCur = CpMin((long)(sizeof (rgch)), fcMacPic - fc)); + bltbx((char far *)rgch, lpch, (int)lcbCur); + } + + GlobalUnlock (hData); + + /* Now we have the whole of picture in a windows Global handle */ + /* See what kind of picture we have */ + + switch (mm) + { + default: + if (vpicFetch.mfp.mm >= MM_META_MAX) + goto Failed; + if ( ((hDataDescriptor=OurGlobalAlloc(wAlloc, + (long)sizeof(METAFILEPICT) ))==NULL) || + ((lpch=GlobalLock( hDataDescriptor ))==NULL)) + { + goto Failed; + } + else + { + vpicFetch.mfp.hMF = hData; + //asserts to allow use of bltbx + Assert (sizeof(METAFILEPICT) < 65535); + Assert ((unsigned)(-LOWORD(lpch)) >= (unsigned)sizeof(METAFILEPICT) || + (unsigned)(-LOWORD(lpch)) == 0); + bltbx( (LPCH) &vpicFetch.mfp, lpch, sizeof(METAFILEPICT)); + GlobalUnlock( hDataDescriptor ); + } + break; + + case MM_DIB: + hDataDescriptor = hData; + break; // should just need to pass the data to clip + + case MM_BITMAP: + { + int yp1mm, xp1mm; + + if (fDIBInMf) // this is the case where we convert a DIB to a bitmap + { + // what we got in hData now are the DIB header/color table + // and DIB bits + + int cbInfoHdr; + LPCH lpBits; + HANDLE hGDI; + FARPROC lpfn; + + if ((hGDI = GetModuleHandle(SzShared("GDI"))) == NULL) + goto Failed; + + lpfn = GetProcAddress(hGDI, MAKEINTRESOURCE(idoCreateDIBitmap)); + Assert(lpfn != NULL); + + if ((lpch = GlobalLock(hData)) == NULL) + { + goto Failed; + } + + if (((LPBITMAPINFOHEADER)lpch)->biCompression != BI_RGB) + { + // Don't handle DIB that is compressed yet + GlobalUnlock(hData); + goto Failed; + } + + cbInfoHdr = CbDIBHeader(lpch); + lpBits = LpchIncr(lpch, cbInfoHdr); + + Assert(wwCur != wwNil); + Assert(PwwdWw(wwCur)->hdc != NULL); + // calling CreateDIBitmap (a Win 3 call) through GetProcAddress + // because we still have to run under Win 2 + if ((hDataDescriptor = (*lpfn)(PwwdWw(wwCur)->hdc, + (LPBITMAPINFOHEADER)lpch, (DWORD)CBM_INIT, + (LPSTR)lpBits, (LPBITMAPINFO)lpch, DIB_RGB_COLORS)) == NULL) + { + GlobalUnlock(hData); + goto Failed; + } + } + else if ( ((lpch=GlobalLock( hData ))==NULL) || + (vpicFetch.bm.bmBits=lpch, + ((hDataDescriptor= + CreateBitmapIndirect((LPBITMAP)&vpicFetch.bm))==NULL))) + { + if (lpch != NULL) + GlobalUnlock( hData ); + goto Failed; + } + + // now we got hDataDescriptor being the handle to the bitmap + + // Specify the "goal size" for this guy + // convert twips back to .1mm units. + LogGdiHandle(hDataDescriptor, 1028); + xp1mm = NMultDiv (vpicFetch.dxaGoal, 100, czaCm); + yp1mm = NMultDiv (vpicFetch.dyaGoal, 100, czaCm); + SetBitmapDimension( hDataDescriptor, xp1mm, yp1mm); +#ifdef XBZTEST + { + long lT; + + lT = GetBitmapDimension( hDataDescriptor ); + CommSzNum(SzShared("FWritePict bitmap dimension x: "), LOWORD( lT )); + CommSzNum(SzShared("FWritePict bitmap dimension y: "), HIWORD( lT )); + } +#endif /* XBZTEST */ + + + GlobalUnlock( hData ); + GlobalFree( hData ); /* Bitmap was copied by CreateBitmapIndirect, + don't need it anymore */ + hData = NULL; + break; + } + } /* switch (mm) */ + + + + /* Scaling/cropping note: the scaling and cropping info is + maintained within Opus; there is no good way to render only + a portion of the bitmap or metafile, so the entire picture is + given to the clipboard. bz 12/23/87 + */ + + /* here, hDataDescriptor has the bitmap or metafile. If this + if for DDE (cbInitial != 0), then we must allocate another + block that includes the cbInitial data and hDataDescriptor + */ + + if (!cbInitial) + return hDataDescriptor; + else + { + hReturn = GlobalAlloc2( wAlloc, + (long)(cbInitial + sizeof (HANDLE)) ); + if (hReturn != NULL) + { + if ( ( lpch=GlobalLock(hReturn) ) != NULL ) + { + bltbx( (LPCH) &hDataDescriptor, LpchIncr(lpch, cbInitial), + sizeof(HANDLE) ); + GlobalUnlock( hReturn ); + return hReturn; + } + } + /* fall through intentional */ + } + + +Failed: + if (hDataDescriptor != NULL) + { + if (vpicFetch.mfp.mm == MM_BITMAP || fDIBInMf) + { + UnlogGdiHandle(hDataDescriptor, 1028); + DeleteObject (hDataDescriptor); + } + else + // metafile, dib in metafile + GlobalFree(hDataDescriptor); + } + + if (hData != NULL) + GlobalFree( hData ); + + if (hReturn != NULL) + GlobalFree( hReturn); + + return NULL; +} + + + + +/* I C H F R O M C P V F L I */ +/* Returns the ich of the character in vfli.rgch representing cp, or + the first represented character after cp. +*/ +/* %%Function: IchFromCpVfli %%Owner: bobz */ + +IchFromCpVfli (cp) +CP cp; + +{ + CP cpCur = vfli.cpMin; + int ich, dch; + struct CHR *pchr; + + pchr = &(**vhgrpchr)[0]; + ich = 0; + while (cpCur < cp) + { + dch = pchr->ich - ich; + if (cpCur + dch >= cp) + return ich + cp - cpCur; + cpCur += dch; + ich += dch; + if (pchr->chrm == chrmVanish) + cpCur += ((struct CHRV *)pchr)->dcp; + else if (pchr->chrm == chrmDisplayField) + { + ich++; + cpCur += ((struct CHRDF *)pchr)->dcp; + } + /* result is garbage with formulas! + PETER - do you know why this is? Before we call this we + are setting grpfVisi.fForceField to make everything show up in + instructions mode. Isn't a formula just a field? Why would + this be a problem? (bz) + BOB - the problem is that we are asking for (and getting) the + result of the field, not the instructions. Formula results, + if viewed as a stream (which we are doing here), may not be very + meaningful. We probably should leave it the way it is, but + first look at what kind of result we are getting and see just how + bad it is. (pj) + + RE: from bob. We do get funny chars, but we call SanitizeRgch on + the result, so non-printing chars become . and some others get + cleaned up. I think this is about the best we can do unless we + put out field instructions rather than results, which is generally + less desirable. + */ + Assert (ich < vfli.ichMac); + Assert (pchr->chrm); + Assert (pchr->chrm != chrmEnd); + (char *)pchr += pchr->chrm; + } + return ich; +} + + + +/* F R E A D E X T S C R A P */ +/* %%Function: FReadExtScrap %%Owner: bobz */ + +int FReadExtScrap() + { /* Transfer the external scrap to the scrap document. This means: + read the contents of the clipboard into docScrap, using whatever + available standard format we can process. Return fFalse=ERR, fTrue=OK */ + + HANDLE hClipboard; + int cf = cfNil; + BOOL fOk = fFalse; + struct CA ca; + +#ifdef DEBUG + /* used for testing paste - forces us to paste in from clipboard + even if we owned it. Set in SlapWnd and for debugging, turned off when + we load something into the clipboard. + */ + extern int vTestClip; + + Assert( !vsab.fOwnClipboard || vTestClip); +#endif /* DEBUG */ + + if ( !OpenClipboard( vhwndApp ) ) + { +#ifdef BZ + CommSzSz(SzShared("FReadExtScrap failure: OpenClipboard"), szEmpty); +#endif + return fFalse; + } + + vsab.fMayHavePic = vsab.fExt = vsab.fPict = vsab.fBlock = + vsab.fFormatted = fFalse; + vsab.fExtEqual = fTrue; + + + /* FReadHdata will clear out any previously set styles/fonts */ + + /* Get the handle for the highest-priority type available */ + while ((cf = CfNextCf (cf,fFalse)) != cfNil) + { + hClipboard = GetClipboardData (cf); + +#ifdef BZ + CommSzNum(SzShared("FReadExtScrap cf: "), cf); + CommSzNum(SzShared("FReadExtScrap hClipboard from GetClipboardData: "), + hClipboard); +#endif + + if (hClipboard != NULL && + FReadHData (hClipboard, cf, PcaSetWholeDoc(&ca,docScrap),0)) + { + /* data sucessfully read into docScrap */ + fOk = fTrue; + if (cf == CF_BITMAP || cf == CF_METAFILEPICT || cf == CF_DIB) + { + vsab.fMayHavePic = vsab.fPict = fTrue; + } + if (cf != CF_TEXT) + vsab.fFormatted = fTrue; + break; + } +#ifdef BZ + else + CommSzSz(SzShared("FReadExtScrap failure: FReadHData"), szEmpty); +#endif + } + /* styles/fonts are either put into docScrap with RTF or do not + differ from standard. At any rate, docScrap contains its fonts + and styles at this point, and it does not come from any + outside doc. + */ + vsab.docStsh = docNil; + CloseClipboard(); + + return fOk; + +} + + +/* F R E A D H D A T A */ +/* Read data from hData to replace text in doc at cpFirst:cpLim. + Text is in format cf. Skip the first cbInitial bytes. + Return fFalse if the text cannot be read in format cf or in case + of other error. +*/ +/* %%Function: FReadHData %%Owner: bobz */ + + +FReadHData (hData, cf, pca, cbInitial) +HANDLE hData; +int cf; +struct CA *pca; +int cbInitial; +{ + int docDest; + BOOL fOk; + struct CA ca; + +#ifdef BZ + CommSzNum(SzShared("FReadHData cf: "), cf); +#endif + + switch (cf) + { + case CF_TEXT: + case CF_DIB: + case CF_BITMAP: + case CF_METAFILEPICT: + break; + default: + if (cf == cfPrPic && cfPrPic != cfNil) + /* Excel printer metafile format */ + { + cf = CF_METAFILEPICT; + break; + } + + if (cf != cfRTF) + { + return fFalse; + } + } + + /* get document to put text into */ + if (pca->doc == docScrap) + /* if pasting to scrap, use docScrap directly */ + docDest = docScrap; + /* otherwise use vdocScratch */ + else if ((docDest = DocCreateScratch (pca->doc)) == docNil) + return fFalse; + + /* empty the destination doc and set styles, fonts to standard */ + SetWholeDoc (docDest, PcaSetNil(&ca)); + ResetDocStsh(docDest, fTrue /* fMinimal */); + ResetDocFonts(docDest); + + switch (cf) + { + case CF_DIB: + case CF_BITMAP: + case CF_METAFILEPICT: + fOk = FReadPict (PcaPoint(&ca, docDest, cp0 ), cf, + hData, cbInitial, fFalse /* fEmptyPic */, + NULL /* pchp */, NULL /* prcWinMF */); + break; + default: + Assert (cf == cfRTF); + fOk = FReadRTF (docDest, cf, hData, cbInitial); + break; + case CF_TEXT: + fOk = FReadText (docDest, cf, hData, cbInitial); + } + + fOk &= (!vmerr.fMemFail && !vmerr.fDiskFail); + + if (fOk) + { + struct CA caDest; + + ScratchBkmks(PcaSetWholeDoc( &caDest, docDest)); + + if (pca->doc != docScrap) + /* we were sucessfull, copy the new data over the old */ + { + Assert (docDest == vdocScratch); + + CachePara(pca->doc, pca->cpFirst); + if (vpapFetch.fTtp || + !FMoveOkForTable(pca->doc, pca->cpLim, &caDest) || + !FDeleteableEop(pca, rpkCa, &caDest) || + !FReplaceCps( pca, &caDest )) + fOk = fFalse; + else + { + pca->cpLim = pca->cpFirst + DcpCa(&caDest); + CopyStylesFonts (docDest, pca->doc, pca->cpFirst, DcpCa(pca)); + AssureNestedPropsCorrect(pca, fFalse); + } + } + else + pca->cpLim = pca->cpFirst + DcpCa(&caDest); + } + + /* if we failed, empty the document */ + if (!fOk) /* fOk may be reset above */ + SetWholeDoc (docDest, PcaSetNil(&ca)); + +#ifdef DEBUG + if (pca->doc != docScrap) + ReleaseDocScratch(); +#endif /* DEBUG */ + + return fOk; +} + + + +/* F R E A D T E X T */ +/* Read text data from hData into docDest. + + Used for CF_TEXT . FReadRTF in rtfin.c used for rtf +*/ +/* %%Function: FReadText %%Owner: bobz */ + + +FReadText (docDest, cf, hData, cbInitial) +int docDest; +int cf; +HANDLE hData; +int cbInitial; +{ + BOOL fEol; + struct RIBL **hribl; + struct PAP papT; + struct CHP chpT; + LPCH lpch; + unsigned long lcb; + CHAR rgch[256]; + CP cp = cp0; + + /* NOTE: Under Windows, global handle sizes are rounded up to the + nearest 16-byte bound. We compensate for the fact that lcb may + be larger than the actual size of the scrap object by checking + for a null terminator. See CchReadLineExt. */ + + /* note: if lcb is more than 64K, our simple methods won't work--don't try */ + if ((lcb = GlobalSize(hData)) > 0x00010000L) + return fFalse; + + if ((lpch = GlobalLockClip(hData)) == NULL ) + return fFalse; + + /* skip unwanted portion */ + lpch += cbInitial; + lcb -= cbInitial; + + StandardChp(&chpT); + StandardPap(&papT); + + while (lcb > 0 && !vmerr.fMemFail && !vmerr.fDiskFail) + { + + /* Copy bytes from lpch to doc's cp stream */ + unsigned cch = lcb < 255 ? lcb : 255; + + if ((cch = CchReadLineExt( lpch, cch, rgch, &fEol))==0) + /* Reached terminator */ + break; + + FInsertRgch( docDest, cp, rgch, cch, &chpT, + (fEol) ? &papT : 0); + cp += (CP) cch; + + + lcb -= cch; + lpch += cch; + } + + GlobalUnlock (hData); + + return (fTrue); +} + + +/* F R E A D P I C T */ +/* Read picture data from hData into docDest. + + Used for (at least) CF_BITMAP and CF_METAFILE +*/ +/* %%Function: FReadPict %%Owner: bobz */ + + +FReadPict (pcaDest, cf, hData, cbInitial, fEmptyPic, pchp, prcWinMF) +struct CA *pcaDest; +int cf; +HANDLE hData; +int cbInitial; +BOOL fEmptyPic; +struct CHP *pchp; +struct RC *prcWinMF; /* window org/ext rc for metafiles. may be null */ +{ + extern LPCH LpchIncr(); + + struct CHP chpT; + CHAR rgch[256]; + struct PIC picInfo; + HBITMAP hbmMono=NULL; + HANDLE hBits; + HANDLE hDIB = NULL; + LPCH lpch; + unsigned long lcb; + unsigned long lcbPicData; + int cbOverhead = 0; + int cch; + BOOL fOk = fFalse; + BOOL fPMDIB = fFalse; /* if true, needs to convert the DIB to Win 3 format */ + METAFILEPICT mfp; + struct MFHDRDIBMF mfhdr; /* leading record for DIB in metafile */ + struct WINMRTAG mftag; /* trailing record for DIB in metafile */ +#ifdef DEBUG + LPCH lpchSave; +#endif + + + Profile( vpfi == pfiPictPaste ? StartProf( 30) : 0); + + if (cbInitial != 0) /* true only for DDE */ + { + HANDLE hDDE; + + if ((lpch = GlobalLockClip(hData)) == NULL ) + return fFalse; + + /* for DDE, the actual data handle is in word 3 of the + handle passed to us. Since we did not need to free up + hData anyway, we just set it to the new data location + */ + /* get to actual data handle address */ + lpch += cbInitial; + bltbx( lpch, &hDDE, sizeof(HANDLE)); + GlobalUnlock( hData ); + hData = hDDE; + } + + + SetBytes( &picInfo, 0, cbPIC); + picInfo.mx = mx100Pct; + picInfo.my = my100Pct; + + picInfo.brcl = brclNone; + +#ifdef INEFFICIENT + picInfo.dyaCropTop = 0; + picInfo.dxaCropLeft = 0; + picInfo.dyaCropBottom = 0; + picInfo.dxaCropRight = 0; +#endif /* INEFFICIENT */ + + + /* make local chp which can be modified */ + if (pchp == NULL) + StandardChp(&chpT); + else + chpT = *pchp; + + ShrinkSwapArea(); /* allow more memory for pics */ + + if (cf == CF_BITMAP && vwWinVersion >= 0x0300) + { + /* convert a color bitmap into a DIB under win 3 or beyond, + so that picture shows up in color instead of our old way of + converting it to monochrome bitmap + */ + BITMAP bm; + unsigned long lcbBits; + int cbInfoHdr; + LPCH lpBits; + LPCH lpBitsInfo; + HANDLE hGDI; + FARPROC lpfn; + int cBitsPix; + + + if (GetObject(hData, sizeof(BITMAP), &bm) < sizeof(BITMAP)) + goto ReadDone; // error reading bitmap descriptor + + cBitsPix = bm.bmPlanes * bm.bmBitsPixel; + if (cBitsPix > 1) // color bitmap -> convert + { + if (cBitsPix != 4 && cBitsPix != 8 && cBitsPix != 24) + { + // don't know how to handle these non standard cases, leave it to + // the normal procedure +#ifdef BZ + CommSzSz(SzShared("FReadPict: Non standard bm, can't convert to DIB"), szEmpty); +#endif /* BZ */ + goto LKeepGoing; + } + + if ((hGDI = GetModuleHandle(SzShared("GDI"))) == NULL) + goto LKeepGoing; + + Assert(wwCur != wwNil); + + // size of DIB required + lcbBits = (long)WIDTHBYTES(cBitsPix * bm.bmWidth) * (long)bm.bmHeight; + + cbInfoHdr = sizeof(BITMAPINFOHEADER); + // size of color table required + if (cBitsPix != 24) + cbInfoHdr += (1 << cBitsPix) * sizeof(RGBQUAD); + + if ((hDIB = GlobalAlloc2(GMEM_MOVEABLE, + (DWORD)((long)cbInfoHdr + lcbBits))) == NULL || + (lpBitsInfo = GlobalLock(hDIB)) == NULL) + { + goto ReadDone; + } + +#define lpbi ((LPBITMAPINFOHEADER) lpBitsInfo) + bltbcx(0, lpBitsInfo, sizeof(BITMAPINFOHEADER)); // init + lpbi->biSize = sizeof(BITMAPINFOHEADER); + lpbi->biWidth = bm.bmWidth; + lpbi->biHeight = bm.bmHeight; + lpbi->biBitCount = cBitsPix; + lpbi->biPlanes = 1; +#undef lpbi + lpBits = LpchIncr(lpBitsInfo, (unsigned)cbInfoHdr); + + lpfn = GetProcAddress(hGDI, MAKEINTRESOURCE(idoGetDIBits)); + Assert(lpfn != NULL); + // calling GetDIBits (a Win 3 call) through GetProcAddress + // because we still have to run under Win 2 + if ((*lpfn)(PwwdWw(wwCur)->hdc, hData, 0, bm.bmHeight, (LPSTR)lpBits, + (LPBITMAPINFO)lpBitsInfo, DIB_RGB_COLORS) != bm.bmHeight) + { + GlobalUnlock(hDIB); + goto ReadDone; + } + + GlobalUnlock(hDIB); + hData = hDIB; + cf = CF_DIB; + // we now got a DIB, request DIB format, so it will be turned + // into a metafile + } + } + +LKeepGoing: + + switch (cf) + { + case CF_DIB: + { + + /* at this point hData is a memory handle to a DIB */ + /* embed the DIB into a metafile */ + + int cbDIBHdr; /* the header inside a DIB */ + unsigned long lcbDIB; /* DIB bits */ + int bmWidth; + int bmHeight; + int bmBitsPixel; + + lpch = GlobalLock(hData); + picInfo.mfp.mm = MM_ANISOTROPIC; // convert a DIB to be embedded in a metafile + +#define lpbc ((LPBITMAPCOREHEADER) lpch) +#define lpbi ((LPBITMAPINFOHEADER) lpch) + +#ifdef DEBUG + lpchSave = lpch; +#endif + if ((cbDIBHdr = CbDIBHeader(lpbi)) == 0) + { + GlobalUnlock(hData); + goto ReadDone; + } + + if (lpbi->biSize == (DWORD)sizeof(BITMAPINFOHEADER)) /* Win 3.0 */ + { + + /* Remove the following check when we work with Run-Length Encoding */ + + if (lpbi->biCompression != BI_RGB) + { + GlobalUnlock(hData); + goto ReadDone; + } + + bmWidth = (WORD) lpbi->biWidth; + bmHeight = (WORD) lpbi->biHeight; + bmBitsPixel = (WORD) lpbi->biBitCount; + } + else if (lpbc->bcSize == (DWORD)sizeof(BITMAPCOREHEADER)) /* Old PM 1.1, 1.2 format */ + { + bmWidth = lpbc->bcWidth; + bmHeight = lpbc->bcHeight; + bmBitsPixel = lpbc->bcBitCount; + + fPMDIB = fTrue; /* need to convert DIB to Win 3 format later */ + + /* add in the difference between Win 3 and PM DIB header size */ + cbDIBHdr += (sizeof(BITMAPINFOHEADER) - sizeof(BITMAPCOREHEADER)) + + /* color table difference */ + (bmBitsPixel == 24 ? 0 : (1 << bmBitsPixel)); + } + else /* unknown format */ + { + GlobalUnlock(hData); + goto ReadDone; + } + + lcbDIB = (long) WIDTHBYTES((DWORD)bmWidth * bmBitsPixel) * + (long)bmHeight; + + /* this will set size based on current screen resolution */ + mfp.mm = MM_BITMAP; + mfp.xExt = bmWidth; + mfp.yExt = bmHeight; + FComputePictSize( &mfp, &picInfo.dxaGoal, &picInfo.dyaGoal ); + + /* have to convert from twips to himetrics */ + picInfo.mfp.xExt = UMultDiv(picInfo.dxaGoal, 1000, czaCm); + picInfo.mfp.yExt = UMultDiv(picInfo.dyaGoal, 1000, czaCm); + + lcbPicData = (unsigned long)cbDIBHdr + lcbDIB; + + /* build the leading and trailing metafile records */ + BuildMFRecordForDIB(&mfhdr, &mftag, lcbPicData, bmWidth, bmHeight); + + cbOverhead = cbMFHDRDIBMF + cbWINMRTAG; + + break; + } + + case CF_BITMAP: + { /* Set up Picinfo structure for bitmap */ + long lBmDimension; + + picInfo.mfp.mm = MM_BITMAP; + + /* at this point hData is a GDI handle to a BITMAP, which + must be manipulated with GetObject, etc; it is not just + a global handle with data in it. + */ + + if (GetObject( hData, sizeof( BITMAP ), (LPSTR)&picInfo.bm ) + < sizeof (BITMAP)) + { /* Error reading bitmap descriptor */ + goto ReadDone; + } + + /* size used below. Grab it before converting color to mono or that is lost */ + lBmDimension = GetBitmapDimension( hData ); + +#ifdef BZ + CommSzNum(SzShared("Bitmap dimension xExt at insert: "), LOWORD( lBmDimension )); + CommSzNum(SzShared("Bitmap dimension yExt at insert: "), HIWORD( lBmDimension )); +#endif + /* Again, we are not responsible for freeing the data + in hData, so we can reuse the variable here. + */ + + if (picInfo.bm.bmPlanes > 1 || picInfo.bm.bmBitsPixel > 1) + { /* Color bitmap --> make it monochrome */ + + if ((hbmMono = HbmMonoFromHbmColor( hData )) != NULL) + { + hData = hbmMono; + if (GetObject( hData, sizeof( BITMAP ), + (LPSTR)&picInfo.bm ) < sizeof (BITMAP)) + { /* Error reading bitmap descriptor */ + goto ReadDone; + } + } + else + /* Error -- could not make it monochrome */ + goto ReadDone; + } + + /* store Ideal/goal size here */ + + /* trick 1: we want to store these values in twips. They + are in .1mm units as are MM_LOMETRIC metafiles. We + build a fake metafile with these values and MM_LOMETRIC + and FComputePictSize will do it for us. + */ + if (lBmDimension != 0L) + { + mfp.mm = MM_LOMETRIC; + mfp.xExt = LOWORD( lBmDimension ); + mfp.yExt = HIWORD( lBmDimension ); + FComputePictSize( &mfp, &picInfo.dxaGoal, + &picInfo.dyaGoal ); + } + else /* no goal size */ + /* trick 2: this will set size based on current screen resolution */ + { + mfp.mm = MM_BITMAP; + mfp.xExt = picInfo.bm.bmWidth; + mfp.yExt = picInfo.bm.bmHeight; + FComputePictSize( &mfp, &picInfo.dxaGoal, + &picInfo.dyaGoal ); + } + + /* redundant, but the ext fields are the actual size, and + so are consistent for bitmaps and metafiles this way. + */ + + picInfo.mfp.xExt = picInfo.bm.bmWidth; + picInfo.mfp.yExt = picInfo.bm.bmHeight; + + lcbPicData = ((unsigned long) picInfo.bm.bmWidthBytes * + (unsigned long) picInfo.bm.bmHeight * + (unsigned long) picInfo.bm.bmPlanes ); + + /* Get the bitmap bits into a global handle */ + if ( ((hBits = GlobalAlloc2( GMEM_MOVEABLE, lcbPicData ))==NULL) || + ((lpch = GlobalLock( hBits )) == NULL) || + (GetBitmapBits( hData, lcbPicData, lpch ) == 0)) + { + /* Error */ + goto ReadDoneFree; + } + break; + } + + case CF_TIFF: + { /* Set up Picinfo structure for tiff bitmap. Put + lcb as the size of stFile and point lpch to + the start of stFile. + */ + + picInfo.mfp.mm = MM_TIFF; + + /* at this point hData is a global handle with a BITMAP + struct followed by the normalized stFile for the + tiff file. + */ + + if ((lpch=(BITMAP FAR *)GlobalLockClip(hData))==NULL) + { + goto ReadDone; + } + + bltbx( lpch, (BITMAP FAR *)&picInfo.bm, + sizeof(BITMAP)); + lpch += sizeof(BITMAP); /* point lpch at stFile */ + + /* store Ideal/goal size here */ + GetGrSize(ftTIFF, &picInfo.dyaGoal, + &picInfo.dxaGoal ); + + picInfo.mfp.xExt = picInfo.bm.bmWidth; + picInfo.mfp.yExt = picInfo.bm.bmHeight; + + /* data is just the file name */ + lcbPicData = (unsigned long) (*lpch + 1); + break; + } + + default: /* metafile */ + { + int mm; + METAFILEPICT FAR *lpmfp; + + /* Set up PicInfo structure for Metafile Picture */ + Assert (cf == CF_METAFILEPICT); + if ((lpmfp=(METAFILEPICT FAR *)GlobalLockClip(hData))==NULL) + { + goto ReadDone; + } + bltbx( lpmfp, (METAFILEPICT FAR *)&picInfo.mfp, + sizeof(METAFILEPICT)); + GlobalUnlock( hData ); + + if ((lpch=GlobalLockClip( picInfo.mfp.hMF ))==NULL) + { + goto ReadDone; + } + + lcbPicData = GlobalSize( picInfo.mfp.hMF ); + mfp = picInfo.mfp; + +#ifdef BZ + CommSzRgNum(SzShared("ReadPict - mfp at insert: "), &mfp, + CwFromCch(sizeof(METAFILEPICT))); + CommSzLong(SzShared("Readpict metafile globalsize lcbPicData: "), lcbPicData); +#endif + + /* note: failure implies bogus metafile: abort */ + if (!FComputePictSize( &mfp, &picInfo.dxaGoal, + &picInfo.dyaGoal )) + { + goto ReadDoneFree; + } + + if (prcWinMF != NULL) /* indicates that the metafile is supplied by convertor */ + { + /* need to add SetWindowOrg, SetWindowExt records to the metafile */ + /* so increment size */ + cbOverhead = sizeof (struct WMFWINOE); /* see below */ + } + + + break; + } + } /* switch (cf) */ + + + + /* Here we write out to the scratch file */ + + lcb = lcbPicData + (unsigned long)cbOverhead; + + /* Insert Picinfo structure into scratch file */ + picInfo.cbHeader = cbPIC; + picInfo.lcb = lcb + cbPIC; /* lcb includes header size */ + + /* ensure pic starts on a long word boundary */ + PfcbFn(fnScratch)->cbMac = ((PfcbFn(fnScratch)->cbMac + 3) >> 2) << 2; + /* this has to be contiguous, don't use holes in scratch file */ + vfkpdText.pn = pnNil; + + + /* do this so we actually don't need to put anything in the metafile + and will still get something the right size that shows up as a bordered + square. This is done only for metafiles inserted with CndInsPicture. + Force the size to be 1" square too. + */ + if (fEmptyPic) + { + picInfo.brcl = brclSingle; + picInfo.dxaGoal = picInfo.dyaGoal = czaInch; + picInfo.fFrameEmpty = fTrue; + } + + chpT.fcPic = FcAppendRgchToFn(fnScratch, &picInfo, cbPIC); + +#ifdef BZ + CommSzRgNum(SzShared("ReadPict - picInfo at insert: "), &picInfo, + CwFromCch(cbPIC)); +#endif + +#ifdef DCLIPPIC + CommSzLong(SzShared("chp.fcPic during FReadPict fcAppend: "), chpT.fcPic); +#endif + chpT.fSpec = 1; + chpT.fnPic = 0; /* will be set at format; clears fDirty */ + + /* prcWinMF is only used for grpi special metafiles; + if null, the rc is 0 and we set the window org to 0,0 + and its extent to the page size. + If non-null, insert metafile instructions for Window Origin and + Window Extent into the start of the metafile, following the metafile header. + That is, increment the header file size, dump the header, then + these records. + + */ + + if (cf == CF_METAFILEPICT && prcWinMF != NULL) + { + int dxp, dyp; + struct WMFWINOE wmfwinoe; + struct METAHDR FAR *pMetaHdr = lpch; + + cch = pMetaHdr->mtHeaderSize * sizeof(WORD); + if (cch > sizeof(rgch) || (long)cch > lcbPicData) + { + goto ReadDoneFree; + } + + pMetaHdr->mtSize += (long)cwWMFWINOE; /* size is in words */ + + bltbxHuge(lpch, (char far *) rgch, cch, fTrue /* fSrcHuge */); + +#ifdef BZ + CommSzNum(SzShared("Import metafile header size: "), cch); +#endif /* BZ */ + + /* dump the header */ + FcAppendRgchToFn(fnScratch, rgch, cch); + lcbPicData -= cch; + + wmfwinoe.cwWinOrigin = wmfwinoe.cwWinExtent = + /* cw for each rec: total cb /4 */ + (long)(sizeof(struct WMFWINOE) >> 2); + wmfwinoe.kwdWinOrigin = META_SETWINDOWORG; + wmfwinoe.xpWinOrigin = prcWinMF->xpLeft; + wmfwinoe.ypWinOrigin = prcWinMF->ypTop; + wmfwinoe.kwdWinExtent = META_SETWINDOWEXT; + wmfwinoe.xpWinExtent = prcWinMF->xpRight - prcWinMF->xpLeft; + wmfwinoe.ypWinExtent = prcWinMF->ypBottom - prcWinMF->ypTop; + + Assert (wmfwinoe.xpWinExtent > 0 && wmfwinoe.ypWinExtent > 0); + +#ifdef BZ + CommSzRgNum(SzShared("ReadPict - WMFWINOE: "), &wmfwinoe, + CwFromCch(sizeof(struct WMFWINOE))); +#endif /* BZ */ + + FcAppendRgchToFn(fnScratch, &wmfwinoe, sizeof (struct WMFWINOE)); + + // will likely never overflow 64k, but calling LpchIncr rather + // than having to prove that. cch will never be > 64K, but it would be possible + // to advance lpch previously, so this removes any possibility of + // overflow. bz + + lpch = LpchIncr(lpch, cch); + } + else if (cf == CF_DIB) + { + /* If handleing DIB, insert the leading metafile record */ + FcAppendRgchToFn(fnScratch, &mfhdr, cbMFHDRDIBMF); + + if (fPMDIB) /* convert PM DIB header to Win 3 format */ + { + BITMAPINFOHEADER bminfohdr; + int cbRGB; + + /* lpbc is defined to be lpch, make sure no one have changed + lpch since this code was written */ + Assert(lpchSave == lpch); + + /* bitmapinfohdeader to bitmapcoreheader */ + SetBytes(&bminfohdr, 0, sizeof(BITMAPINFOHEADER)); + bminfohdr.biSize = sizeof(BITMAPINFOHEADER); + bminfohdr.biWidth = (DWORD)lpbc->bcWidth; + bminfohdr.biHeight = (DWORD)lpbc->bcHeight; + bminfohdr.biPlanes = lpbc->bcPlanes; + bminfohdr.biBitCount = lpbc->bcBitCount; + /* rest of bminfohdr are zeros by SetBytes */ + +#undef lpbc +#undef lpbi + + FcAppendRgchToFn(fnScratch, &bminfohdr, sizeof(BITMAPINFOHEADER)); + + lpch = LpchIncr(lpch, sizeof(BITMAPCOREHEADER)); + lcbPicData -= sizeof(BITMAPINFOHEADER); + + /* color table - rgbTriple to rgbQuad */ + // cbRGB is the number of source bytes to read based on planes. + // 1 plane: 6 bytes -> 8 + // 4 planes: 48 bytes -> 64 + // 8 planes: 256 * 3 bytes -> 256 * 4 + if (bminfohdr.biBitCount == 24) + cbRGB = 0; + else + cbRGB = (1 << bminfohdr.biBitCount) * 3; + + // for 8 planes we need to make 4 passes, so we fit in rgch, + // converting 192-> 256 at a time. 1 and 4 planes can be done + // in 1 pass. + + while (cbRGB && !vmerr.fMemFail && !vmerr.fDiskFail) + { + int cbCur; + char * psrc; + char * pdst; + + bltbx(lpch, (LPCH)&rgch, (cbCur = min(cbRGB, 192))); + psrc = rgch + cbCur; // at end of triples + pdst = psrc + (cbCur / 3); // where quads will end + + while (psrc > rgch) + { + *--pdst = 0; + *--pdst = *--psrc; + *--pdst = *--psrc; + *--pdst = *--psrc; + } + + lpch = LpchIncr(lpch, cbCur); + cbRGB -= cbCur; + cbCur += cbCur / 3; + FcAppendRgchToFn(fnScratch, &rgch, cbCur); + lcbPicData -= cbCur; + } + } + } + + /* put pic bits into fnScratch */ + for (; !vmerr.fMemFail && !vmerr.fDiskFail && lcbPicData > 0L; + lcbPicData -= cch, lpch = LpchIncr(lpch, cch)) + { + bltbxHuge(lpch, (char far *) rgch, + cch = (lcbPicData > 256L) ? 256 : lcbPicData, + fTrue /* fSrcHuge */); + FcAppendRgchToFn(fnScratch, rgch, cch); + } + + // Write out the trailing metafile record for DIB case, + // we got a DIB embeded inside a metafile! + if (cf == CF_DIB) + FcAppendRgchToFn(fnScratch, &mftag, cbWINMRTAG); + + fOk = !vmerr.fDiskFail && !vmerr.fMemFail; + + if (fOk && FNewChpIns(pcaDest->doc, pcaDest->cpFirst, &chpT, stcNil)) + { + /* put special picture char in docDest */ + char ch = chPicture; + +#ifdef DCLIPPIC + CommSzLong(SzShared("chp.fcPic during FReadPict after Fn: "), chpT.fcPic & 0x00FFFFFF); + CommSzNum(SzShared("chp.fnPic during FReadPict: "), chpT.fnPic); +#endif + + if (pcaDest->doc == selCur.doc) + FReplaceRM( pcaDest, fnScratch, + FcAppendRgchToFn(fnScratch, &ch, 1), (FC)1); + else + FReplace(pcaDest, fnScratch, + FcAppendRgchToFn(fnScratch, &ch, 1), (FC) 1); +#ifdef DCLIPPIC + CachePara(pcaDest->doc, pcaDest->cpFirst); + FetchCp(pcaDest->doc, pcaDest->cpFirst, fcmProps); + CommSzRgNum(SzShared("vchpFetch after insert pic: "), &vchpFetch, cwCHP); +#endif + + /* record the fact that document may have a pict */ + PdodMother(pcaDest->doc)->fMayHavePic = fTrue; + } + + fOk = !vmerr.fDiskFail && !vmerr.fMemFail; + +ReadDoneFree: + switch (picInfo.mfp.mm) + { + default: + Assert (picInfo.mfp.mm < MM_META_MAX); + GlobalUnlock( picInfo.mfp.hMF ); + if (cf == CF_DIB) /* get to here because a DIB turns into a metafile */ + GlobalUnlock(hData); + break; + + case MM_TIFF: + GlobalUnlock( hData ); + break; + + case MM_BITMAP: + GlobalUnlock( hBits ); + GlobalFree( hBits ); + break; + } + +ReadDone: + + GrowSwapArea(); /* restore */ + + if (hbmMono != NULL) + { + DeleteObject( hbmMono ); + } + + if (hDIB != NULL) + { + GlobalFree(hDIB); + } + + if (vmerr.fDiskFail || vmerr.fMemFail) + { + struct CA ca; + + if (pcaDest->doc != selCur.doc) + SetWholeDoc( pcaDest->doc, PcaSetNil(&ca)); + fOk = fFalse; + } + + Profile( vpfi == pfiPictPaste ? StopProf() : 0); + + return fOk; +} + + + +/********************************/ +/* %%Function: HbmMonoFromHbmColor %%Owner: bobz */ + +HbmMonoFromHbmColor( hbmSrc ) +HBITMAP hbmSrc; + { /* Return a monochrome copy of the passed bitmap. Return NULL + if an error occurred. Assumes that the passed bitmap can be + selected into a memory DC which is compatible with the doc DC. */ + + extern long rgbBkgrnd; + extern long rgbText; + extern HWND vhWnd; + + BITMAP bm; + HBITMAP hbmMono=NULL; + HDC hMDCSrc = NULL; + HDC hMDCDst = NULL; + + /* Create memory DC for source, set colors, select in passed bitmap */ + + if ( (hMDCSrc = CreateCompatibleDC( (*hwwdCur)->hdc )) == NULL ) + goto BmFailure; + LogGdiHandle(hMDCSrc, 1038); + +#ifdef BOGUS + /* We can't assume that every window out there has the same window colors that + we have. In fact, we have no way to figure out how to convert this color + bitmap; so white will map to white and everything else will map to black. */ + SetBkColor( hMDCSrc, rgbBkgrnd ); + SetTextColor( hMDCSrc, rgbText ); +#endif /* BOGUS */ + + if (SelectObject( hMDCSrc, hbmSrc ) == NULL) + goto BmFailure; + + /* Create memory DC for destination, select in a new monochrome bitmap */ + + if ( ((hMDCDst = CreateCompatibleDC( (*hwwdCur)->hdc )) == NULL) || + ((GetObject( hbmSrc, sizeof (BITMAP), (LPSTR) &bm ) == 0)) || + ((hbmMono = CreateBitmap( bm.bmWidth, bm.bmHeight, + 1, 1, (LPSTR) NULL )) == NULL) || + Debug((hbmMono == NULL) ? fFalse : (LogGdiHandle(hbmMono, 1002), fFalse) ||) + (SelectObject( hMDCDst, hbmMono ) == NULL) ) + { + goto BmFailure; + } + LogGdiHandle(hMDCDst, 1039); + + /* Now blt the bitmap contents. The screen driver in the source will + "do the right thing" in copying color to black-and-white. */ + + BitBlt( hMDCDst, 0, 0, bm.bmWidth, bm.bmHeight, hMDCSrc, 0, 0, SRCCOPY ); + + UnlogGdiHandle(hMDCSrc, 1038); + DeleteDC( hMDCSrc ); + UnlogGdiHandle(hMDCDst, 1039); + DeleteDC( hMDCDst ); + return hbmMono; + +BmFailure: + + if (hMDCSrc != NULL) /* ORDER IS IMPORTANT: DC's before */ + { + UnlogGdiHandle(hMDCSrc, 1038); + DeleteDC( hMDCSrc ); /* objects selected into them */ + } + if (hMDCDst != NULL) + { + UnlogGdiHandle(hMDCDst, 1039); + DeleteDC( hMDCDst ); + } + if (hbmMono != NULL) + { + UnlogGdiHandle(hbmMono, 1002); + DeleteObject( hbmMono ); + } + return NULL; +} + + +/* C F N E X T C F */ +/* Enumerate the clipboard formats that we understand in the order + we like them. cfNil returned when done, pass in cfNil to get first. + + Doesn't deal with CF_LINK which we do understand, but won't normally + ask for. + + if fPrPic is fTrue, we will ask for the cfPrPic format (Excel specific). +*/ +/* %%Function: CfNextCf %%Owner: bobz */ + + +CfNextCf (cf, fPrPic) +int cf; +BOOL fPrPic; +{ + + /* Desired order (win3 word: Notice text before picture formats): + cfRTF + CF_TEXT + cfPRPic + CF_METAFILEPICT + CF_DIB + CF_BITMAP + */ + +#ifdef DEBUG + /* a slimy way to let us test clipboard stuff and let us use + slapWnd to put stuff into the clipboard. If nonzero, we take its + value to be the desired format. values are CF_ values + we set its values with multiple calls to SetTestClip + a debug function currently just the function set in + cmddebug7 + */ + { + extern int vTestClip; + if (vTestClip) + return (vTestClip); + } +#endif /* DEBUG */ + + switch (cf) + { + default: + if (cf == cfRTF) + return CF_TEXT; /* 2nd choice */ + Assert(cf == cfPrPic && fPrPic && cfPrPic != cfNil); + goto LMetafile; /* 4th or 5th choice */ + + case cfNil: + return cfRTF; /* 1st choice */ + case CF_TEXT: + if (fPrPic && cfPrPic != cfNil) + return cfPrPic; /* 4th choice (Excel specific) */ +LMetafile: + + return CF_METAFILEPICT; /* 4th or 5th choice */ + case CF_METAFILEPICT: + return CF_DIB; /* 5th or 6th choice */ + case CF_DIB: + return CF_BITMAP; /* 6th or 7th choice */ + case CF_BITMAP: + return cfNil; + } + + Assert (fFalse); +} + + +/* F C A N W R I T E C F */ +/* Return true iff it is possible to represent doc, [cpFirst:cpLim] + in format cf. +*/ +/* %%Function: FCanWriteCf %%Owner: bobz */ + + +FCanWriteCf (cf, doc, cpFirst, cpLim, fRestrictRTF) +int cf, doc; +CP cpFirst, cpLim; + // if true, (currently only at quit), do not generate rtf if a picture + // or if unformatted text, since it would be redundant +BOOL fRestrictRTF; +{ + struct CA caT; + CP cpImport; + int mm; + + switch (cf) + { + case CF_TEXT: + /* reject text for either a normal pic or an import field pic, + since it has no text result and would show nothing */ + if (!FCaIsGraphics(PcaSet(&caT, doc, cpFirst, cpLim), + fvcResults, &cpImport)) + return (cpLim > cpFirst); + else + return (fFalse); + + case CF_DIB: + /* we can supply this if the ca is a DIB in metafile */ + case CF_BITMAP: + /* We can supply this if the ca is a bitmap */ + case CF_METAFILEPICT: + /* We can supply this if the ca is a metafile */ + + /* FPicRenderable does a ChFetch. Treats metafile import fields as + a pic, not tiff. Does a FetchPe so that vpicFetch is set up. + */ + if (FPicRenderable(doc, cpFirst, cpLim, &mm)) + { + Assert (doc != docScrap || vsab.fPict); + // just a warning. Unrecognized formats safely ignored bz + Assert (mm == MM_BITMAP || mm < MM_META_MAX || mm == MM_DIB); + switch (cf) + { + case CF_DIB: + return FDIBInMetafile(); + case CF_BITMAP: + return (mm == MM_BITMAP || + (vwWinVersion >= 0x0300 && FDIBInMetafile())); + case CF_METAFILEPICT: + return (mm < MM_META_MAX); + default: // currently unrecognized format + return fFalse; + } + } + else + return (fFalse); + + case CF_OWNERDISPLAY: + /* Render rich text to another Opus instance */ + Assert(fFalse); + return (fFalse); + + default: + if (cf == cfRTF) + { + // if we have a picture or unformatted text, the RTF is redundant, so omit + if (fRestrictRTF && (!vsab.fFormatted || + FCaIsGraphics(PcaSet(&caT, doc, cpFirst, cpLim), + fvcResults, &cpImport))) + { + return (fFalse); + } + else + return (cpLim > cpFirst); + } + else if (cf == cfLink && doc == docScrap) + return (FCanLinkScrap ()); + else + return (fFalse); + } + + Assert (fFalse); // should never reach here +} + + +/* F A S S U R E H C B G L O B */ +/* %%Function: FAssureHCbGlob %%Owner: bobz */ + + +FAssureHCbGlob( ph, lcb, wAlloc, plcbMac, plcbMax ) +int ***ph; +LONG lcb; +int wAlloc; +LONG *plcbMac; +LONG *plcbMax; +{ + /* Inputs: *ph -- a handle + *plcbMax - amount of space currently allocated to handle + (0 iff *ph is NULL) + lcb -- amount of space desired in handle + wAlloc -- Global mem value. usually GMEM_DDE or + GMEM_MOVEABLE + Outputs: *ph -- if successful, a handle with at least cb bytes of + space else hNil + *plcbMac -- if successful, == lcb, else unchanged or 0 + *plcbMax -- amount of space allocated to handle on return + + Return: fTrue if we returned with at least cb bytes of space in the + handle; fFalse if we tried to grow/allocate it and failed. + + Based on FAssureHCb. Used by Clipboard handle routines. We try to + allocate bigger chunks - like 1K bytes; if that fails we try for + the requested size. If this is to be generalized, CBDESIRED can + be changed to be a parameter. + */ + +#define CBDESIRED (1024) + /* round alloc requests to multiples of 16 */ +#define CBTOPBOUND(cb) ((cb + 15) >> 4 << 4) + + HANDLE h; + long lcbT; + + /* easy case, already have enough space */ + + if (lcb <= *plcbMax) + { + *plcbMac = lcb; + return fTrue; + } + + if (*plcbMax > 0L) /* aleady been allocated. Try to grow */ + { +#ifdef BZTEST + CommSz(SzShared("FAssureHCbGlob realloc start: ")); +#endif /* BZTEST */ + + Assert( *ph != hNil ); + h = *ph; /* to save original handle */ + if ((*ph = OurGlobalReAlloc( *ph, + (LONG) (lcbT = CBTOPBOUND (lcb + CBDESIRED)), + wAlloc )) == NULL) + { /* Could not expand handle. Try minimum allocation */ + *ph = h; + if ((*ph = OurGlobalReAlloc( *ph, (LONG) (lcbT = CBTOPBOUND(lcb)), + wAlloc )) == NULL) + { /* Could not expand handle */ + *ph = h; /* So it can still be used */ + /* leave ph, mac and max unchanged */ + return fFalse; + } + } + +#ifdef BZTEST + CommSzLong(SzShared("FAssureHCbGlob realloc size: "), lcbT); +#endif /* BZTEST */ + + } + else + { + Assert( *ph == hNil ); + + if ((*ph = OurGlobalAlloc( wAlloc, + (LONG) (lcbT = CBTOPBOUND(lcb + CBDESIRED)) )) == hNil) + { /* Could not get desired amount. Try minimum allocation */ + if ((*ph = OurGlobalAlloc( wAlloc, + (LONG) (lcbT = CBTOPBOUND(lcb)))) == hNil) + { /* Could not get minimum */ + *plcbMac = *plcbMax = 0; + return fFalse; + } + } +#ifdef BZTEST + CommSzLong(SzShared("FAssureHCbGlob first alloc size: "), lcbT); +#endif /* BZTEST */ + + } + + *plcbMax = lcbT; + *plcbMac = lcb; + return fTrue; +} + + + +/*****************************/ +/* %%Function: FPicRenderable %%Owner: bobz */ + +/* returns TRUE is range represents a single picture + pmm is the picture type, from vpicfetch.mfp.mm, even + if FALSE is returned. It will be MM_NIL if the range is not a picture at all. + will return true for non-TIFF import fields. + "old format" import metafiles will be rejected here. + Note that FCaIsGraphics returns true for all imports, and + is the more general routine. This routine is used only by those + callers who want a renderable picture. + + vpicfetch will be set up if TRUE +*/ + +FPicRenderable(doc, cpFirst, cpLim, pmm) +int doc; +CP cpFirst, cpLim; +int *pmm; +{ + struct CA caT; + CP cpImport; + + PcaSet(&caT, doc, cpFirst, cpLim); + if (FCaIsGraphics(&caT, fvcResults, &cpImport)) + { + Assert(*vhpchFetch == chPicture && vchpFetch.fSpec); + Assert (cpImport == cpNil || cpImport == vcpFetch); + /* FetchPe will set vchpFetch.fnPic to fnFetch bz */ + FetchPe(&vchpFetch, doc, vcpFetch); + + *pmm = vpicFetch.mfp.mm; /* set up even if we reject */ + + if (vpicFetch.mfp.mm == MM_TIFF || + /* rejects old format import metafiles */ + (vpicFetch.mfp.mm < MM_META_MAX && !FEmptyRc(&vpicFetch.rcWinMF))) + { + return fFalse; + } + else + return fTrue; + + } + + *pmm = MM_NIL; /* set up even if we reject */ + return fFalse; + +} + + +/* %%Function: bltbxHuge %%Owner: bobz */ + + +bltbxHuge( lpchSrc, lpchDest, cbCopy, fSrcHuge) +LPCH lpchSrc; +LPCH lpchDest; +unsigned cbCopy; +BOOL fSrcHuge; // if true, lpchSrc is the huge data, else lpchDest +{ + /* blt from lpchSrc to lpchDest, splitting into 2 blts if cchCopy + would cross a 64k segment boundary. Assumes that only 1 of the + 2 pointers is a huge block that could cross 64k boundaries + */ + + unsigned cbRemain; + + LPCH lpchHuge = fSrcHuge? lpchSrc : lpchDest; + + // cbRemain will be the # of bytes left in current segment + if ((cbRemain = -LOWORD(lpchHuge)) < cbCopy) + { + if (cbRemain) // can skip if 0 + { +#ifdef BZ + CommSzLong(SzShared("Splitting blt: lpchHuge = "), lpchHuge); + CommSzNum(SzShared("Splitting blt: cbRemain = "), cbRemain); + CommSzNum(SzShared("Splitting blt: cbCopy = "), cbCopy); +#endif + bltbx(lpchSrc, lpchDest, cbRemain); + cbCopy -= cbRemain; + lpchSrc = LpchIncr(lpchSrc, cbRemain); + lpchDest = LpchIncr(lpchDest, cbRemain); + } + } + + bltbx(lpchSrc, lpchDest, cbCopy); + +} + + +VOID BuildMFRecordForDIB(pmfhdr, pmftag, lcbDIB, bmWidth, bmHeight) +struct MFHDRDIBMF *pmfhdr; /* destination of leading record */ +struct WINMRTAG *pmftag; /* destination of trailing record */ +unsigned long lcbDIB; /* bytes of DIB bits */ +int bmWidth; /* bitmap width */ +int bmHeight; /* bitmap height */ +/* + * BuildMFRecordForDIB - build some metafile records, a leading and + * a trailing record for the purpose of embedding DIB inside a metafile. + * The leading record is to be inserted before a DIB and the trailing + * record is inserted after the DIB. + * The leading record consists of : + * 1) a standard metafile header (METAHDR), + * 2) a window orgin and extent record (WMFWINOE), + * 3) a text / background color record (WMFCOLOR), + * 4) a stretchdibbitmap record (WMFSDIB). + * The trailing record is just a simple end metafile record. + * Return value : none + * Side effects : none + * Documentation: + */ +{ + + // Leading metafile record : + + // windows org and ext records + + pmfhdr->winoe.cwWinOrigin = pmfhdr->winoe.cwWinExtent = + /* cw for each rec: total cb /4 */ + (long)(sizeof(struct WMFWINOE) >> 2); + pmfhdr->winoe.kwdWinOrigin = META_SETWINDOWORG; + pmfhdr->winoe.xpWinOrigin = pmfhdr->winoe.ypWinOrigin = 0; + pmfhdr->winoe.kwdWinExtent = META_SETWINDOWEXT; + pmfhdr->winoe.xpWinExtent = bmWidth; + pmfhdr->winoe.ypWinExtent = bmHeight; + + // text and background color records + + pmfhdr->color.cwTColor = pmfhdr->color.cwBColor = + /* cw for each rec: total cb /4 */ + (long)(sizeof(struct WMFCOLOR) >> 2); + pmfhdr->color.kwdTColor = META_SETTEXTCOLOR; + pmfhdr->color.rgbTColor = vsci.rgbText; + pmfhdr->color.kwdBColor = META_SETBKCOLOR; + pmfhdr->color.rgbBColor = vsci.rgbBkgrnd; + + // StretchDIBits record + + pmfhdr->stretchdib.kwdSDIB = META_STRETCHDIB; + // stretchdibits size: lbcDIB + record overhead + pmfhdr->stretchdib.cwSDIB = (lcbDIB + cbWMSDIB + sizeof(WORD) - 1) / + sizeof(WORD); + pmfhdr->stretchdib.dwRop = SRCCOPY; + pmfhdr->stretchdib.wUsage = 0; // unused + pmfhdr->stretchdib.srcYExt = bmHeight; + pmfhdr->stretchdib.srcXExt = bmWidth; + pmfhdr->stretchdib.srcY = 0; + pmfhdr->stretchdib.srcX = 0; + pmfhdr->stretchdib.dstYExt = bmHeight; + pmfhdr->stretchdib.dstXExt = bmWidth; + pmfhdr->stretchdib.dstY = 0; + pmfhdr->stretchdib.dstX = 0; + + + // standard metafile header record + + pmfhdr->metahdr.mtType = 1; // disk metafile + pmfhdr->metahdr.mtHeaderSize = cwMETAHDR; + pmfhdr->metahdr.mtVersion = WINMETAVERSION; + // total size (words): the dib bits + mf overhead + pmfhdr->metahdr.mtSize = (lcbDIB + cbMFHDRDIBMF + cbWINMRTAG + + sizeof(WORD) - 1) / sizeof(WORD); + pmfhdr->metahdr.mtNoOObjects = 0; + pmfhdr->metahdr.mtNoParameters = 0; // unused + pmfhdr->metahdr.mtMaxRecord = pmfhdr->stretchdib.cwSDIB; + + // Trailing metafile record + + pmftag->rdSize = cwWINMRTAG; + pmftag->kwd = METAENDREC; + +} + + +BOOL FDIBInMetafile() +/* + * FDIBInMetafile - Check to see if a metafile contains just a DIB, + * Check by comparing keywords of metafile record that we put in + * when we embed a DIB into a metafile. + * + * Return value : True if a DIB is embedded in a metafile, otherwise, false + * Side effects : none + * Documentation: + */ +{ + long lcb = vpicFetch.lcb; + struct MFHDRDIBMF mfhdr; + + /* make sure we have the picture fetched */ + Assert(*vhpchFetch == chPicture && vchpFetch.fSpec); + Assert(vfcFetchPic == ((vchpFetch.fcPic & 0x00FFFFFF) + cbPIC)); + + if (vpicFetch.mfp.mm == MM_ANISOTROPIC && /* is a metafile */ + lcb > (long)(cbPIC + cbMFHDRDIBMF + cbWINMRTAG)) /* and at least big enough */ + { + /* vfcFetchPic points to the begining of the metafile */ + /* read the metafile leading record */ + FetchPeData(vfcFetchPic, (char HUGE *)&mfhdr, (long)cbMFHDRDIBMF); + + /* win 3 metafile? in case of randomness, check if all keywords + that we put in are there + */ + if (mfhdr.metahdr.mtVersion >= WINMETAVERSION && + mfhdr.winoe.kwdWinOrigin == META_SETWINDOWORG && + mfhdr.winoe.kwdWinExtent == META_SETWINDOWEXT && + mfhdr.color.kwdTColor == META_SETTEXTCOLOR && + mfhdr.color.kwdBColor == META_SETBKCOLOR && + mfhdr.stretchdib.kwdSDIB == META_STRETCHDIB) + { + /* last check: that DIB is the only thing embedded in this metafile */ + /* i.e. the only thing left after the DIB is a end metafile record */ + if (lcb - (cbPIC + cbMFHDRDIBMF + + ((mfhdr.stretchdib.cwSDIB - cwWMSDIB) * sizeof(WORD))) == cbWINMRTAG) + return fTrue; + } + } + + return fFalse; +} + diff --git a/src/Opus/CMD3.C b/src/Opus/CMD3.C new file mode 100644 index 0000000..0d5e63c --- /dev/null +++ b/src/Opus/CMD3.C @@ -0,0 +1,1211 @@ + +#include "word.h" +DEBUGASSERTSZ /* WIN - bogus macro for assert string */ +#include "debug.h" +#include "cmdtbl.h" +#include "disp.h" +#include "props.h" +#include "sel.h" +#include "ch.h" +#include "keys.h" +#include "prm.h" +#include "doc.h" +#include "cmd.h" +#include "profile.h" +#include "format.h" +#include "screen.h" +#include "heap.h" +#include "border.h" /* to get TCC */ +#include "rerr.h" +#include "print.h" +#define AUTOSAVE +#include "autosave.h" +#include "idd.h" +#include "sdmdefs.h" +#include "sdmver.h" +#include "sdm.h" +#include "sdmtmpl.h" +#include "sdmparse.h" +#include "iconbar.h" +#include "resource.h" +#include "error.h" +#include "pic.h" +#include "menu2.h" +#define RSBSONLY +#include "rsb.h" +#include "version.h" +#include "message.h" +#include "idle.h" +#define RULER +#define REPEAT +#include "ruler.h" +#include "rareflag.h" + +#include "apprun.hs" +#include "apprun.sdm" + +extern struct RF vrf; +extern ASD asd; +extern CHAR szApp[]; +extern BOOL fElActive; +extern struct SCI vsci; +extern struct WWD ** hwwdCur; +extern HMENU vhMenu; +extern int viMenu; +extern int wwMac; +extern struct WWD ** mpwwhwwd[]; +extern BOOL vfFileCacheDirty; +extern BOOL vfWndCacheDirty; +extern struct MWD ** hmwdCur; +extern HWND vhwndStatLine; +extern struct SAB vsab; +extern HWND vhwndApp; +extern HANDLE vhInstance; +extern struct AAB vaab; +extern BOOL vfExtendSel; +extern BOOL vfOvertypeMode; +extern CHAR HUGE *vhpchFetch; +extern struct RULSS vrulss; +extern RRF rrf; +extern HWND vhwndRibbon; +extern BOOL vfBlockSel; +extern struct SEL selCur; +extern KMP ** hkmpCur; +extern struct CHP vchpFetch; +extern int wwCur; +extern int mwCur; +extern struct PREF vpref; +extern struct STTB ** vhsttbWnd; +extern struct UAB vuab; +extern struct MWD **mpmwhmwd[]; +extern struct RC vrcUnZoom; +extern int mwMac; +extern int vmwClipboard; +extern struct TCC vtcc; +extern int vlm; +extern struct PIC vpicFetch; +extern struct BMI mpidrbbmi []; +extern struct MERR vmerr; +extern HWND vhwndPgvCtl; +extern struct MERR vmerr; +extern struct SEL selCur; +extern struct UAB vuab; +extern int vccpFetch; +extern CHAR HUGE *vhpchFetch; +extern struct CHP vchpFetch; +extern struct PAP vpapFetch; +extern struct CA caPara; +extern CP vcpFetch; +extern BOOL vfEndFetch; +extern IDF vidf; +extern struct STTB **vhsttbFont; +extern struct PRI vpri; + + +#define iAppMin 0 +#define iAppClipbrd 0 +#define iAppControl 1 +#define iAppMax 2 + + +#ifdef OPUS_X64 +csconst char csrgstApp [][13] = +{ + "\013CLIPBRD.EXE", + "\013CONTROL.EXE" +}; +#else +csconst char csrgstApp [] [] = +{ + StKey("CLIPBRD.EXE",ClipbrdFileDef), + StKey("CONTROL.EXE",CtrlFileDef) +}; +#endif + +#ifdef INTL +#ifdef OPUS_X64 +csconst char csrgstUSApp [][13] = +{ + "\013CLIPBRD.EXE", + "\013CONTROL.EXE" +}; +#else +csconst char csrgstUSApp [] [] = +{ + St("CLIPBRD.EXE"), + St("CONTROL.EXE") +}; +#endif +#endif /* INTL */ + + +/* These strings are the Module and Class names of the apps in csrgstApp */ +#define istAppInfoClipbrd 0 +#define istAppInfoControl 2 +#ifdef OPUS_X64 +csconst char csrgstAppInfo[][11] = +{ + "\007CLIPBRD", + "\011CLIPBOARD", + "\007CONTROL", + "\010CTLPANEL" +}; +#else +csconst char csrgstAppInfo[][] = +{ + St("CLIPBRD"), + St("CLIPBOARD"), + St("CONTROL"), + St("CTLPANEL") +}; +#endif + + +#define ichMaxApp 16 + +/* %%Function: CmdControlRun %%Owner: bradch */ + +CMD CmdControlRun(pcmb) +CMB * pcmb; +{ + if (FCmdFillCab()) + { + ((CABAPPRUN *) *pcmb->hcab)->iApp = 0; + } + + if (FCmdDialog()) + { + char dlt [sizeof(dltAppRun)]; + + BltDlt(dltAppRun, dlt); + + switch (TmcOurDoDlg(dlt, pcmb)) + { +#ifdef DEBUG + default: + Assert(fFalse); + return cmdError; +#endif + case tmcError: + return cmdNoMemory; + + case tmcCancel: + return cmdCancelled; + + case tmcOK: + break; + } + } + + if (FCmdAction()) + { + int iApp, cch; + char szApp [ichMaxApp]; + + iApp = ((CABAPPRUN *) *pcmb->hcab)->iApp; + + if ((uns) (iApp - iAppMin) >= (iAppMax - iAppMin)) + return cmdError; + + switch (iApp) + { + case iAppClipbrd: + if (FReactivateApp(istAppInfoClipbrd)) + return cmdOK; + break; + case iAppControl: + if (FReactivateApp(istAppInfoControl)) + return cmdOK; + break; + } + + bltbx(csrgstApp[iApp] + 1, (char FAR *) szApp, + cch = csrgstApp[iApp][0]); + szApp[cch] = '\0'; + + StartLongOp(); + /* adjusts memory and tries to run application */ + if (!FOurRunApp(szApp, SW_SHOWNORMAL, eidNoMemRunApp, fTrue)) + { +#ifdef INTL + bltbx(csrgstUSApp[iApp] + 1, (char FAR *) szApp, + cch = csrgstUSApp[iApp][0]); + szApp[cch] = '\0'; + if (!FOurRunApp(szApp, SW_SHOWNORMAL, eidNoMemRunApp, fTrue)) +#endif /* INTL */ + ErrorEid(eidCantRunApp, "CmdControlRun"); + } + EndLongOp(fFalse); + } + + return cmdOK; +} + + +/* %%Function: FReactivateApp %%Owner: bradch */ + +FReactivateApp(istAppInfo) +int istAppInfo; +{ + HWND hwnd; + int cch; + CHAR sz[ichMaxApp]; + + /* Load the module name */ + cch = csrgstAppInfo[istAppInfo][0]; + bltbx(csrgstAppInfo[istAppInfo]+1, (char FAR *) sz, cch); + sz[cch] = '\0'; + + if (GetModuleHandle((LPSTR)sz)) + { + /* Load the class name */ + cch = csrgstAppInfo[istAppInfo+1][0]; + bltbx(csrgstAppInfo[istAppInfo+1]+1, (char FAR *) sz, cch); + sz[cch] = '\0'; + if ((hwnd = FindWindow((LPSTR)sz, NULL)) != NULL) + { + if (FActivateWindow(hwnd)) + { + if (IsIconic(hwnd)) + OpenIcon(hwnd); + return fTrue; + } + } + } + return fFalse; +} + + + +/* C M D E D I T P I C */ +/* Launch the DRAW application with the selected picture in the clipboard. + when focus returns to Opus, paste the picture from the clipboard. +*/ +/* %%Function: CmdEditPic %%Owner: bobz */ + +CMD CmdEditPic(pcmb) +CMB *pcmb; +{ + CHAR rgchCmdLine[cchMaxSz]; + CHAR szDrawApp[64]; + CHAR szDrawAppDef[64]; + int rgw[2]; + int mm; + +/* place graphic in clipboard */ + /* make sure current selection is a graphic selection */ + /* metafile import field will be treated as a pic, not TIFF field */ + if (!FPicRenderable(selCur.doc, selCur.cpFirst, selCur.cpLim, &mm)) + { + Beep(); + return cmdError; + } + + Assert(selCur.fGraphics); + + CmdCopy1(&selCur, &selCur.ca); + + GetSzProfileIpst(ipstDrawName, szDrawApp, szDrawAppDef, 64, fFalse); + rgw[0] = szDrawApp; + rgw[1] = szApp; + BuildStMstRgw(mstLaunchDraw, rgw, rgchCmdLine, cchMaxSz, hNil); + StToSzInPlace(rgchCmdLine); + + vrf.fWaitForDraw = fTrue; + +/* launch DRAW application */ + if (FOurRunApp(rgchCmdLine, SW_SHOWNORMAL, eidNoMemRunApp, fTrue)) + return cmdOK; + + else + { + vrf.fWaitForDraw = fFalse; + return cmdError; + } +} + + +/* D O E D I T P I C 2 */ +/* %%Function: DoEditPic2 %%Owner: bobz */ + +DoEditPic2() +{ + HWND hwnd; + HANDLE h; + CP cpPic; + CHAR szClassOwner[64]; + CHAR szClassDraw[64]; + CHAR szClassDrawDef[64]; + struct CA ca1, ca2; + struct PIC pic; + int mm; + + vrf.fWaitForDraw = fFalse; + + GetSzProfileIpst(ipstDrawClass, szClassDraw, szClassDrawDef, 64, fFalse); + + if ((hwnd = GetClipboardOwner()) == vhwndApp + || (!IsClipboardFormatAvailable(CF_METAFILEPICT) && + !IsClipboardFormatAvailable(CF_BITMAP))) + return; + + /* TIFF import field will be rejected, even though it should never get this far */ + /* for a metafile import field, we will only replace the single + chPic character. + */ + + if (!FPicRenderable(selCur.doc, selCur.cpFirst, selCur.cpLim, &mm)) + return; + +/* get old formatting for merge FPicRenderable did a fetchpe, and + set up vcpFetch as the chPic character, even for an import + field */ + + Assert(*vhpchFetch == chPicture && vchpFetch.fSpec); + pic = vpicFetch; /* old pic formatting */ + cpPic = vcpFetch; /* cp of chPic char */ + + if (hwnd != NULL) + GetClassName(hwnd, (LPSTR)szClassOwner, 255); + +#ifdef DEDITPIC + CommSzNum(SzShared("hwnd owner = "), hwnd); + CommSzSz(SzShared("owner class = "), szClassOwner); + CommSzSz(SzShared("looking for class = "), szClassDraw); +#endif /* DEDITPIC */ + + if ((hwnd != NULL && *szClassDraw && FNeNcSz(szClassOwner, szClassDraw)) + || !FReadExtScrap() || !vsab.fPict || + CpMacDoc(docScrap) != 1+ccpEop) + return; + +/* set up undo and kill the existing selection */ + if (!FSetUndoBefore(bcmPaste, uccPaste)) + return; + TurnOffSel(&selCur); + +/* copy the new picture in */ + if (!FReplaceCps(PcaSetDcp(&ca1, selCur.doc, cpPic, (CP)1), + PcaSetDcp(&ca2, docScrap, cp0, (CP)1))) + return; + +/* check table/dead field properties */ + AssureNestedPropsCorrect(PcaSetDcp(&ca1, selCur.doc, cpPic, (CP)1), fTrue); + +/* select the new picture */ + Select(&selCur, cpPic, cpPic+1); + +/* merge in old pictures formatting */ + MergePicProps(selCur.doc, cpPic, &pic); + +/* assure document props correct */ + PdodDoc(selCur.doc)->fFormatted = fTrue; + PdodDoc(selCur.doc)->fMayHavePic = fTrue; + +/* set up undo */ + SetUndoAfter(&ca1); +} + + +#define cchBuffer 256 + +/* %%Function: CmdSwapCase %%Owner: bradch */ + +CMD CmdSwapCase(pcmb) +CMB *pcmb; +{ + int doc, wcs; + CP cpSelFirst, cpSelLim; + int fArmUndo = fFalse; + struct CA caT; + extern BYTE vfNoInvalField; + + if (selCur.fIns) + { + Select(&selCur, CpFirstSty(wwCur, selCur.doc, selCur.cpFirst, + styWord, fFalse), CpLimSty(wwCur, selCur.doc, selCur.cpFirst, + styWord, fFalse)); + } + + if (selCur.sk != skSel) + { + Beep (); + return cmdError; + } + + doc = selCur.doc; + cpSelFirst = selCur.cpFirst; + cpSelLim = selCur.cpLim; + CachePara(doc, cpSelFirst); + + TurnOffSel(&selCur); /* to avoid horrible flashing */ + + /* Set up undo if we haven't yet */ + if (vuab.bcm != bcmChangeCase || + FNeRgch(&selCur.ca, &vuab.selsBefore.ca, + sizeof (struct CA))) + { + if (!FSetUndoBefore(bcmChangeCase, uccFormat)) + return cmdCancelled; + fArmUndo = fTrue; + } + + /* figure out which state we should put the selection in */ + wcs = WcsCa(&selCur.ca); + + vfNoInvalField = fTrue; + /* perform the mapping */ + MapCaseDocCps (wcs, doc, cpSelFirst, cpSelLim); + vfNoInvalField = fFalse; + + /* all done, so reset selection */ + Select(&selCur, cpSelFirst, cpSelLim); + + if (fArmUndo) + SetUndoAfter(NULL); + + return cmdOK; +} + + +/* %%Function: ElWChangeCase %%Owner: bradch */ + +EL int ElWChangeCase(wcs) +int wcs; +{ + int doc; + CP cpSelFirst, cpSelLim; + int fArmUndo = fFalse; + struct CA caT; + extern int vcElParams; + extern int vfElFunc; + + if (selCur.fIns) + { + Select(&selCur, CpFirstSty(wwCur, selCur.doc, selCur.cpFirst, + styWord, fFalse), CpLimSty(wwCur, selCur.doc, selCur.cpFirst, + styWord, fFalse)); + } + + doc = selCur.doc; + cpSelFirst = selCur.cpFirst; + cpSelLim = selCur.cpLim; + CachePara(doc, cpSelFirst); + + if (selCur.sk != skSel) + { + Beep (); + return cmdError; + } + + if (vfElFunc) + { + /* Called as a function */ + wcs = WcsCa(&selCur.ca); /* This is the next case state */ + wcs--; /* We want the original case state */ + if (wcs < 0) + wcs = 2; + } + else + { /* deal with range */ + if (wcs < 0 || wcs > 2) + { + RtError(rerrBadParam); + /* NOT REACHED */ + Assert(fFalse); + } + else + { + TurnOffSel(&selCur); /* to avoid horrible flashing */ + + /* Set up undo if we haven't yet */ + if (vuab.bcm != bcmChangeCase || + FNeRgch(&selCur.ca, &vuab.selsBefore.ca, + sizeof (struct CA))) + { + if (!FSetUndoBefore(bcmChangeCase, uccFormat)) + return cmdCancelled; + fArmUndo = fTrue; + } + if (vcElParams == 0) + { + /* Called to toggle to next case state */ + wcs = WcsCa(&selCur.ca); + } + + /* perform the mapping */ + MapCaseDocCps (wcs, doc, cpSelFirst, cpSelLim); + } + } + + /* all done, so reset selection */ + Select(&selCur, cpSelFirst, cpSelLim); + + if (fArmUndo) + SetUndoAfter(NULL); + + return wcs; +} + + + +/* M A P C A S E D O C C P S */ +/* Map the case of the text in doc, cp:cpLim to wcs. +*/ +/* %%Function: MapCaseDocCps %%Owner: bradch */ + +MapCaseDocCps (wcs, doc, cp, cpLim) +int wcs, doc; +CP cp, cpLim; + +{ + int cch, ich; + CHAR ch; + BOOL fFirstDone = fFalse; + BOOL fWordBegin = fTrue; + BOOL fToUpper; + struct CA caT; + CHAR rgch [cchBuffer]; + + Assert (cpLim <= CpMacDoc (doc)); + + while (cp < cpLim && !vmerr.fMemFail && !vmerr.fDiskFail) + { + CachePara (doc, cp); + if (cp >= caPara.cpLim-ccpEop) + { + cp = caPara.cpLim; + fWordBegin = fTrue; + continue; + } + FetchCp (doc, cp, fcmProps+fcmChars); + + /* in toggling case, don't fool with the EOP marks or the + fSpec characters. Deleteing them may have bad results!! */ + if (vchpFetch.fSpec) + { + cp += vccpFetch; + fWordBegin = fTrue; + continue; + } + + cch = min (cchBuffer, vccpFetch); + if (cp + cch > caPara.cpLim-ccpEop) + cch = caPara.cpLim-ccpEop-cp; + if (cp + cch > cpLim) + cch = cpLim-cp; + Assert (cch > 0); + + bltbh(vhpchFetch, rgch, cch); + for (ich = 0; ich < cch; ich++) + { + if (WbFromCh(ch = rgch[ich]) != wbText) + { + fWordBegin = fTrue; + continue; + } + + fToUpper = (wcs == wcsAllUpper) || + (wcs == wcsCapWords && fWordBegin) || + (wcs == wcsFirstCap && fWordBegin && !fFirstDone); + + rgch[ich] = fToUpper ? + ChUpper(ch) : ChLower(ch); + + fWordBegin = fFalse; + fFirstDone = fTrue; + } + + if (FInsertRgch(doc, cp, rgch, cch, &vchpFetch, NULL)) + if (!FDelete(PcaSetDcp(&caT, doc, cp+cch, cch))) + /* failed - remove what we inserted */ + FDelete(PcaSetDcp(&caT, doc, cp, cch)); + + cp += cch; + } +} + + + + + +/* W C S C A */ +/* Given a CA, try to determine the current "Case State." This is done by +scanning for the first two consecutive alphabetic characters. If the first +character is lower case, it is assumed that all characters are lower case. +Otherwise, if the second character is upper case, it is assumed that all +characters are upper case. If the first letter is upper case and the second +is lower case, it is assumed that words are capitalized. + +NOTE: if there are no alphabetic characters in the first cchBuffer (256) +characters of the selection, nothing will happen!. +*/ + +/* %%Function: WcsCa %%Owner: bradch */ + +int WcsCa(pca) +struct CA * pca; +{ + int wCaseState; + int cch, ich; + char rgch[cchBuffer]; + + FetchRgch(&cch, &rgch[0], pca->doc, pca->cpFirst, pca->cpLim, + cchBuffer); + + wCaseState = -1; + for (ich = 0; ich < cch; ++ich) + { + if (FAlpha(rgch[ich])) + { + /* take care of case where there are not two + consecutive alpha chars */ + if (wCaseState < 0) + wCaseState = FLower(rgch[ich]) ? + wcsAllUpper : wcsAllLower; + + /* take care of other cases */ + if (cch > 1 && FAlpha(rgch[ich + 1])) + { + if (FLower(rgch[ich])) + wCaseState = wcsAllUpper; + else if (FLower(rgch[ich + 1])) + wCaseState = wcsAllLower; + else + wCaseState = wcsCapWords; + break; + } + } + } + + return wCaseState; +} + + +/* %%Function: CmdGrowFont %%Owner: bryanl */ + +CMD CmdGrowFont(pcmb) +CMB *pcmb; +{ + return CmdBumpFontSize(fTrue); +} + + +/* %%Function: CmdShrinkFont %%Owner: bryanl */ + +CMD CmdShrinkFont(pcmb) +CMB *pcmb; +{ + return CmdBumpFontSize(fFalse); +} + + +/* C m d B u m p F o n t S i z e */ +/* not a real cmd func, just called by above. */ +/* increase/decrease size of fonts in selection to next available size + on the printer */ + +/* %%Function: CmdBumpFontSize %%Owner: bryanl */ + +CmdBumpFontSize(fGrow) +int fGrow; +{ + char prl [2]; + int fArmUndo = fFalse; + struct CA ca; + +/* If we have never gotten a printer DC, this is the time to do it */ + if (vpri.hsttbPaf == hNil) + SetFlm(flmRepaginate); + if (vpri.hsttbPaf == hNil) + goto LNoAction; /* no printer attached */ + + prl [0] = sprmCHps; + if (selCur.fIns) + { + prl [1] = HpsBump( selCur.doc, selCur.chp.ftc, selCur.chp.hps, fGrow); + ApplyGrpprlSelCur( prl, 2, fTrue /*fSetUndo*/ ); + return cmdOK; + } + + if (!FSetUndoBefore(bcmFormatting, uccFormat)) + return cmdCancelled; + + PcaPoint( &ca, selCur.doc, selCur.cpFirst ); + + for ( ; ca.cpFirst < selCur.cpLim ; ca.cpFirst = ca.cpLim ) + { + FetchCpAndParaCa( &ca, fcmProps ); + ca.cpLim = CpMin( vcpFetch + vccpFetch, selCur.cpLim ); + prl [1] = HpsBump( selCur.doc, vchpFetch.ftc, vchpFetch.hps, fGrow ); + + if (prl [1] != vchpFetch.hps) + { + ApplyGrpprlInvalCa( prl, 2, &ca ); + fArmUndo = fTrue; + } + } + if (fArmUndo) + SetUndoAfter(NULL); + else + { +LNoAction: + Beep(); + return cmdError; + } + + return cmdOK; +} + + + +/* H p s B u m p */ +/* return next largest or smallest size for printer font. If + not available (font not found or already largest/smallest), return + existing size. + + Uses vpri.hsttbPaf, the list of sizes obtained by printer enumeration +*/ + +/* %%Function: HpsBump %%Owner: bryanl */ + +HpsBump( doc, ftc, hps, fGrow ) +int doc, ftc, hps, fGrow; +{ + int ibstFont; + int ibpaf; + struct PAF *ppaf; + char *phpsMin, *phpsMac; + int ihps; + + Assert( hps <= 255 ); + + if ((ibstFont = IbstFontFromFtcDoc( ftc, doc )) == iNil) + goto LNotFound; + + Assert( ibstFont < (*vhsttbFont)->ibstMac ); + Assert( vpri.hsttbPaf != hNil ); + + for ( ibpaf = 0 ; ibpaf < (*vpri.hsttbPaf)->ibstMac ; ibpaf++ ) + { + if (ibstFont == (ppaf = ((struct PAF *) PstFromSttb(vpri.hsttbPaf, ibpaf)))->ibst) + { + phpsMac = (phpsMin = &ppaf->rghps [0]) + IhpsMacPpaf(ppaf); + + if (fGrow) + { + for ( ; phpsMin < phpsMac ; phpsMin++ ) + if (hps < *phpsMin) + return *phpsMin; + } + else + { + while ( phpsMac-- > phpsMin ) + if (hps > *phpsMac) + return *phpsMac; + } + break; + } + } + +LNotFound: + return hps; +} + + +BYTE vfNoInvalField = fFalse; + +/* A p p l y G r p p r l I n v a l C a */ +/* Like ApplyGrpprlCa, but includes inval stuff from + ApplyGrpprlSelCur. This might be a useful routine in + other cases. Currently it uses ApplyGrpprlCa, not the + Ninch version, so the toggle props are not handled correctly for + the majority sprm. */ + +/* %%Function: ApplyGrpprlInvalCa %%Owner: davidlu */ + +ApplyGrpprlInvalCa( grpprl, cb, pca ) +char *grpprl; +int cb; +struct CA *pca; +{ + extern struct RULSS vrulss; + struct CA ca; + + ca = *pca; + +/* flush any pending sprms in ruler sprm cache */ + if (vrulss.caRulerSprm.doc != docNil && grpprl[0] != sprmPRuler) + FlushRulerSprms(); + + PdodDoc(ca.doc)->fOutlineDirty = fTrue; + + InvalCp(&ca); + +/* HACK! */ +/* in order for this hack to work, we need to guarantee that the applied + grpprl can never contain sprmCVanish, sprmCFldVanish or sprmPStc */ + Debug(GrpprlOKForFld(grpprl, cb)); + Assert(!vfNoInvalField); + vfNoInvalField = fTrue; + +/* dirty any enclosing field result */ + InvalText (&ca, fFalse /* fEdit */); + + vfNoInvalField = fFalse; + + ApplyGrpprlCa( grpprl, cb, &ca ); +} + + +/* %%Function: GrpprlOKForFld %%Owner: peterj */ + +#ifdef DEBUG +GrpprlOKForFld(pgrpprl, cb) +char *pgrpprl; +int cb; +{ + int cch; + while (cb) + { + switch (*pgrpprl) + { + case sprmCFVanish: + case sprmCFFldVanish: + case sprmPStc: + Assert(fFalse); + } + cch = CchPrl(pgrpprl); + pgrpprl += cch; + cb -= cch; + } +} + + +#endif /* DEBUG */ + + +/* +* msrun.c -- Exec stuff swiped from Win Excel, 4/87 dsb +*/ + +#define CchSzNotBogus(sz) (CchSz(sz) - 1) + +extern CHAR szEmpty[]; +extern CHAR stEmpty[]; + +/* F O U R R U N A P P */ +/* Run Application. pchRun is a file followed by the arguments to the + command. sw is the Show Window code indicating how to bring the + other app up. Returns TRUE if the call succeeded. +*/ +/* %%Function: FOurRunApp %%Owner: peterj */ + +FOurRunApp (pchRun, sw, eid, fSingleAppOk) +CHAR *pchRun; +int sw; +int eid; +BOOL fSingleAppOk; + +{ + int w; + extern BOOL vfSingleApp; + + if (!fSingleAppOk && vfSingleApp) + { + ErrorEid(eidRuntimeWindows, " FOurRunApp"); + return fFalse; + } + + /* reduce the amount of memory we use */ + ShrinkSwapArea(); + + if ((w = RunApp (pchRun, sw)) == 8) + /* out of memory */ + /* other errors are reported already (or caller's responsibility) */ + ErrorNoMemory(eid); + + /* restore our swap area */ + GrowSwapArea(); + + /* DOS error codes are always less than 32 */ + return w >= 32; +} + + +/**** RunApp - run command procedure. + This proc tries to execute (or load) the given string accordingly + to the given iEvent. (can be any SW_ code) + Returns a DOS application handle ( < 32 indicates error). +*/ +/* %%Function: RunApp %%Owner: peterj */ + +int RunApp (pchRun, iEvent) +CHAR *pchRun; +int iEvent; + +{ + extern BOOL vfSingleApp; + CHAR *pch1, *pch2; /* 2 multi-usage string pointers */ + CHAR *pchCmdLine; /* ptr Command Line (Arguments) */ + int iDone; /* Dos return value */ + int cch; /* Character count */ + int fcb1buf[2]; /* ?????????????? */ + unsigned int iOkay; /* Dos return value when EXECuting */ + CHAR szExt[4]; /* File extension string */ + CHAR szFile[128]; /* Filename string */ + CHAR szBuf[128]; /* Buffer string for Dos Exec */ + CHAR szArgs[128]; /* Arguments string */ + CHAR *pchBuf; /* ptr into szBuf or rgchArgs */ + CHAR *pchArgs; /* ptr into rgchArgs or szBuf */ + struct LOADPARMS + { + WORD segEnv; /* Env. segment */ + LPSTR lpCmdLine; /* Arguments long ptr */ + LPSTR lpFCB1; /* FCBs long ptr */ + LPSTR lpFCB2; + } loadparms; /* Load parameters struct used by Dos */ + + /* Get rid of leading blanks */ + while (*pchRun == ' ') + pchRun++; + + /* Get arguments string. */ + pchCmdLine = PchParseNextFile(pchRun); + + /* Check FileName and fill szFile if OK. */ + if (!FCheckRunFile (szFile, pchRun)) + return(0); + + /* If szFile is our help app, we want to run it directly, ignoring any + extension fields in WIN.INI. First, we find the app name by + traversing the string backwards from the end until we find a + colon or backslash. Then we compare the string to "WINWORD.HLP", + and skip the WIN.INI extension field check if they match. */ + pch1 = szFile + CchSzNotBogus(szFile); + while (pch1 >= szFile && *pch1 != '\\' && *pch1 != ':') + pch1--; + if (!FNeNcSz(++pch1, SzSharedKey("WINWORD.HLP",HelpFileDef))) + { + szBuf[0] = '\0'; + goto Lwinhelp; + } + + /* Go Backward into the string until '.' and get extension. + Remember CheckFileRun() adds extension and '.' is not a valid + Kanji 2nd byte. + */ + pch1 = szFile + CchSzNotBogus(szFile); + while (*pch1 != '.') + pch1--; + CchCopySz(++pch1, szExt); + + /* If extension field exists in WIN.INI replace current filename + by new filename and if Skill character is found in the field + add also the the previous filename: + TEXT.DOC + doc=write.exe ^.doc ==> WRITE.EXE TEXT.DOC + We also exchange ptrs on filename and arguments. + */ + if (GetProfileString((LPSTR)SzSharedKey("extensions",Extensions), + (LPSTR)szExt, (LPSTR)szEmpty, (LPSTR)szBuf, 128)) + { + pch1 = szArgs; + CchCopySz(szBuf, pch1); + /* '.' is not a valid Kanji 2nd byte but SKILLCHAR is, so...*/ + while (*pch1 && *pch1 != chSkill) + pch1 = (CHAR *)LOWORD((long)AnsiNext((LPSTR)pch1)); + if (*pch1 == chSkill) + { + CchCopySz(szFile, pch1); + while (*pch1) + pch1++; + while (*pch1 != '.') + pch1--; + pch2 = szBuf + CchSzNotBogus(szBuf); + while (pch2 != szBuf && *pch2 != '.' && *pch2 != chSkill) + pch2 = (CHAR *)LOWORD((long)AnsiPrev((LPSTR)szBuf, (LPSTR)pch2)); + if (*pch2 == '.') + CchCopySz(++pch2, ++pch1); + } + pchBuf = szArgs; /* Here takes place the ptrs Xchange */ + pchArgs = szBuf; + } + + /* Otherwise run the file itself (if valid) */ + else + { +Lwinhelp: + pchBuf = szBuf; /* Just create plain ptrs */ + pchArgs = szArgs; + CchCopySz(szFile, szBuf); + } + + /* From now we can't use direct ptr to szBuf or szArgs because they + can be xchanged, so use only the created ptrs: pchBuf and pchArgs. + At this moment pchArgs points into a buffer whose content is not + yet defined. + */ + SzSzAppend(pchBuf, SzShared(" ")); + cch = CchSzNotBogus(pchBuf); + if (CchSzNotBogus(pchCmdLine) + cch > 127) + *(pchCmdLine + 127 - cch) = 0; + + /* Concatenate everything */ + SzSzAppend(pchBuf, pchCmdLine); + + /* Go after the filename and skip blanks (Kanji OK) */ + for (pch1 = pchBuf; *pch1 && *pch1 != '/' && *pch1 != ' '; ++pch1); + pch2 = pch1; + while (*pch1 == ' ') + pch1++; + + /* Build a length in front carriage return terminated string + for Arguments (Dos needs this way). */ + AnsiToOem((LPSTR)pch1, (LPSTR)pch1); + *pchArgs = CchSzNotBogus(pch1); + CchCopySz(pch1, pchArgs+1); + *(pchArgs + 1 + *pchArgs) = chReturn; + + /* Fill LOADPARMS structure */ + fcb1buf[0] = 2; + fcb1buf[1] = iEvent; + loadparms.segEnv = 0; + loadparms.lpCmdLine = (LPSTR)pchArgs; + loadparms.lpFCB1 = (LPSTR)fcb1buf; + loadparms.lpFCB2 = (LPSTR)NULL; + + /* Zero terminate application name */ + *pch2 = 0; + + /* Go backward from filename until ':' or '\'. */ +/* FUTURE (pj): this loop seems totally useless since pch2 is never used... */ + while (*pch2 != ':' && *pch2 != '\\' && pch2 != pchBuf) + pch2 = (CHAR *)LOWORD((long)AnsiPrev((LPSTR)pchBuf, (LPSTR)pch2)); + if (*pch2 == '\\' || *pch2 == ':') + pch2++; + + QszUpper(pchBuf); + AnsiToOem((LPSTR)pchBuf, (LPSTR)pchBuf); + return(ShellExec(pchBuf, &loadparms)); +} + + +/**** FCheckRunFile - Check if filename is a decent file to Run. + pchSrc is an ANSI string and so pchDest should be. + This routine deals with Kanji chars. + + The filename it returns must contain a '.' +*/ +/* %%Function: FCheckRunFile %%Owner: peterj */ + +BOOL FCheckRunFile(pchDest, pchSrc) +CHAR *pchDest; +CHAR *pchSrc; + +{ + CHAR *pch; + int iter, cch; + CHAR szBuf[128]; + OFSTRUCT ofFile; + + /* Check if valid filename. */ + if (OpenFile ((LPSTR)pchSrc, (LPOFSTRUCT)&ofFile, OF_PARSE) == -1) + return FALSE; + + pch = pchSrc + CchSzNotBogus(pchSrc); + while (pch != pchSrc && *pch != '\\' && *pch != '.') + pch = (CHAR *)LOWORD((long)AnsiPrev((LPSTR)pchSrc, (LPSTR)pch)); + + /* Check if file exists as given */ + if (OpenFile ((LPSTR)pchSrc, (LPOFSTRUCT)&ofFile, OF_EXIST) != -1) + { + OemToAnsi((LPSTR)ofFile.szPathName, (LPSTR)pchDest); + /* Did the source filename have an extension? */ + if (*pch != '.') + { + /* No, did OpenFile stick one on for us? */ + pch = pchDest + CchSzNotBogus(pchDest); + if (*(pch-1) != '.') + { + /* No, well we better add one */ + *pch++ = '.'; + *pch = 0; + } + } + return(TRUE); + } + + /* We didn't find file so look for extension separator '.'. + If '.' is found it can't be an executable file (would have been + found by previous OpenFile(). But i.e. it can be an argument like + FOO.DOC and so asks for load WRITE.EXE. Therefore says it's OK. + */ + if (*pch != '.') + /* file must have an extension */ + { + ErrorEid(eidNoExtension, "FCheckRunFile"); + return (FALSE); + } + else if (!FIsRunFile(pchSrc)) + { + CchCopySz(pchSrc, pchDest); + return(TRUE); + } + else + /* file was not found, caller should report (?) */ + return(FALSE); +} + + +/**** PchParseNextFile - zero terminate the first file in the list of files + returns pointer to the next file in the list +*/ +/* %%Function: PchParseNextFile %%Owner: peterj */ + +PchParseNextFile(pchList) +CHAR *pchList; + +{ + CHAR *pchNext; + + while (*pchList && *pchList != ' ' && *pchList != ',') + ++pchList; + pchNext = pchList; + if (*pchList) + pchNext++; + *pchList = 0; + while (*pchNext == ' ' || *pchNext == ',') + ++pchNext; + return(pchNext); +} + + +/**** FIsRunFile - Make sure File has runnable extension like + EXE, COM, BAT or PIF. + pchName should points into an Ansi string (Kanji OK). +*/ +/* %%Function: FIsRunFile %%Owner: peterj */ + +BOOL FIsRunFile(pchName) +CHAR *pchName; + +{ + CHAR *pch; + int cch; + + pch = pchName; + QszUpper(pch); + pch = pch + CchSzNotBogus(pch); + while (*pch != '\\' && *pch != '.' && pch > pchName) + pch = (CHAR *)LOWORD((long)AnsiPrev((LPSTR)pchName, (LPSTR)pch)); + if (*pch++ == '.') + { + cch = max(3,CchSzNotBogus(pch)); + if ( !FNeRgch(pch, SzFrame("EXE"), cch) || + !FNeRgch(pch, SzFrame("COM"), cch) || + !FNeRgch(pch, SzFrame("PIF"), cch) || + !FNeRgch(pch, SzFrame("BAT"), cch)) + return(TRUE); + } + return(FALSE); +} diff --git a/src/Opus/CREATE2.C b/src/Opus/CREATE2.C new file mode 100644 index 0000000..0379b2f --- /dev/null +++ b/src/Opus/CREATE2.C @@ -0,0 +1,1100 @@ +/* C R E A T E 2 */ +/* Core functionality of creation code */ + +#define NOWINMESSAGES +#define NOVIRTUALKEYCODES +#define NONCMESSAGES +#define NOSYSMETRICS +#define NOMENUS +#define NOICON +#define NOKEYSTATE +#define NOSYSCOMMANDS +#define NORASTEROPS +#define NOSHOWWINDOW +#define NOSYSMETRICS +#define NOBRUSH +#define NOCLIPBOARD +#define NOCOLOR +#define NOCREATESTRUCT +#define NODRAWTEXT +#define NOHDC +#define NOMEMMGR +#define NOMINMAX +#define NOMSG +#define NOPEN +#define NOPOINT +#define NOREGION +#define NOSCROLL +#define NOSOUND +#define NOTEXTMETRIC +#define NOWH +#define NOWINOFFSETS +#define NOWNDCLASS +#define NOCOMM +#define NOKANJI +#define NOCTLMGR +#define NOFONT +#define NOMETAFILE +#define NOGDI + +#include "word.h" +DEBUGASSERTSZ /* WIN - bogus macro for assert string */ +#include "heap.h" +#include "doc.h" +#include "file.h" +#include "props.h" +#include "sel.h" +#include "prm.h" +#include "fkp.h" +#include "ch.h" +#include "ruler.h" +#include "debug.h" +#include "format.h" +#include "screen.h" +#include "wininfo.h" +#include "winddefs.h" +#include "menu2.h" +#include "keys.h" +#include "layout.h" +#include "cmdtbl.h" +#include "field.h" +#include "disp.h" +#include "inter.h" +#include "strtbl.h" +#include "doslib.h" +#include "ibdefs.h" +#include "outline.h" +#define FINDNEXT +#include "search.h" +#include "cmd.h" + + +#ifdef PROTOTYPE +#include "create2.cpt" +#endif /* PROTOTYPE */ + +#ifdef DEBUG +#ifdef PCJ +/* #define SHOWFLDS */ +/* #define DBGDOCOPEN */ +#endif /* PCJ */ +#endif /* DEBUG */ + +/* E X T E R N A L S */ +extern struct PREF vpref; +extern struct SCI vsci; +extern struct FTI vfti; +extern struct FLI vfli; +extern struct DOD **mpdochdod[]; +extern int docMac; +extern struct FCB **mpfnhfcb[]; +extern int fnMac; +extern int vdocTemp; +extern struct SELS rgselsInsert[]; +extern int vdocScratch; +extern struct MERR vmerr; +extern struct PRC **vhprc; +extern struct SEL selCur; +extern struct UAB vuab; +extern struct SAB vsab; +extern CHAR szEmpty[]; +extern CHAR stEmpty[]; +extern CHAR rgchEop[]; +extern struct RULSS vrulss; +extern int docGlobalDot; +extern int vdocFetch; +extern struct FLS vfls; +extern int wwMac; +extern struct WWD **mpwwhwwd[]; +extern struct MWD **hmwdCur; +extern int mwCur; +extern struct CA caPage; +extern struct CA caPara; +extern struct CA caSect; +extern int vdocPapLast; +extern int vdocHdrEdit; +extern struct STTB **HsttbPropeFromStsh(); +extern uns **HCopyHeapBlock(); +extern struct DBS vdbs; +extern FNI fni; +extern struct AAB vaab; + +extern MUD ** vhmudUser; +extern KMP ** hkmpCur; +extern KMP ** vhkmpUser; + +struct DTTM DttmCur(); +long DttmFromPdta(); + + + +/* D O C C R E A T E */ +/* Create a doc to place fn in. If fn is fnNil, create a plain (fDoc) + document. +*/ + +/* %%Function:DocCreate %%Owner:chic */ +int DocCreate(fn) +int fn; +{ /* Create a document. Caller responsible for reporting errors. */ + int doc; + + if (fn != fnNil) + { + StartLongOp(); + if ((doc = DocCreateFn (fn, fTrue, NULL, NULL, NULL)) == docCancel) + /* USER opted to cancel the operation */ + doc = docNil; + EndLongOp(fFalse); + } + else + doc = DocCloneDoc (docNew, dkDoc); + + return doc; + +} + + +/* %%Function:DocAlloc %%Owner:peterj */ +/* D O C A L L O C */ +/* Allocate a doc and initialize its dod. Doc will be of type dk. Pdod + is pointer to stack dod which will contain the value of *PdodDoc (doc). +*/ + +DocAlloc (dk, pdod) +int dk; +struct DOD *pdod; + +{ + int doc; + int cw; + +#ifdef DEBUG + switch (dk) + { + case dkDoc: + case dkDot: + case dkGlsy: + case dkMcr: + case dkHdr: + case dkFtn: + case dkAtn: + case dkSDoc: + case dkDispHdr: + break; + default: + Assert (fFalse); + } +#endif /* DEBUG */ + /* %%Function:SetBytes %%Owner:peterj */ + SetBytes (pdod, 0, cbDOD); + pdod->fFormatted = fTrue; + pdod->dk = dk; + pdod->lvl = lvlAll; + + if (!pdod->fShort) + { + cw = cwDOD; + pdod->dttmOpened = DttmCur(); + } + else + cw = cwDODShort; + + doc = IAllocCls (clsDOD, cw); + Assert (cbDODShort == sizeof (int) * cwDODShort); + Assert (cbDOD == sizeof (int) * cwDOD); + + if (doc != docNil) + blt (pdod, PdodDoc (doc), cw); + + Debug( vdbs.fCkHeap ? CkHeap() : 0 ); + return doc; + +} + + +/* %%Function:DocCreateSub %%Owner:peterj */ +/* D O C C R E A T E S U B */ +/* Create a doc of type dk which is linked to doc. Returns docNil + if cannot create. Sets up links in both directions. (Created document + is not necessarly fShort). +*/ + +DocCreateSub (docMother, dk) +int docMother, dk; + +{ + int doc; + struct DOD *pdodMother; + + if ((doc = DocCloneDoc (docNew, dk)) == docNil) + return docNil; + + /* set up links */ + + PdodDoc (doc)->doc = docMother; + pdodMother = PdodDoc (docMother); + Assert (!pdodMother->fShort); + PdodDoc(doc)->fLockForEdit = pdodMother->fLockForEdit; + switch (dk) + { + case dkHdr: + pdodMother->docHdr = doc; + pdodMother->fFormatted = fTrue; + break; + case dkFtn: + pdodMother->docFtn = doc; + pdodMother->fFormatted = fTrue; + break; + case dkGlsy: + Assert (pdodMother->fDot); + pdodMother->docGlsy = doc; + break; + case dkMcr: + Assert(pdodMother->fDot); + pdodMother->docMcr = doc; + break; + case dkAtn: + pdodMother->docAtn = doc; + PdodDoc(doc)->fLockForEdit = fFalse; /* regardless of mother */ + pdodMother->fFormatted = fTrue; + break; + default: + break; + } + + return (doc); +} + + +/* %%Function:DocCloneDoc %%Owner:peterj */ +/* D O C C L O N E D O C */ +/* Clone document docSrc, but make it a type dk document. Returns a doc + or docNil. Cloning from an fShort to !fShort is NOT handled! +*/ + +DocCloneDoc (docSrc, dk) +int docSrc, dk; + +{ + int docClone; + struct DOD **hdodSrc = mpdochdod [docSrc]; + struct DOD **hdodClone; + struct CA caT, caSrc; + + if ((docClone = DocCloneDocNoText (docSrc, dk, fFalse)) == docNil) + return docNil; + + hdodClone = mpdochdod [docClone]; + + if (!(*hdodClone)->fMother) + /* new doc is not a mother, must give it a mother for the moment + so that FReplaceCps doesn't get confused. (Caller responsible for + resetting doc.) */ + (*hdodClone)->doc = (*hdodSrc)->fMother ? docSrc : docNew; + + if (docSrc != docNew) /* docNew has no text */ + { + BOOL f; + /* Copy text of doc to be cloned into clone doc. Copies up to + CpMacDoc and FReplaceCps will automatically get properties of + final section. */ + + /* avoid useless Inval calls */ + DisableInval(); + f = FReplaceCps( PcaSet( &caT, docClone, cp0, CpMacDoc(docClone) ), + PcaSet( &caSrc, docSrc, cp0, CpMacDoc( docSrc ) ) ); + EnableInval(); + if (!f) + goto ErrRet; + } +#ifdef ENABLE /* docNew has no section properties. Enable if that changes */ + else + { + /* apply docNew's formatting to the new document. Note: only section + properties currently supported. */ + ApplyDocSep (docClone, docNew); + } +#endif /* ENABLE */ + + /* if both are DOT's, Clone Glsy and Mcr subdocs */ + if ((*hdodClone)->fDot && (*hdodSrc)->fDot) + { + if ((*hdodSrc)->docGlsy != docNil) + { + int docGlsy; + Assert ((*hdodClone)->dk != dkGlsy); + docGlsy = DocCloneDoc ((*hdodSrc)->docGlsy, dkGlsy); + if (((*hdodClone)->docGlsy = docGlsy) == docNil) + goto ErrRet; + PdodDoc (docGlsy)->doc = docClone; + } + + if ((*hdodSrc)->docMcr != docNil) + { + int docMcr; + int imcr, imcrMac; + struct PLC ** hplcmcrClone; + struct PLC ** hplcmcr; + uns bsy; + MCR mcr; + char stName [cchMaxSyName]; + + docMcr = DocCloneDoc((*hdodSrc)->docMcr, dkMcr); + if (((*hdodClone)->docMcr = docMcr) == docNil) + goto ErrRet; + PdodDoc(docMcr)->doc = docClone; + + + /* If we are cloning a mcr doc, copy all the + command table entries. */ + + hplcmcrClone = PdodDoc(docMcr)->hplcmcr; + Assert(hplcmcrClone != hNil); + + hplcmcr = PdodDoc((*hdodSrc)->docMcr)->hplcmcr; + Assert(hplcmcr != hNil); + + imcrMac = (*hplcmcrClone)->iMac - 1; + for (imcr = 0; imcr < imcrMac; imcr += 1) + { + GetPlc(hplcmcr, imcr, &mcr); + GetNameFromBsy(stName, mcr.bcm); + if ((bsy = BsyAddCmd1(stName, docClone, imcr)) == bsyNil) + { + (*hplcmcrClone)->iMac = imcr + 1; + goto ErrRet; + } + + mcr.bcm = bsy; + PutPlc(hplcmcrClone, imcr, &mcr); + } + } + } + + /* if both are glossaries, copy glsy structures */ + else if ((*hdodClone)->fGlsy && (*hdodSrc)->fGlsy) + { + /* plc copy must be AFTER FReplaceCps, hence not in FCloneDocStructs */ + (*hdodClone)->hplcglsy = + HCopyHeapBlock((*hdodSrc)->hplcglsy, strcPLC); + (*hdodClone)->hsttbGlsy = + HCopyHeapBlock((*hdodSrc)->hsttbGlsy, strcSTTB); + if (vmerr.fMemFail) + goto ErrRet; + } + + /* if both are Ftn,Hdr or Mcr or Atn, copy plc */ + else if ((*hdodSrc)->fShort && (*hdodSrc)->dk == (*hdodClone)->dk) + { + (*hdodClone)->hplcfnd = + HCopyHeapBlock((*hdodSrc)->hplcfnd, strcPLC); + if (vmerr.fMemFail) + goto ErrRet; + } + + /* cannot CkDoc a subdoc yet, must set up links and structures */ + Debug (vdbs.fCkDoc && ( (*hdodClone)->fDoc || (*hdodClone)->fDot ) + ? CkDoc (docClone) : 0); + + return docClone; + +ErrRet: + DisposeDoc (docClone); + return docNil; +} + + +/* %%Function:DocCloneDocNoText %%Owner:peterj */ +/* D O C C L O N E D O C N O T E X T */ +/* Clones all of doc to a new doc of type dk but does not copy + doc's text. If fExtraInfo then new doc will have same docType + (crefLock incremented) and some common summary info. +*/ + +DocCloneDocNoText (docSrc, dk, fExtraInfo) +int docSrc, dk; +BOOL fExtraInfo; + +{ + int docClone; + struct DOD dod; + struct STTB **hsttbSrc; + + /* allocate the new doc */ + if ((docClone = DocAlloc (dk, &dod)) == docNil) + return docNil; + + /* set up the piece table */ + if (!FInitPlcpcd (&dod, fnNil, NULL)) + goto LFailed1; + + Assert (!PdodDoc(docSrc)->fShort || dod.fShort); + + /* copy basic structures */ + if (!dod.fShort) + { + if (!FCloneDocStructs (&dod, docSrc)) + { +LFailed1: + DisposeDocPdod (docClone, &dod); + return docNil; + } + } + else + fExtraInfo = fFalse; + + /* copy new dod back out to the heap */ + blt (&dod, PdodDoc(docClone), dod.fShort ? cwDODShort : cwDOD); + + /* if have ftn separators, create docHdr, copy text, copy hplchdd */ + if (!dod.fShort && dod.dop.grpfIhdt != 0) + { + int docHdrSrc, docHdrClone; + int ihddFtnSepMac = 0; + int ihddMac; + int grpfIhdt; + struct CA caIns, caT; + struct PLC **hplchddClone; + struct PLC **hplchddSrc; + + docHdrSrc = PdodDoc(docSrc)->docHdr; + hplchddSrc = PdodDoc(docHdrSrc)->hplchdd; + Assert(docHdrSrc && hplchddSrc); + docHdrClone = DocCreateSub(docClone, dkHdr); + if (docHdrClone == docNil || + (hplchddClone = HplcCreateEdc(mpdochdod[docHdrClone], edcHdd)) == hNil) + goto LFailed; + grpfIhdt = dod.dop.grpfIhdt; + ihddMac = IMacPlc(hplchddSrc); + + for (; grpfIhdt != 0; grpfIhdt >>= 1) + if ((grpfIhdt & 1) && ++ihddFtnSepMac == ihddMac) + { + Assert(fFalse); + goto LFailed; + } + Assert(ihddFtnSepMac > 0); + CaFromIhddFirstLim(docHdrSrc, 0, ihddFtnSepMac, &caIns); + if (!FReplaceCps(PcaSet(&caT, docHdrClone, cp0, cp0), &caIns)) + goto LFailed; + PutCpPlc(hplchddClone, 0, CpPlc(hplchddClone, 0)+DcpCa(&caIns)); + if (!FOpenPlc(hplchddClone, 0, ihddFtnSepMac)) + goto LFailed; + CopyMultPlc(ihddFtnSepMac, hplchddSrc, 0, hplchddClone, 0, cp0, 0, 0); + } + + if (fExtraInfo && (hsttbSrc = PdodDoc (docSrc)->hsttbAssoc) != hNil) + { + int ibst, docDot; + struct STTB **hsttbClone = HsttbAssocEnsure (docClone); + if (hsttbClone == hNil) + { +LFailed: + DisposeDoc (docClone); /* also frees hsttbClone */ + return docNil; + } + /* warning: assumes order of ibst's */ + for (ibst = ibstAssocDot; ibst <= ibstAssocComments; ibst++) + { + CHAR st [cchMaxSz]; + GetStFromSttb(hsttbSrc, ibst, st); + FChangeStInSttb (hsttbClone, ibst, st); + if (vmerr.fMemFail) + goto LFailed; + } + + if (PdodDoc(docSrc)->fDoc && (docDot=PdodDoc(docSrc)->docDot)!=docNil) + { + PdodDoc (docClone)->docDot = docDot; + PdodDoc (docDot)->crefLock++; + } + } + + + return docClone; +} + + +/* %%Function:FCloneDocStructs %%Owner:peterj */ +/* F C L O N E D O C S T R U C T S */ +/* Copy the basic structures from docSrc to pdod. Clone only meaningful if + both source and clone are !fShort. Does not copy hsttbAssoc. + + allocation failure note: this routine assumes that its caller(s) + will free all the dod handles if we return fFalse, so we just bag out here + +*/ + +FCloneDocStructs (pdod, docSrc) +struct DOD *pdod; +int docSrc; + +{ + struct STTB **hsttb; + struct PLESTCP **hplestcp; + struct DOD * pdodSrc; + struct DOD dodSrc; + + blt (PdodDoc(docSrc), &dodSrc, cwDOD); + + Assert ( !pdod->fShort && !dodSrc.fShort ); + + /* new or unformatted files have no DOP, so perform an aDOPtion. */ + pdod->dop = dodSrc.dop; + if (PdodDoc(docSrc)->fDot) /* do not carry lock for annotation over */ + pdod->dop.fLockAtn = fFalse; + +#ifdef DEBUG + /* this is a test. Docs that can be saved will later have a non-zero + value put in. */ + pdod->dop.nRevision = 0; +#endif /* DEBUG */ + + /* create a section table */ + if (FNoHeap(HplcCreateEdc(&pdod, edcSed))) + goto ErrRet; + + /* copy fonts */ + if (FNoHeap ( pdod->hmpftcibstFont = + HCopyHeapBlock(dodSrc.hmpftcibstFont,strcPLAIN) )) + goto ErrRet; + pdod->ftcMac = dodSrc.ftcMac; + pdod->ftcMax = dodSrc.ftcMax; + + /* copy style sheet */ + pdod->stsh.cstcStd = dodSrc.stsh.cstcStd; + if (FNoHeap ( pdod->stsh.hsttbName = + HCopyHeapBlock(dodSrc.stsh.hsttbName,strcSTTB) )) + goto ErrRet; + if (FNoHeap ( pdod->stsh.hsttbChpx = + HCopyHeapBlock(dodSrc.stsh.hsttbChpx,strcSTTB) )) + goto ErrRet; + if (FNoHeap ( pdod->stsh.hsttbPapx = + HCopyHeapBlock(dodSrc.stsh.hsttbPapx,strcSTTB) )) + goto ErrRet; + if (FNoHeap ( pdod->stsh.hplestcp = + HCopyHeapBlock(dodSrc.stsh.hplestcp,strcPL) )) + goto ErrRet; + + if (FNoHeap ( pdod->hsttbChpe = HCopyHeapBlock(dodSrc.hsttbChpe,strcSTTB) )) + goto ErrRet; + if (FNoHeap ( pdod->hsttbPape = HCopyHeapBlock(dodSrc.hsttbPape,strcSTTB) )) + goto ErrRet; + + /* keymap and menu */ + if (pdod->fDot) + /* a DOT must have keymap and menu */ + if (dodSrc.fDot) + /* source is a dot, copy its keymap and menu */ + { + if (FNoHeap ( pdod->hkmpUser = + HCopyHeapBlock (dodSrc.hkmpUser, strcPLAIN) )) + goto ErrRet; + if (FNoHeap ( pdod->hmudUser = + HCopyHeapBlock (dodSrc.hmudUser, strcPLAIN) )) + goto ErrRet; + } + else + /* must create new keymap and menu since dest is a dot */ + { + if (FNoHeap ( pdod->hkmpUser = HkmpCreate(0, kmfPlain) )) + goto ErrRet; + (*pdod->hkmpUser)->hkmpNext = vhkmpUser; + if (FNoHeap ( pdod->hmudUser = HmudInit (0) )) + goto ErrRet; + } + + + return !vmerr.fMemFail; + +ErrRet: + return fFalse; +} + + +/* %%Function:DocCreateScratch %%Owner:peterj */ +/* D O C C R E A T E S C R A T C H */ +/* Creates vdocScratch if it hasn't already been created. For debugging + purposes checks and sets a flag indicating that vdocScratch is in use. + Note that it may fail, in which case it will return docNil. + + The Scratch document, vdocScratch, is a general purpose, long-dod + document that may be used by anyone as long as its not already in use + (condition assured under DEBUG only). Call ReleaseDocScratch() when + done. Will be thrown away at idle time (thus caller is not responsible + for emptying or disposing). + + Passing a doc will save style sheet merging. +*/ + +DocCreateScratch (doc) +int doc; + +{ + struct CA ca; + Assert (!fDocScratchInUse); + + if (vdocScratch != docNil || + (vdocScratch = DocCreate (fnNil)) != docNil) + { + Debug (fDocScratchInUse = fTrue); + if (doc != docNil) + { + struct DOD *pdod = PdodDoc (vdocScratch); + pdod->fMotherStsh = fTrue; + pdod->doc = doc; + } + SetWholeDoc (vdocScratch, PcaSetNil(&ca)); + } + + return vdocScratch; +} + + +/* %%Function:DocCreateTemp %%Owner:peterj */ +/*******************************/ +/* D o c C r e a t e T e m p */ +DocCreateTemp(doc) +int doc; +{ +/* create the temp document if it doesn't exist yet; in any case make it a + sub-creature of the specified doc. NOTE: this can fail! + User is responsible for assuring that what is stored in vdocTemp is small + or for deleting or disposing when done.*/ + Assert(doc != docNil); + doc = DocMother(doc); + if (vdocTemp == docNil) + vdocTemp = DocCreateSub (doc, dkSDoc); + else + PdodDoc(vdocTemp)->doc = doc; + return(vdocTemp); +} + + + +/* %%Function:FInitPlcpcd %%Owner:peterj */ +/* I N I T P L C P C D */ +/* create initial piece table. There are the following cases: + fn==fnNil: Eop piece, End + fHasFib: fcMin - fcMac piece, End +Unformatted: fcMin - fcMac piece, Eop piece, End + +where Eop piece has fnNil and fcSpecEop. +End piece has cpMin = cpMac of doc. +*/ +BOOL FInitPlcpcd(pdod, fn, ppnFib) +struct DOD *pdod; +int fn; +PN *ppnFib; + { /* Initialize the piece table for a doc, given its initial fn. If fn + has a fib, on return *ppnFib is pnNext of this fib. (Allows + sequential calls to FInitPlcpcd for compound files). */ + + CP cpMac; + struct PLC **hplcpcd; + struct PCD pcd; + struct FIB fib; + + if (FNoHeap(hplcpcd = HplcInit(cbPCD, 1, cpMax, fTrue /* ext rgFoo */))) + return fFalse; + + if (fn == fnNil) + { +/* place two special eops at end of document. one will be last para of doc and + the other will be the hidden section mark. Last is document sentinel*/ + BuildPcd(&pcd, fnInsert, (FC)fcSpecEop); + if (!FInsertInPlc(hplcpcd, 0, (CP) 0, &pcd)) + goto LFail; + cpMac = ccpEop; + if (!FInsertInPlc(hplcpcd, 1, ccpEop, &pcd) || + !FInsertInPlc(hplcpcd, 2, 2*ccpEop, &pcd)) + goto LFail; + cpMac += ccpEop * 2; + } + else + { +/* short docs are always allocated using fnNil */ + struct FCB *pfcb = *mpfnhfcb[fn]; + if (pfcb->fHasFib) + { +/* we don't add the special eops for Word files, because the caller will + later call InsertHiddenSectionMark. */ + Assert (ppnFib != NULL); + FetchFib(fn, &fib, *ppnFib); + BuildPcd(&pcd, fn, fib.fcMin); + if (!FInsertInPlc(hplcpcd, 0, (CP) 0, &pcd)) + goto LFail; + cpMac = fib.fcMac - fib.fcMin; + *ppnFib = fib.pnNext; + } + else + { + int ipcd = 0; + char rgch [cchEop]; + + cpMac = pfcb->cbMac; + BuildPcd(&pcd, fn, (FC)0); + if (cpMac > 0 && !FInsertInPlc(hplcpcd, ipcd++, + (CP) 0, &pcd)) + goto LFail; + BuildPcd(&pcd, fnInsert, (FC)fcSpecEop); +/* we do add the special eops for text files. */ + if (!FInsertInPlc(hplcpcd, ipcd++, cpMac, &pcd) || + !FInsertInPlc(hplcpcd, ipcd++, cpMac + ccpEop, &pcd)) + goto LFail; +/* if the text file ends with an eop, we won't have to add one of the special + eops. */ + if (cpMac - ccpEop > cp0) + { + SetFnPos(fn, cpMac - ccpEop); + ReadRgchFromFn(fn, rgch, (int) ccpEop); + } + if (cpMac < ccpEop || FNeRgch(rgch, rgchEop, (int) ccpEop)) + { + if (!FInsertInPlc(hplcpcd, ipcd++, + cpMac + 2*ccpEop, &pcd)) + goto LFail; + cpMac += ccpEop; + } +/* delay adjustment for first two extra eops till now so that the comparisons + above are simpler. */ + cpMac += 2*ccpEop; + } + } + PutCpPlc(hplcpcd, IMacPlc(hplcpcd), cpMac); + + pdod->cpMac = cpMac; + pdod->hplcpcd = hplcpcd; + Debug( vdbs.fCkHeap ? CkHeap() : 0 ); + return fTrue; + +LFail: + FreeHplc(hplcpcd); + return fFalse; + + +} /* end FInitPlcpcd */ + + +/* %%Function:BuildPcd %%Owner:peterj */ +/* B U I L D P C D */ +BuildPcd(ppcd, fn, fc) +struct PCD *ppcd; +int fn; +FC fc; +{ + SetBytes(ppcd,0,sizeof(struct PCD)); + ppcd->fn = fn; + ppcd->fc = fc; + Debug(ppcd->fNoParaLastValid = fFalse); + ppcd->fNoParaLast = fFalse; + ppcd->prm = prmNil; +#ifdef DEBUG + if (vdbs.fCkDoc) + Assert( FValidFn(fn) ); +#endif +} + + +/* %%Function:DisposeDoc %%Owner:peterj */ +/* D I S P O S E D O C */ +/* if the doc is not the scrap document and no windows are displaying + the document: + 1) reclaim all heap blocks referenced by doc + 2) deallocate the DOD for the doc + 3) invalidate caches and declare no undo allowed if undo refers + to this doc +*/ +DisposeDoc(doc) +int doc; +{ /* Wipe this doc, destroying any changes since last save */ + + int isels; + struct DOD *pdod, dod; + extern struct PL **vhplbmc; + + Assert(doc >= 0 && doc < docMac); + Assert(doc == docNil || mpdochdod[doc] != hNil); + +/* Return without destroying if crefLock != 0 or it is not a valid doc to + Dispose. */ + if (doc == docNil || mpdochdod[doc] == hNil || doc == docScrap + || FDocBusy(doc)) + return; + + if (vhplbmc != hNil) + InvalBmc(doc, cp0, CpMacDoc(doc)); + + pdod = PdodDoc(doc); + Assert (pdod->wwDisp == wwNil && pdod->crefLock == 0); + + if (pdod->fDot && pdod->docMcr != docNil) + RemoveDotMacros(doc); + + /* make sure the stsh for scrap is saved */ + if (vsab.docStsh == doc) + CheckScrapStsh(doc); + pdod = PdodDoc(doc); + +/* kill the cache for vpapStc if it points to the doc we're disposing of */ + if (doc == vdocPapLast) + vdocPapLast = docNil; + if (doc == vdocHdrEdit) + vdocHdrEdit = docNil; + /* Free all tables attached to dod */ + blt(pdod, &dod, pdod->fShort ? cwDODShort : cwDOD); + if (doc == vdocTemp) + vdocTemp = docNil; + else if (doc == vdocScratch) + vdocScratch = docNil; + DisposeDocPdod(doc, &dod ); + + Assert (vdocScratch == docNil || PdodDoc(vdocScratch)->doc + != doc || !fDocScratchInUse); + + vdocFetch = docNil; + InvalCaFierce(); + InvalFli(); + if (selCur.doc == doc) + selCur.doc = docNil; + if (vrulss.caRulerSprm.doc == doc) + vrulss.caRulerSprm.doc = docNil; + if (vsab.caCopy.doc == doc) + vsab.caCopy.doc = docNil; + if (vuab.ca.doc == doc || vuab.caMove.doc == doc) + { + SetUndoNil(); + +/* FUTURE : (cc) more appropriate place to set docNil to vuab is in SetUndoNil + but because we want minimum side effect, we do it here, see bug #3349 */ + vuab.ca.doc = docNil; + vuab.caMove.doc = docNil; + } + + if (fni.doc == doc) + fni.doc = docNil; + for (isels = 0; isels < iselsInsertMax; isels++) + if (rgselsInsert[isels].doc == doc) + rgselsInsert[isels].doc = docNil; + if ((vaab.doc == doc && vaab.bcm == bcmTyping) || + (vaab.caAgain.doc == doc && + (vaab.bcm == bcmMoveSp || vaab.bcm == bcmCopySp))) + InvalAgain(); +} + + +/* %%Function:DisposeDocPdod %%Owner:peterj */ +/* D I S P O S E D O C P D O D */ +/* Disposes a doc whose dod is pointed to by pdod. Frees heap space used, + disposes referenced documents, and frees the doc itself. +*/ + +DisposeDocPdod (doc, pdod) +int doc; +struct DOD *pdod; + +{ + if (!pdod->fShort) + { + /* recursively call DisposeDoc for all short doc, + has to do this before the mother doc is freed because + WwDisp from FDocBusy is trying to refer to pdodMother */ + DisposeDoc(pdod->docFtn); + DisposeDoc(pdod->docHdr); + DisposeDoc(pdod->docAtn); + if (pdod->fDot) + DisposeDoc(pdod->docMcr); + } + else if (pdod->dk == dkHdr && pdod->doc != docNil) + /* trash all display docs for header */ + FCleanUpHdr(doc, fTrue, fFalse); + + FreeCls(clsDOD, doc); + FreeHplc(pdod->hplcpcd); + FreeHplc(pdod->hplcfld); + FreeHplc(pdod->hplcfnd); /* hplchdd, hplcglsy, hplcmcr, hplcand, ... */ + FreeHplc(pdod->hplcpgd); + if (!pdod->fShort) + { + FreeHsttb(pdod->hsttbAssoc); + FreeHplc(pdod->hplcsed); + FreeHplc(pdod->hplcsea); + FreeHplc(pdod->hplcfrd); + FreeHplc(pdod->hplcpad); + FreeHplc(pdod->hplcatrd); + FreeHsttb(pdod->stsh.hsttbName); + FreeHsttb(pdod->stsh.hsttbChpx); + FreeHsttb(pdod->stsh.hsttbPapx); + FreeH(pdod->stsh.hplestcp); + FreeHsttb(pdod->hsttbChpe); + FreeHsttb(pdod->hsttbPape); + FreeHplc(pdod->hplcbkf); + FreeHplc(pdod->hplcbkl); + FreeHsttb(pdod->hsttbBkmk); + FreeH(pdod->hmpftcibstFont); + + + /* deal with docDot/hsttbGlsy/docGlsy union */ + if (pdod->fGlsy) + FreeHsttb(pdod->hsttbGlsy); + else if (pdod->fDot) + { + DisposeDoc (pdod->docGlsy); + if (hkmpCur == pdod->hkmpUser) + { + hkmpCur = (*pdod->hkmpUser)->hkmpNext; + } + FreeH(pdod->hkmpUser); + FreeH(pdod->hmudUser); + } + else if (pdod->fDoc && pdod->docDot) + { + PdodDoc(pdod->docDot)->crefLock--; + DisposeDoc (pdod->docDot); + } + } + + +} + + +/* %%Function:DocSubEnsure %%Owner:peterj */ +/* D O C S U B E N S U R E */ +/* ensures that footnote/annotation related appendages exist for doc and +returns docFtn/docAtn. +*/ +DocSubEnsure(doc, edcDrp) +int doc, edcDrp; +{ + struct DOD **hdodMom = mpdochdod[doc]; + struct DOD **hdodSub; + int docSub; + struct PLC **hplcRef; + struct DRP *pdrp; + int dk, cbRef, cbfoo; + + if (edcDrp == edcDrpFtn) + { + dk = dkFtn; + cbRef = cbFRD; + cbfoo = cbFND; + } + else + { + dk = dkAtn; + cbRef = cbATRD; + cbfoo = cbAND; + } + + Assert(!(*hdodMom)->fShort); + pdrp = ((int *)PdodDoc(doc)) + edcDrp; + hplcRef = pdrp->hplcRef; + if ((docSub = pdrp->doc) == docNil) + { +/* create docSub, empty with trailing Eop */ + if ((docSub = DocCreateSub(doc, dk)) == docNil) + return(docNil); + pdrp = ((int *)PdodDoc(doc)) + edcDrp; + pdrp->doc = docSub; + (*hdodMom)->fDirty = fTrue; + } + if (hplcRef == hNil) + { +/* create hplcRef (ftn/atn reference table) for doc */ + if ((hplcRef = + HplcInit(cbRef, 0, CpMac2Doc(doc), fTrue /* ext rgFoo */)) == hNil) + goto LRetFail; + pdrp = ((int *)PdodDoc(doc)) + edcDrp; + pdrp->hplcRef = hplcRef; + } + hdodSub = mpdochdod[docSub]; + Assert(docSub != docNil); + if ((*hdodSub)->hplcfnd == hNil) +/* create text table in docSub */ + {/* hplcfnd is different from hplcfrd, it needs an initial entry + cpMac entry, therefore do not use HplcInit */ + if (HplcCreateEdc(hdodSub, edcFnd) == hNil) + goto LRetFail; + } + (*hdodMom)->fFormatted = fTrue; + return docSub; +LRetFail: + if (hplcRef != hNil) + { + FreeHplc(hplcRef); + pdrp = ((int *)PdodDoc(doc)) + edcDrp; + pdrp->hplcRef = hNil; + } + DisposeDoc(docSub); + pdrp = ((int *)PdodDoc(doc)) + edcDrp; + pdrp->doc = docNil; + return docNil; +} + + +/* %%Function:ApplyDocMgmtNew %%Owner:peterj */ +/* A P P L Y D O C M G M T N E W */ +/* set up document management properties */ + +ApplyDocMgmtNew (doc, fn) +int doc, fn; +{ + struct STTB **hsttb; + struct DOD *pdod; + struct DOP *pdop; + + FreezeHp(); + pdod = PdodDoc (doc); + Assert ( !pdod->fShort); + pdod->fPromptSI = fTrue; + pdop = &pdod->dop; + + pdop->nRevision = 1; /* reflects version working on. updated at save */ + pdop->tmEdited = 0; /* minutes this file has been edited. */ + pdop->dttmRevised.lDttm = 0; + pdop->dttmLastPrint.lDttm = 0; + + if (fn == fnNil) /* new file */ + { + pdop->dttmCreated = DttmCur(); + pdop->dttmRevised.lDttm = 0; + } + else + { + struct FINDFILE dta; + struct DTTM *pdttm; + char szFile[ichMaxFile]; + + StToSz(PfcbFn(fn)->stFile, szFile); + AnsiToOem(szFile, szFile); + FFirst(&dta, szFile, DA_NORMAL|DA_READONLY); + + /* The following expands out DttmFromPdta, it is done for swap + * tuning purposes. + */ + pdttm = &(pdop->dttmCreated.lDttm); + pdttm->mint = dta.mint; + pdttm->hr = dta.hr; + pdttm->dom = dta.dom; + pdttm->mon = dta.mon; + pdttm->yr = dta.yr + 80; /* DOS year started at 1980 */ + + pdttm->wdy = 0; + pdop->dttmRevised.lDttm = *(long *) pdttm; + +#ifdef WINBUG /* the dos time and date in ofh from WINDOW is in reversed order */ + (struct DTTM)DttmFromDOSTIMEDATE(PfcbFn(fn)->ofh.dostd); +#endif + } + + + MeltHp(); + + /* add author */ + + if ((hsttb = HsttbAssocEnsure(doc)) != hNil && fn == fnNil) /* HM */ + /* if this fails then the author will be incorrect */ + FChangeStInSttb( hsttb, ibstAssocAuthor, vpref.stUsrName ); +} + diff --git a/src/Opus/DDESRVR.C b/src/Opus/DDESRVR.C new file mode 100644 index 0000000..e4ae3f3 --- /dev/null +++ b/src/Opus/DDESRVR.C @@ -0,0 +1,1063 @@ +/* D D E S R V R . C */ +/* Routines for server functionality of DDE */ + + +#include "word.h" +DEBUGASSERTSZ /* WIN - bogus macro for assert string */ +#include "heap.h" +#include "dde.h" +#include "doc.h" +#include "file.h" +#include "strtbl.h" +#include "ch.h" +#include "doslib.h" +#include "idle.h" + +#include "debug.h" + +#ifdef PROTOTYPE +#include "ddesrvr.cpt" +#endif /* PROTOTYPE */ + +extern BOOL fElActive; +extern struct DCLD ** mpdclhdcld[]; +extern struct DOD ** mpdochdod[]; +extern BOOL vfDdeIdle; +extern struct DDES vddes; +extern BOOL vfDeactByOtherApp; +extern int docMac; +extern int cfLink; +extern struct SAB vsab; +extern struct MERR vmerr; +extern int docMac; +extern BOOL vfInsertMode; +extern BOOL vfAbortInsert; +extern IDF vidf; + +#ifdef OPUS_X64 +csconst CHAR stAppDde[] = { 7, 'W', 'i', 'n', 'W', 'o', 'r', 'd' }; +csconst CHAR stSystemDde[] = { 6, 'S', 'y', 's', 't', 'e', 'm' }; +#else +csconst CHAR stAppDde[] = St("WinWord"); +csconst CHAR stSystemDde[] = St("System"); +#endif + +WCompSt (); + +#define cchDdeLinkBkmkBase 9 /* includes terminator */ + +/* F S E R V E R D D E M S G */ +/* Handle messages that are destined for a channel on which we are + the server. Return fFalse if we are not prepared to handle now (message + will come back next time through). +*/ +/* %%Function:FServerDdeMsg %%Owner:peterj */ +FServerDdeMsg (dcl, message, wLow, wHigh) +int dcl; +unsigned message; +int wLow, wHigh; + +{ + BOOL fTerminating = PdcldDcl (dcl)->fTerminating; + struct DDLI ddli; + + DdeDbgCommMsg ("Server", dcl, message, wLow, wHigh); + + if (vfInsertMode) + /* can't safely do anything in insert mode */ + { + vfAbortInsert = fTrue; + return fFalse; + } + + switch (message) + { + + case WM_DDE_EXECUTE: + /* wLow : unused + wHigh : hCommands + */ + { + int das; + BOOL f; + + if (fTerminating || PdcldDcl(dcl)->fExecuting || fElActive) + goto LExeNACK; + + PdcldDcl(dcl)->fExecuting = fTrue; + f = FExecuteHCommands(wHigh); + PdcldDcl(dcl)->fExecuting = fFalse; + + if (!f) + { +LExeNACK: + das = dasNACK; + } + else + das = dasACK; + + if (!FPostDdeDcl (dcl, WM_DDE_ACK, das, wHigh)) + { + GlobalFree (wHigh); + + if (PdcldDcl(dcl)->fTermReceived && !PdcldDcl(dcl)->fExecuting) + /* channel destroyed in course of EXECUTE */ + DestroyDcl(dcl); + } + break; + } + + case WM_DDE_POKE: + /* wLow : hData + wHigh : atomItem + */ + { + struct DMS FAR * lpdms, dms; + int doc = PdcldDcl (dcl)->doc; + int das = dasNACK; + int ibkmk; + + if (fTerminating) + /* not much point in receiving while terminating */ + { + goto LNoAckPoke; + } + + if (fElActive) + /* can't poke while a macro is running */ + { + goto LNackPoke; + } + if ((lpdms = GlobalLockClip (wLow)) == NULL) + /* couldn't lock object, should be rare */ + { + /* incoming data--could easily not be lockable */ + ShrinkSwapArea(); + lpdms = GlobalLockClip (wLow); + GrowSwapArea(); + if (lpdms == NULL) + /* still can't lock it */ + { + ReportDdeError ("Cannot lock handle, dropping message", + dcl, message, 0); + break; + } + } + dms = *lpdms; + GlobalUnlock (wLow); + if (doc != docSystem && + (ibkmk = IbkmkFromDclItem (dcl, wHigh)) != ibkmkNil) + /* we have some place to put the data */ + { + CP ccp; + CHAR stBkmk [cchBkmkMax]; + struct CA ca; + + PcaSet( &ca, doc, cp0, CpMacDocEdit(doc) ); + + if (ibkmk < ibkmkSpecialMin) + { + /* we must reconstruct bkmk later, get info */ + BkmkCpsFromIbkf(ca.doc, ibkmk, &ca.cpFirst, &ca.cpLim); + ca.cpLim = CpMin (CpMacDocEdit (ca.doc), ca.cpLim); + GetStFromSttb(PdodDoc(doc)->hsttbBkmk, ibkmk, stBkmk); + Assert (FLegalBkmkName (stBkmk) && *stBkmk < cchBkmkMax); + } + else + FBkmkCpsIbkmkSpecial (doc, ibkmk, &ca.cpFirst, &ca.cpLim); + + AssureLegalSel (&ca); + + /* put the data in doc where the old bkmk was */ + if (FReadHData (wLow, dms.cf, &ca, cbDMS )) + { + das = dasACK; + if (ibkmk < ibkmkSpecialMin) + { + /* put the bookmark back in place */ + AssureLegalSel (&ca); + /* we can assert this because bookmark already exists */ + AssertDo (FInsertStBkmk (&ca, stBkmk, NULL)); + } + + /* if we are not active, update the display */ + if (vfDeactByOtherApp && !vidf.fNotLive) + UpdateAllWws (fTrue); + + SetUndoNil(); + InvalAgain(); + } + + } +LNackPoke: + if (!FPostDdeDcl (dcl, WM_DDE_ACK, das, wHigh)) + /* unable to post ACK */ + { +LNoAckPoke: + DeleteAtom (wHigh); + GlobalFree (wLow); + } + else if (das == dasACK && dms.fRelease) + GlobalFree (wLow); + break; + } + + + case WM_DDE_ACK: + /* wLow : das + wHigh : atomItem + */ + /* must be in response to some WM_DDE_DATA message */ + { + int iddli = IddliFromDclItem (dcl, wHigh); + + struct DAS das; + bltb (&wLow, &das, sizeof (das)); + + FreezeHp (); + if (iddli != iddliNil) + { + GetPl( vddes.hplddli, iddli, &ddli ); + + if (!das.fAck && ddli.dls == dlsWait) + { + /* free the data */ + Assert (ddli.hData != NULL); + GlobalFree (ddli.hData); + ddli.hData = NULL; + } + if (!das.fAck && das.fBusy) + /* they were busy, cause us to resend */ + ddli.fDirty = fTrue; + + ddli.dls = dlsClear; + PutPl( vddes.hplddli, iddli, &ddli ); + } + DeleteAtom (wHigh); + MeltHp (); + break; + } + + case WM_DDE_REQUEST: + /* wLow : cf + wHigh : atomItem + */ + { + int doc = PdcldDcl (dcl)->doc; + + if (fTerminating || + !FRenderDocItemCf (doc, wHigh, wLow) || + !FSendData (dcl, doc, wHigh, wLow, iddliNil)) + if (!FPostDdeDcl (dcl, WM_DDE_ACK, dasNACK, wHigh)) + DeleteAtom (wHigh); + break; + } + + case WM_DDE_ADVISE: + /* wLow : hOptions + wHigh : atomItem + */ + { + struct DMS FAR * lpdms, dms; + int doc = PdcldDcl (dcl)->doc; + int das = dasNACK; + + /* get the options */ + if ((lpdms = GlobalLockClip (wLow)) == NULL) + { + ReportDdeError ("Cannot lock handle, dropping message", + dcl, message, 0); + return fTrue; + } + dms = *lpdms; + GlobalUnlock (wLow); + + /* if item exists and we can render in cf, set up advise */ + /* (we do not support an ADVISE on the system topic) */ + if (!fTerminating && doc != docSystem && + FRenderDocItemCf (doc, wHigh, dms.cf) && + FAdviseItem (dcl, wHigh, dms.cf, dms.fAck, dms.fNoData)) + { + GlobalFree (wLow); + das = dasACK; + } + + /* ACK or NACK as appropriate */ + if (!FPostDdeDcl (dcl, WM_DDE_ACK, das, wHigh)) + { + DeleteAtom (wHigh); + if (das == dasNACK) + GlobalFree (wLow); + } + break; + } + + case WM_DDE_UNADVISE: + /* wLow : unused + wHigh : atomItem + */ + { + int iddli; + int das = dasACK; + + if (wHigh != NULL && + (iddli = IddliFromDclItem (dcl, wHigh)) != iddliNil) + { + GetPl( vddes.hplddli, iddli, &ddli ); + if (ddli.dls == dlsClear) + { + DeleteDdliServer (iddli); + } + else + /* we are waiting on an ack, cannot delete */ + das = dasBUSY; + } + + else if (wHigh == NULL) + { + int iddliMac = IMacPl( vddes.hplddli ); + + /* determine if it is possible first */ + for (iddli = 0; iddli < iddliMac; iddli++) + { + GetPl( vddes.hplddli, iddli, &ddli ); + if (ddli.dcl == dcl && ddli.dls != dlsClear) + /* can't UNADVISE (waiting on ACK) */ + { + das = dasBUSY; + break; + } + } + if (das == dasACK) + /* no reason not to unadvise found */ + { + for (iddli = iddliMac-1; iddli >= 0; iddli--) + { + GetPl( vddes.hplddli, iddli, &ddli ); + if (ddli.dcl == dcl) + DeleteDdliServer (iddli); + } + } + } + else + /* no advise is set up to delete! */ + { + ReportDdeError ("Unknown link for UNADVISE", dcl, message, + 0); + das = dasNACK; + } + + if (!FPostDdeDcl (dcl, WM_DDE_ACK, das, wHigh)) + DeleteAtom (wHigh); + + break; + } + +#ifdef DEBUG + default: + Assert (fFalse); +#endif /* DEBUG */ + + } + + return fTrue; +} + + + +/* I N I T I A T E D D E */ +/* Called by our AppWndProc when an INITIATE message is received. + Decides if we can serve the requested conversation and, if so, + creates the necessary channels. +*/ +/* %%Function:InitiateDde %%Owner:peterj */ +InitiateDde (hwndThem, atomApp, atomTopic) +HWND hwndThem; +ATOM atomApp, atomTopic; + +{ + if (vidf.fDead || vmerr.fDiskEmerg || vmerr.hrgwEmerg1 == hNil + || vmerr.hrgwEmerg2 == hNil || vmerr.hrgwEmerg3 == hNil || + (atomApp != NULL && atomApp != AtomFromStNA (StNear(stAppDde)))) + /* initiate is not directed to us or we are not accepting links */ + { + DdeDbgCommAtom ("InitiateDde: initiate refused", dclNil, atomApp); + return; + } + + DdeDbgCommAtom ("InitiateDde", dclNil, atomTopic); + + if (atomTopic == NULL) + /* catalog all topics available */ + { + int doc; + CreateServerChannel (docSystem, hwndThem); /* system */ + for (doc = docMinNormal; doc < docMac; doc++) + if (mpdochdod [doc] != hNil && + PdodDoc (doc)->fMother && WwDisp(doc,wwNil,fFalse) != wwNil) + CreateServerChannel (doc, hwndThem); + } + + else if (atomTopic == AtomFromStNA (StNear(stSystemDde))) + /* system topic */ + CreateServerChannel (docSystem, hwndThem); + + else + /* specific topic */ + { + int doc; + CHAR stTopic [cchMaxFile]; + CHAR stNorm [cchMaxFile]; + StFromAtom (stTopic, cchMaxFile, atomTopic); + if ((doc = DocFromSt (stTopic)) != docNil || + (FNormalizeStFile (stTopic, stNorm, nfoNormal) && + (doc = DocFromSt (stNorm)) != docNil)) + CreateServerChannel (doc, hwndThem); + } +} + + +/* C R E A T E S E R V E R C H A N N E L */ +/* create a channel over which we are the server and the topic is doc. +*/ +/* %%Function:CreateServerChannel %%Owner:peterj */ +CreateServerChannel (doc, hwndThem) +int doc; +HWND hwndThem; + +{ + int dcl; + ATOM atomApp, atomTopic; + struct DCLD *pdcld; + CHAR st[ichMaxFile]; + + /* get an st for the topic */ + if (doc == docSystem) + CopyCsSt(stSystemDde, st); + else + GetDocSt(doc, st, gdsoFullPath); + + /* add the atoms in our response */ + Assert (st[0] != 0); + atomTopic = AtomAddSt (st); /* failure checked by fMemFail below */ + atomApp = AtomAddSt (StNear(stAppDde)); + + if (vmerr.fMemFail || (dcl = DclCreateChannel (dtServer)) == dclNil) + { + DeleteAtom(atomTopic); + DeleteAtom(atomApp); + return; /* OOM - channel not created */ + } + + pdcld = PdcldDcl (dcl); + pdcld->hwndThem = hwndThem; + pdcld->doc = doc; + + DdeDbgCommAtom ("CreateServerChannel", dcl, atomTopic); + + /* send response */ + SendMessage (hwndThem, WM_DDE_ACK, pdcld->hwndUs, + MAKELONG (atomApp, atomTopic)); +} + + +/* H R E N D E R C L I P L I N K */ +/* Render doc, cpFirst:cpLim in "LINK" format. Return a handle to an + object of the form: "APPNAME\0TOPICNAME\0ITEMNAME\0\0", or NULL in case + of some failure. +*/ +/* %%Function:HRenderClipLink %%Owner:peterj */ +HRenderClipLink () + +{ + LPCH lpch; + HANDLE hData; + int cch, cchT; + CHAR szApp [cchMaxSz]; + CHAR szTopic [cchMaxFile]; + CHAR szBkmk [cchBkmkMax]; + + DdeDbgCommSz ("HRenderClipLink"); + + Assert (vsab.fOwnClipboard); + Assert (FCanLinkScrap()); + + StToSz (StNear(stAppDde), szApp); + GetDocSt(vsab.doc, szTopic, gdsoFullPath); + StToSzInPlace(szTopic); + + if (!FGetSzBkmkForCps (&vsab.caCopy, szBkmk)) + { + DdeDbgCommSz ("HRenderClipLink: no bookmark to render"); + return NULL; + } + + cch = 0; + if ((hData = OurGlobalAlloc(GMEM_MOVEABLE, (DWORD) + (CchSz(szApp)+CchSz(szTopic)+CchSz(szBkmk)+1))) == NULL || + (lpch = GlobalLockClip (hData)) == NULL) + { + if (hData != NULL) + GlobalFree (hData); + DdeDbgCommSz ("HRenderClipLink: render unsuccessful"); + return NULL; + } + + bltbx ((LPSTR)szApp, (LPSTR)lpch+cch, cchT = CchSz (szApp)); + cch += cchT; + bltbx ((LPSTR)szTopic, (LPSTR)lpch+cch, cchT = CchSz (szTopic)); + cch += cchT; + bltbx ((LPSTR)szBkmk, (LPSTR)lpch+cch, cchT = CchSz (szBkmk)); + cch += cchT; + lpch [cch] = '\0'; + + GlobalUnlock (hData); + + DdeDbgCommSz ("HRenderClipLink: render successful"); + + return hData; +} + + + +/* F G E T S Z B K M K F O R C P S */ +/* Called to render a link. Creates a unique bookmark name for + a range of text (that was copied to clipboard at some point before) + and defines the bookmark. +*/ +/* %%Function:FGetSzBkmkForCps %%Owner:peterj */ +FGetSzBkmkForCps (pca, sz) +struct CA *pca; +CHAR *sz; + +{ + int wBkmk = 1; + CHAR st [cchBkmkMax]; + + bltb (StSharedKey("DDE_LINK",DdeLinkBkmk), st, cchDdeLinkBkmkBase); + + /* find the next unused dde link bkmk name */ + while (FSearchBookmark (pca->doc, st, NULL, NULL, NULL, bmcUser)) + { + CHAR *pch = st + cchDdeLinkBkmkBase; + *st = cchDdeLinkBkmkBase - 1 + CchIntToPpch (++wBkmk, &pch); + } + + Assert (FLegalBkmkName (st)); + if (!FInsertStBkmk (pca, st, NULL)) + return fFalse; + + StToSz (st, sz); + return fTrue; +} + + + +/* V A L I D A T E S E R V E R L I N K S */ +/* Go through all active links we serve and for each one whose ibkmk + is ibkmkNil (indicates the bookmark was deleted at some point) try to + find a bookmark based on atomItem. +*/ +/* %%Function:FValidateServerLinks %%Owner:peterj */ +ValidateServerLinks () +{ + int iddli; + struct PLDDLI **hplddli = vddes.hplddli; + struct DDLI ddli; + + vddes.fInvalidDdli = fFalse; + + if (hplddli == hNil) + return; + + DdeDbgCommSz ("ValidateServerLinks"); + + FreezeHp (); + + for ( iddli = 0; iddli < IMacPl( hplddli ); iddli++ ) + { + GetPl( hplddli, iddli, &ddli ); + if (ddli.ibkf == ibkmkNil) + { + int ibkmk = IbkmkFromDclItem (ddli.dcl, ddli.atomItem); + if (ibkmk != ibkmkNil) + /* bookmark now exists, use it */ + { + ddli.ibkf = ibkmk; + ddli.fDirty = fTrue; + PutPl( hplddli, iddli, &ddli ); + vddes.fDirtyLinks = fTrue; + DdeDbgCommAtom ("Validating", ddli.dcl, ddli.atomItem); + } + else + /* we still have invalid links */ + { + vddes.fInvalidDdli = fTrue; + DdeDbgCommAtom ("Still Invalid", ddli.dcl, ddli.atomItem); + } + } + } + MeltHp (); +} + + + + +/* U P D A T E D I R T Y L I N K S */ +/* For each dirty server link, send new data. +*/ +/* %%Function:UpdateDirtyLinks %%Owner:peterj */ +UpdateDirtyLinks () +{ + + int iddli, iddliMac; + struct PL **hplddli = vddes.hplddli; + struct DDLI ddli; + + vddes.fDirtyLinks = fFalse; + + if (hplddli == hNil) + return; /* no links */ + + DdeDbgCommSz ("UpdateDirtyLinks"); + FreezeHp (); + iddliMac = IMacPl( hplddli ); + for (iddli = 0; iddli < iddliMac; iddli++) + { + GetPl( hplddli, iddli, &ddli ); + if (ddli.fDirty && ddli.ibkf != ibkmkNil) + { + /* this link is dirty, send an update */ + int dcl = ddli.dcl; + int doc = PdcldDcl (dcl)->doc; + ATOM atom = ddli.atomItem; + BOOL f; + ReaddAtom (atom); + + MeltHp (); + f = FSendData (dcl, doc, atom, ddli.cf, iddli); + DdeDbgCommAtom ("UpdateDirtyLinks: sending update", dcl, atom); + FreezeHp (); + if (!f) + DeleteAtom (ddli.atomItem); + else + { + GetPl (hplddli, iddli, &ddli); + ddli.fDirty = fFalse; + PutPl (hplddli, iddli, &ddli); + } + } + } + MeltHp (); +} + + +/* D E L E T E D D L I S E R V E R */ +/* Delete a link for which we are the server. +*/ +/* %%Function:DeleteDdliServer %%Owner:peterj */ +DeleteDdliServer (iddli) +int iddli; +{ + struct PL **hplddli = vddes.hplddli; + struct DDLI ddli; + + FreezeHp (); + Assert (hplddli != hNil); + Assert (IMacPl( hplddli ) > iddli); + + GetPl( hplddli, iddli, &ddli ); + DeleteAtom (ddli.atomItem); + MeltHp (); + + DeleteFromPl (hplddli, iddli); + + if (IMacPl( hplddli ) == 0) + FreePh (&vddes.hplddli); +} + + + +/* F R E N D E R D O C I T E M C F */ +/* Return true if we can render the bookmark (doc, atomItem) in format + cf. +*/ +/* %%Function:FRenderDocItemCf %%Owner:peterj */ +FRenderDocItemCf (doc, atomItem, cf) +int doc, cf; +ATOM atomItem; +{ + + CP cpFirst, cpLim; + + DdeDbgCommAtom ("Trying to render", cf, atomItem); + + if (doc == docSystem) + return cf == CF_TEXT && StiFromSystemItem (atomItem) != stiNil; + + else + /* first find the bookmark, if it exists check the format */ + return (FCpsFromDocItem (doc, atomItem, &cpFirst, &cpLim) + && FCanWriteCf (cf, doc, cpFirst, cpLim, fFalse /*fRestrictRTF */)); +} + + + +/* F C P S F R O M D O C I T E M */ +/* %%Function:FCpsFromDocItem %%Owner:peterj */ +FCpsFromDocItem (doc, atomItem, pcpFirst, pcpLim) +int doc; +ATOM atomItem; +CP *pcpFirst, *pcpLim; +{ + int ibkmk; + CHAR stBkmk [cchBkmkMax]; + + if (doc == docSystem) + { + Assert (fFalse); + return fFalse; + } + + StFromAtom (stBkmk, cchBkmkMax, atomItem); + return FSearchBookmark(doc, stBkmk, pcpFirst, pcpLim, NULL, bmcUser|bmcDoc) + && *pcpLim > *pcpFirst; +} + + +/* I B K M K F R O M D C L I T E M */ +/* %%Function:IbkmkFromDclItem %%Owner:peterj */ +IbkmkFromDclItem (dcl, atomItem) +int dcl; +ATOM atomItem; +{ + int ibkmk; + int doc = PdcldDcl (dcl)->doc; + CHAR st [cchBkmkMax]; + + if (doc == docSystem || !mpdochdod [doc]) + return ibkmkNil; + + Assert (!PdodDoc (doc)->fShort); + StFromAtom (st, cchBkmkMax, atomItem); + FSearchBookmark(doc, st, NULL, NULL, &ibkmk, bmcUser|bmcDoc); + return ibkmk; +} + + +/* S T I F R O M S Y S T E M I T E M */ +/* Return the system item number identified by atomItem. +*/ +/* %%Function:StiFromSystemItem %%Owner:peterj */ +StiFromSystemItem (atomItem) +ATOM atomItem; +{ + CHAR rgch [cchMaxSz]; + + StFromAtom (rgch, cchMaxSz, atomItem); + StToSzInPlace (rgch); + return IdFromSzgSz (szgDdeSysTopic, rgch); +} + + +/* F S E N D D A T A */ +/* Sends atomItem over channel dcl. If iddli != iddliNil then sends over + link iddli (sets hData and sets fAck, fResponse correctly). Returns + false if the data could not be sent. atomItem should be reused or + deleted iff this returns false. +*/ +/* %%Function:FSendData %%Owner:peterj */ +FSendData (dcl, doc, atomItem, cf, iddli) +int dcl, doc, cf, iddli; +ATOM atomItem; +{ + HANDLE hData; + struct DMS dms; + BOOL fData; + CP cpFirst, cpLim; + LPSTR lpch; + struct DDLI ddli; + int fBlankPic = fFalse; + + + DdeDbgCommAtom ("Sending Data", dcl, atomItem); + + SetBytes (&dms, 0, cbDMS); + + if (iddli != iddliNil) + { + /* this is a response to an ADVISE */ + + GetPl( vddes.hplddli, iddli, &ddli ); + dms.fAck = ddli.fAckReq; + fData = !ddli.fNoData; + dms.fResponse = fFalse; + } + else + { + /* this is a response to a REQUEST */ + dms.fAck = fFalse; + dms.fResponse = fTrue; + fData = fTrue; + } + + dms.cf = cf; + dms.fRelease = fTrue; + Assert (cbDMS == 4); /* cb in hData before actual data */ + + if (fData) + { + if (doc == docSystem) + { + if ((hData = HDataWriteSti (StiFromSystemItem (atomItem))) + == NULL) + return fFalse; + } + /* find the area refered to and copy it to hData */ + else if (!FCpsFromDocItem (doc, atomItem, &cpFirst, &cpLim) + || (hData = HDataWriteDocCps (cf, doc, cpFirst, cpLim, + cbDMS, &fBlankPic)) + == NULL) + /* note: if fBlankPic was true, we had an inserted graphics + frame selected, and the handle returned is null, but it is + not an error. Could alert at this point. + */ + { + return fFalse; + } + + /* copy out the status portion */ + if ((lpch = GlobalLockClip (hData)) == NULL) + goto LFailed; + bltbx ((LPSTR)&dms, lpch, cbDMS); + GlobalUnlock (hData); + } + else + hData = NULL; /* send null if they ask for no data */ + + + /* all set, send the data message */ + if (!FPostDdeDcl (dcl, WM_DDE_DATA, hData, atomItem)) + { +LFailed: + /* message could not be sent, free data. caller frees atom */ + if (hData != NULL) + GlobalFree (hData); + return fFalse; + } + + else if (iddli != iddliNil) + { + GetPl( vddes.hplddli, iddli, &ddli ); + if (ddli.fAckReq) + { + ddli.hData = hData; + ddli.dls = dlsWait; + PutPl (vddes.hplddli, iddli, &ddli); + } + } + + DdeDbgCommSz ("SendData completed successfully"); + return fTrue; +} + + +/* H D A T A W R I T E S T I */ +/* Write system topic item sti to a global handle. Return NULL if it + cannot be written. Handle has cbDMS bytes at the begining unused. +*/ +/* %%Function:HDataWriteSti %%Owner:peterj */ +HDataWriteSti (sti) +int sti; +{ + HANDLE h = NULL; + CHAR FAR *lpch; + int ich = cbDMS, cch = 1 + cbDMS; + CHAR st [cchMaxSt]; + + if ((h = OurGlobalAlloc(GMEM_DDE, (DWORD)(cch))) == NULL) + goto LFailed; + + switch (sti) + { +#ifdef DEBUG + default: + Assert (fFalse); + break; +#endif /* DEBUG */ + + case stiSysItems: /* list item offered on System Topic */ + { + int stiSend; + for (stiSend = stiMin; stiSend < stiMac; stiSend++) + { + st [0] = CchSzFromSzgId (st+1, szgDdeSysTopic, stiSend, + ichMaxFile) - 1; + if (!FAddStToHData (&h, &cch, &ich, st)) + goto LFailed; + } + break; + } + + case stiTopics: /* list topics offered */ + { + int doc; + /* system topic */ + if (!FAddStToHData (&h, &cch, &ich, StNear(stSystemDde))) + goto LFailed; + /* each open document (even those not in a window) */ + for (doc = docMinNormal; doc < docMac; doc++) + { + GetDocSt (doc, st, gdsoFullPath); /* works for all doc's */ + if (*st) + if (!FAddStToHData (&h, &cch, &ich, st)) + goto LFailed; + } + + break; + } + + case stiFormats: /* list clipboard formats rendered */ + { + int cf = cfNil; + CHAR *pch; + + /* standard formats */ + while ((cf = CfNextCf (cf, fFalse)) != cfNil) + { + GetFormatSt(cf, st); + if (!FAddStToHData (&h, &cch, &ich, st)) + goto LFailed; + } + /* add link format */ + GetFormatSt(cfLink, st); + if (!FAddStToHData (&h, &cch, &ich, st)) + goto LFailed; + + break; + } + } + + /* null terminate */ + if ((lpch = GlobalLockClip (h)) == NULL) + goto LFailed; + lpch [ich] = 0; + GlobalUnlock (h); + + return h; + +LFailed: + if (h != NULL) + GlobalFree (h); + return NULL; +} + + +#ifdef OPUS_X64 +csconst CHAR stCsText[] = { 4, 'T', 'E', 'X', 'T' }; +csconst CHAR stCsBitmap[] = { 6, 'B', 'I', 'T', 'M', 'A', 'P' }; +csconst CHAR stCsMetafile[] = { + 12, 'M', 'E', 'T', 'A', 'F', 'I', 'L', 'E', 'P', 'I', 'C', 'T' + }; +#else +csconst CHAR stCsText[] = StKey("TEXT", CfText); +csconst CHAR stCsBitmap[] = StKey("BITMAP", CfBitmap); +csconst CHAR stCsMetafile[] = StKey("METAFILEPICT", CfMetafile); +#endif + +/* G E T F O R M A T S T */ +/* %%Function:GetFormatSt %%Owner:peterj */ +GetFormatSt(cf, st) +int cf; +CHAR *st; +{ + switch (cf) + { + case CF_TEXT: + CopyCsSt(stCsText, st); + break; + case CF_BITMAP: + CopyCsSt(stCsBitmap, st); + break; + case CF_METAFILEPICT: + CopyCsSt(stCsMetafile, st); + break; + default: + st [0] = GetClipboardFormatName(cf, (LPSTR)st+1, cchMaxSt-1); + break; + } +} + + +/* F A D D S T T O H D A T A */ +/* Append st to *ph. *pcch is the size of the block, *pich is the location + for the next item. If *pich is > cbDMS, prepend a tab. +*/ +/* %%Function:FAddStToHData %%Owner:peterj */ +FAddStToHData (ph, pcch, pich, st) +HANDLE *ph; +int *pcch, *pich; +CHAR *st; +{ + CHAR FAR *lpch; + HANDLE h; + BOOL fAddTab = (*pich > cbDMS ? 1 : 0); + + if ((h = OurGlobalReAlloc(*ph, (long)(uns)(*pcch += (*st + fAddTab)), + GMEM_DDE)) == NULL) + return fFalse; + *ph = h; + + if ((lpch = GlobalLockClip (h)) == NULL) + return fFalse; + + if (fAddTab) + lpch [(*pich)++] = chTab; + bltbx ((CHAR FAR *)st+1, (CHAR FAR *)&lpch [*pich], *st); + *pich += *st; + + GlobalUnlock (h); + return fTrue; +} + + + +/* F A D V I S E I T E M */ +/* Set up an advise link on dcl for atomItem. +*/ +/* %%Function:FAdviseItem %%Owner:peterj */ +FAdviseItem (dcl, atomItem, cf, fAckReq, fNoData) +int dcl, cf; +ATOM atomItem; +BOOL fAckReq, fNoData; +{ + struct DDLI ddli; + + if (vddes.hplddli == hNil) + if ((vddes.hplddli = HplInit (cbDDLI, 1)) == hNil) + return fFalse; + + ReaddAtom (atomItem); + + DdeDbgCommAtom ("FAdviseItem", dcl, atomItem); + + SetBytes (&ddli, 0, cbDDLI); + ddli.dcl = dcl; + ddli.fAckReq = fAckReq; + ddli.fNoData = fNoData; + ddli.fDirty = fFalse; + ddli.cf = cf; + ddli.dls = dlsClear; + ddli.ibkf = IbkmkFromDclItem (dcl, atomItem); + ddli.atomItem = atomItem; + ddli.hData = NULL; + + /* guaranteed by init call */ + AssertDo(FInsertInPl (vddes.hplddli, (*vddes.hplddli)->iMac, &ddli)); + + return fTrue; +} + + + + diff --git a/src/Opus/DEBUG.H b/src/Opus/DEBUG.H new file mode 100644 index 0000000..12542df --- /dev/null +++ b/src/Opus/DEBUG.H @@ -0,0 +1,1216 @@ +/* D E B U G . H */ + +/* W I N D O W S A L L O C F A I L U R E S */ +#include "debugwin.h" + +/* this is to ease the pain of who has and who doesn't have PROFILE + defined for putobj/takeobj purposes. +*/ +#ifdef DEBUG +#ifndef PROFILE +#define PROFILE +#endif /* PROFILE */ +#endif /* DEBUG */ +#ifdef HYBRID +#ifndef PROFILE +#define PROFILE +#endif /* PROFILE */ +#endif /* HYBRID */ +#ifndef DEBUG +#ifndef HYBRID +#ifdef PROFILE +#undef PROFILE +#endif /* PROFILE */ +#endif /* !HYBRID */ +#endif /* !DEBUG */ + +#define wUnusedHeapWord 0xFFFF /* sorry, BV, needed an odd number */ + +/* number of characters of extra global space for debugging routines */ +#define cchDebug 2048 + +#ifdef DEBUG +#define ShowLbs(a, b) (!vdbs.fShowLbs ? 0 : ShowLbsProc(a, b)) +#else +#define ShowLbs(a, b) +#endif +#ifdef DEBUG + +#define Scribble(a, b) (!vdbs.grpfScribble ? 0 : ScribbleProc(a, b)) +#else +#define Scribble(a, b) +#endif + +/* S C R I B B L E P O S I T I O N S */ +#define ispNil -1 /* set isp to ispNil to disable */ +/* continious operations */ +#define ispIdle1 1 +#define ispIdle2 0 +#define ispIdleComplete 2 +#define ispInsertLine 3 + +/* frequent operations */ +#define ispInsertMode 7 +#define ispUpdateWw 6 +#define ispQuickSave 5 +#define ispSavePass 6 +#define ispInitStructs 6 +#define ispDisplayFli 5 +#define ispAdjustCp 5 +#define ispFormatLine 5 +#define ispWireFont 4 + +/* format operations */ +#define ispFieldFormat1 4 +#define ispFieldFormat2 3 +#define ispFieldParse 3 + +/* layout/pagination/printing operations */ +#define ispLayout1 11 +#define ispLayout2 10 +#define ispLayout3 9 +#define ispLayout4 8 +#define ispUpdateHplcpgd 13 +#define ispDispLayoutRC 12 + +/* infrequent operations */ +#define ispDdeIdle 13 +#define ispDdeWait 12 +#define ispTest 14 +#define ispRefreshSpeed 14 +#define ispFieldCalc1 15 +#define ispFieldCalc2 14 +#define ispGraphics 12 + +/* following can be removed when all DebugFileHeaders are gone */ +#define DebugFileHeader + +/* A S S E R T */ +/* Assert will stop if the argument is false */ +#ifdef DEBUG +#define Assert(f) ((f) ? 0 : AssertProc((CHAR *)szAssertFile,__LINE__)) +#define AssertX(f) Assert(f) +#define AssertSz(f,sz) ((f) ? 0 : AssertSzProc(SzFrame(sz),(CHAR *)szAssertFile,__LINE__)) +#define AssertH(h) AssertHSzLn(h,(CHAR *)szAssertFile,__LINE__) +#define AssertDo(f) Assert(f) +#else +#define AssertX(f) (0) +#define Assert(f) +#define AssertH(h) +#define AssertDo(f) (f) +#define AssertSz(f,sz) +#endif + +/* A S S E R T P E N V */ +#ifdef DEBUG +#define AssertPenv(penv) \ +{ \ +extern ENV *penvBase; \ +Assert (penv != penvBase); \ +Assert (*(int *)penv); \ +} +#else +#define AssertPenv(penv) +#endif + +/* R E P O R T*/ +#ifdef DEBUG +#define ReportSz(sz) ( ReportSzProc(SzFrame(sz), (CHAR *)szAssertFile,__LINE__)) +#elif defined(OPUS_X64) +#define ReportSz(sz) OpusX64ReportSz((sz), __FILE__, __LINE__) +#else +#define ReportSz(sz) +#endif + +/* R E P O R T F */ +/* ReportF will stop if the argument is false */ +#ifdef DEBUG +#define ReportF(f, id) ((f) ? 0 : ReportProc(id, (CHAR *)szAssertFile,__LINE__)) +#else +#define ReportF(f, id) +#endif + +/* N A T I V E V E R I F I C A T I O N */ + +#ifdef DEBUG +#define FetchCp(doc,cp,fcm) \ + S_FetchCp(doc,cp,fcm) +#define CachePara(doc,cp) \ + S_CachePara(doc,cp) +#define FormatLineDxa(ww,doc,cp,dxa) \ + S_FormatLineDxa(ww,doc,cp,dxa) +#define LoadFont(pchp, fWidth) \ + S_LoadFont(pchp, fWidth) +#define CpSearchSz(pbmib, cpFirst, cpLim, pcpNextRpt, pppr) \ + S_CpSearchSz(pbmib, cpFirst, cpLim, pcpNextRpt, pppr) +#define CpSearchSzBackward(pbmib, cpFirst, cpLim) \ + S_CpSearchSzBackward(pbmib, cpFirst, cpLim) +#define FfcFormatFieldPdcp(pdcp, ww, doc, cp, ch) \ + S_FfcFormatFieldPdcp(pdcp, ww, doc, cp, ch) +#define DcpSkipFieldChPflcd(ch, pflcd, fShowResult, fFetch) \ + S_DcpSkipFieldChPflcd(ch, pflcd, fShowResult, fFetch) +#define FShowResultPflcdFvc(pflcd, fvc) \ + S_FShowResultPflcdFvc(pflcd, fvc) +#define IfldFromDocCp(doc, cp, fMatch) \ + S_IfldFromDocCp(doc, cp, fMatch) +#define FillIfldFlcd(hplcfld, ifld, pflcd) \ + S_FillIfldFlcd(hplcfld, ifld, pflcd) +#define GetIfldFlcd(doc, ifld, pflcd) \ + S_GetIfldFlcd(doc, ifld, pflcd) +#define SetFlcdCh(doc, pflcd, ch) \ + S_SetFlcdCh(doc, pflcd, ch) +#define IfldInsertDocCp(doc, cp) \ + S_IfldInsertDocCp(doc, cp) +#define FetchVisibleRgch(pfvb, fvc, fProps, fNested) \ + S_FetchVisibleRgch(pfvb, fvc, fProps, fNested) +#define FetchCpPccpVisible(doc, cp, pccp, fvc, fNested) \ + S_FetchCpPccpVisible(doc, cp, pccp, fvc, fNested) +#define CpVisibleCpField(doc, cp, fvc, fIns) \ + S_CpVisibleCpField(doc, cp, fvc, fIns) +#define FVisibleCp(ww, doc, cp) \ + S_FVisibleCp(ww, doc, cp) +#define DisplayFliCore( ww, rcClip, xl, yl ) \ + S_DisplayFliCore( ww, rcClip, xl, yl ) +#define FMarkLine(psel, hpldr, idr, pedl, cpFirstSel, cpLimSel, cpFirstLine) \ + S_FMarkLine(psel, hpldr, idr, pedl, cpFirstSel, cpLimSel, cpFirstLine) +#define XpFromDcp(dcp1, dcp2, pxpFirst, pich) \ + S_XpFromDcp(dcp1, dcp2, pxpFirst, pich) +#define MapStc(pdod, stc, pchp, ppap) \ + S_MapStc(pdod, stc, pchp, ppap) +#define AddVisiSpaces(hdc, xpLine, ypLine, prcw) \ + S_AddVisiSpaces(hdc, xpLine, ypLine, prcw) +#define ApplyPrlSgc(hpprl, cch, prgbProps, sgc) \ + S_ApplyPrlSgc(hpprl, cch, prgbProps, sgc) +#define FGetParaState(fAll, fAbortOk) \ + S_FGetParaState(fAll, fAbortOk) +#define FGraphicsFcidToPlf(fcid, plf, fPrinterFont) \ + S_FGraphicsFcidToPlf(fcid, plf, fPrinterFont) +#define PnFromPlcbteFc(hplcbte, fc) \ + S_PnFromPlcbteFc(hplcbte, fc) +#define BFromFc(hpfkp, fc, pfcFirst, pfcLim, pifc) \ + S_BFromFc(hpfkp, fc, pfcFirst, pfcLim, pifc) +#define HpchFromFc(fn, fc) \ + S_HpchFromFc(fn, fc) +#define HpchGetPn(fn, pn) \ + S_HpchGetPn(fn, pn) +#define IbpCacheFilePage(fn, pn) \ + S_IbpCacheFilePage(fn, pn) +#define DoPrmSgc(prm, prgbProps, sgc) \ + S_DoPrmSgc(prm, prgbProps, sgc) +#define LoadFcidFull( fcid ) \ + S_LoadFcidFull( fcid ) +#define ResetFont(fPrinterFont) \ + S_ResetFont(fPrinterFont) +#define DisplayFli( ww, hpldr, idr, dl, ypLine ) \ + S_DisplayFli( ww, hpldr, idr, dl, ypLine ) +#define FormatLine( ww, doc, cp ) \ + S_FormatLine( ww, doc, cp ) +#define FormatLineDr( ww, cp, pdr ) \ + S_FormatDrLine( ww, cp, pdr ) +#define FAddRun(fn, fc, pch, cch, pfkpd, fPara, fAllocMac, fPlcMustExp, fWord3) \ + FAddRunCkProc(fn, fc, pch, cch, pfkpd, fPara, fAllocMac, fPlcMustExp) +#define AddRun(fn, fc, pch, cch, pfkpd, fPara, fAllocMac, fPlcMustExp, fWord3) \ + C_AddRun(fn, fc, pch, cch, pfkpd, fPara, fAllocMac, fPlcMustExp) +#define WriteRgchToFn(fn, pch, cch) \ + S_ScanFnForBytes(fn, (char HUGE *)pch, cch, fTrue /* fWrite */) +#define ReadRgchFromFn(fn, pch, cch) \ + S_ScanFnForBytes(fn, (char HUGE *)pch, cch, fFalse /* fWrite */) +#define WriteHprgchToFn(fn, hpch, cch) \ + S_ScanFnForBytes(fn, hpch, cch, fTrue /* fWrite */) +#define ReadHprgchFromFn(fn, hpch, cch) \ + S_ScanFnForBytes(fn, hpch, cch, fFalse /* fWrite */) +#define FInTableDocCp(doc, cp) \ + S_FInTableDocCp(doc, cp) +#define AdjustCp(pca, dcpIns) \ + S_AdjustCp(pca, dcpIns) +#define IbpLru() \ + S_IbpLru() +#define ClFormatLines(plbs, cpLim, dylFill, dylMax, clLim, dxl, f1, f2) \ + S_ClFormatLines(plbs, cpLim, dylFill, dylMax, clLim, dxl, f1, f2) +#define CacheParaL(doc, cp, fOutline) \ + S_CacheParaL(doc, cp, fOutline) +#define CacheSectL(doc, cp, fOutline) \ + S_CacheSectL(doc, cp, fOutline) +#define FAbortLayout(fOutline, plbs) \ + S_FAbortLayout(fOutline, plbs) +#define PdrFetch(hpldr, idr, pdrf) \ + S_PdrFetch(hpldr, idr, pdrf) +#define PdrFetchAndFree(hpldr, idr, pdrf) \ + S_PdrFetchAndFree(hpldr, idr, pdrf) +#define PdrFreeAndFetch(hpldr, idr, pdrf) \ + S_PdrFreeAndFetch(hpldr, idr, pdrf) +#define FreePdrf(pdrf) \ + S_FreePdrf(pdrf) +#define PtOrigin(hpldr, idr) \ + S_PtOrigin(hpldr, idr) +#define GetCpFirstCpLimDisplayPara(ww, doc, cp, pcpFirst, pcpLim) \ + S_GetCpFirstCpLimDisplayPara(ww, doc, cp, pcpFirst, pcpLim) +#define CpFormatFrom(ww, doc, cp) \ + S_CpFormatFrom(ww, doc, cp) +#define CpVisibleBackCpField(doc, cp, fvc) \ + S_CpVisibleBackCpField(doc, cp, fvc) +#define FAssignLr(plbs, dylFill, fEmptyOK) \ + S_FAssignLr(plbs, dylFill, fEmptyOK) +#define FWidowControl(plbs, plbsNew, dylFill, fEmptyOK) \ + S_FWidowControl(plbs, plbsNew, dylFill, fEmptyOK) +#define IfrdGatherFtnRef(plbs, plbsNew, ifrd, fNormal, ylReject, ylAccept) \ + S_IfrdGatherFtnRef(plbs, plbsNew, ifrd, fNormal, ylReject, ylAccept) +#define FGetFtnBreak(plbs, ifrl, pfrl, fpc) \ + S_FGetFtnBreak(plbs, ifrl, pfrl, fpc) +#define CopyHdtLrs(ihdt, plbs, yl, plbsAbs) \ + S_CopyHdtLrs(ihdt, plbs, yl, plbsAbs) +#define CopyLrs(hpllrFrom, plbsTo, ilrMac, yl, fCopyIgnore, xl) \ + S_CopyLrs(hpllrFrom, plbsTo, ilrMac, yl, fCopyIgnore, xl) +#define ReplaceInPllr(hpllr, ilr, plr) \ + S_ReplaceInPllr(hpllr, ilr, plr) +#define PushLbs(plbsFrom, plbsTo) \ + S_PushLbs(plbsFrom, plbsTo) +#define PopLbs(plbsId, plbsTo) \ + S_PopLbs(plbsId, plbsTo) +#define CopyLbs(plbsFrom, plbsTo) \ + S_CopyLbs(plbsFrom, plbsTo) +#define LbcFormatPara(plbs, dylFill, clLim) \ + S_LbcFormatPara(plbs, dylFill, clLim) +#define FUpdateDr(ww, hpldr, idr, rcwInval, fAbortOK, udmod, cpUpd) \ + S_FUpdateDr(ww, hpldr, idr, rcwInval, fAbortOK, udmod, cpUpd) +#define ScrollDrUp(ww, hpldr, idr, h2, dlFrom, dlTo, yp1, yp2, yp3, yp4) \ + S_ScrollDrUp(ww, hpldr, idr, h2, dlFrom, dlTo, yp1, yp2, yp3, yp4) +#define MiscPlcLoops(hplc, iFirst, iLim, pResult, wRoutine) \ + S_MiscPlcLoops(hplc, iFirst, iLim, pResult, wRoutine) +#define FFillRgwWithSeqLevs(doc, cp, ipad, ifld, hplcpad, hplcfld, rgw) \ + S_FFillRgwWithSeqLevs(doc, cp, ipad, ifld, hplcpad, hplcfld, rgw) +#define AdjustHplcedlCps(hplcedl, cp, dcp) \ + S_AdjustHplcedlCps(hplcedl, cp, dcp) +#define WidthHeightFromBrc(brc, grpf) \ + S_WidthHeightFromBrc(brc, grpf) +#define PxsInit(pxs, ixsMax, pxbc) \ + S_PxsInit(pxs, ixsMax, pxbc) +#define PostTn(pxbc, tnt, h, c) \ + S_PostTn(pxbc, tnt, h, c) +#define FDoTns(pxbc) \ + S_FDoTns(pxbc) +#define CloseTns(pxbc) \ + S_CloseTns(pxbc) +#define FReplace(pca, fn, fc, dfc) \ + S_FReplace(pca, fn, fc, dfc) +#define XReplace(fPlan, pxbc, pxsr) \ + S_XReplace(fPlan, pxbc, pxsr) +#define IpcdSplit(hplcpcd, cp) \ + S_IpcdSplit(hplcpcd, cp) +#define XRepl1(fPlan, pxbc, pxsr) \ + S_XRepl1(fPlan, pxbc, pxsr) +#define InvalCaFierce() \ + S_InvalCaFierce() +#define FCpVisiInOutline(ww, doc, cp, ccp, pcpFirstInvisi) \ + S_FCpVisiInOutline(ww, doc, cp, ccp, pcpFirstInvisi) +#define DrawInsertLine(psel) \ + S_DrawInsertLine(psel) +#define FInsertInPlc(hplc, i, cp, pch) \ + S_FInsertInPlc(hplc, i, cp, pch) +#define FOpenPlc(hplc, i, di) \ + S_FOpenPlc(hplc, i, di) +#define ShrinkPlc(hplc, iMaxNew, i, di) \ + S_ShrinkPlc(hplc, iMaxNew, i, di) +#define FStretchPlc(hplc, di) \ + S_FStretchPlc(hplc, di) +#define FNewChpIns(doc, cp, pchp, stc) \ + S_FNewChpIns(doc, cp, pchp, stc) +#define FInsertRgch(doc, cp, rgch, cch, pchp, ppap) \ + S_FInsertRgch(doc, cp, rgch, cch, pchp, ppap) +#define FcAppendRgchToFn(fn, pch, cch) \ + S_FcAppendRgchToFn(fn, pch, cch) +#define CbGrpprlProp(f, p1, cb, p2, p3, cw, mpiwspx, mpiwspxW3) \ + S_CbGrpprlProp(f, p1, cb, p2, p3, cw, mpiwspx) +#define CbGenPrl(pprop, ppropBase, sprm, rgb) \ + S_CbGenPrl(pprop, ppropBase, sprm, rgb) +#define CbGenChpxFromChp(pchpResult, pchp, pchpBase, fWord3) \ + S_CbGenChpxFromChp(pchpResult, pchp, pchpBase) +#define CbGenPapxFromPap(ppapx, ppap, ppapBase, fWord3) \ + S_CbGenPapxFromPap(ppapx, ppap, ppapBase) +#define ItcGetTcxCache(ww, doc, cp, ptap, itc, ptcx) \ + S_ItcGetTcxCache(ww, doc, cp, ptap, itc, ptcx) +#define ItcGetTcx(ww, ptap, itc, ptcx) \ + S_ItcGetTcx(ww, ptap, itc, ptcx) +#define FUpdateTable(ww, doc, h1, idr, pcp, pyp, h2, dl1, dl2, dl3, yp1, yp2, yp3, rc, f) \ + S_FUpdateTable(ww, doc, h1, idr, pcp, pyp, h2, dl1, dl2, dl3, yp1, yp2, yp3, rc, f) +#define FUpdTableDr(ww, hpldr, idr) \ + S_FUpdTableDr(ww, hpldr, idr) +#define FrameEasyTable(ww, doc, cp, hpldr, prclDrawn, pdr, dyl, f1, f2, f3, f4) \ + S_FrameEasyTable(ww, doc, cp, hpldr, prclDrawn, pdr, dyl, f1, f2, f3, f4) +#define RtfIn(hribl, pch, cch) \ + S_RtfIn(hribl, pch, cch) +#define ChMapSpecChar(ch, chs) \ + S_ChMapSpecChar(ch, chs) +#define FSearchRgrsym(sz, pirsym) \ + S_FSearchRgrsym(sz, pirsym) +#define ValFromPropSprm(prgbProps, sprm) \ + S_ValFromPropSprm(prgbProps, sprm) +#define XDelFndSedPgdPad(fPlan, pxbc, pxsr) \ + S_XDelFndSedPgdPad(fPlan, pxbc, pxsr) +#define PchSzRtfMove(iszRtf, pch) \ + S_PchSzRtfMove(iszRtf, pch) +#define FRepl1(pca, fn, fc, dfc) \ + S_FRepl1(pca, fn, fc, dfc) +#define FReplaceCps(pcaDel, pcaIns) \ + S_FReplaceCps(pcaDel, pcaIns) +#define XReplaceCps(fPlan, pxbc, pxsr) \ + S_XReplaceCps(fPlan, pxbc, pxsr) +#define WCompSzSrt(psz1,psz2,fCase) \ + S_WCompSzSrt(psz1,psz2,fCase) +#define WCompChCh(ch1, ch2) \ + S_WCompChCh(ch1, ch2) +#define WCompRgchIndex(hpch1, cch1, hpch2, cch2) \ + S_WCompRgchIndex(hpch1, cch1, hpch2, cch2) +#define IbstFindSzFfn(hsttb, pffn) \ + S_IbstFindSzFfn(hsttb, pffn) +#else /* !DEBUG */ +#define FetchCp(doc,cp,fcm) \ + N_FetchCp(doc,cp,fcm) +#define CachePara(doc,cp) \ + N_CachePara(doc,cp) +#define FormatLineDxa(ww,doc,cp,dxa) \ + N_FormatLineDxa(ww,doc,cp,dxa) +#define LoadFont(pchp, fWidth) \ + N_LoadFont(pchp, fWidth) +#define CpSearchSz(pbmib, cpFirst, cpLim, pcpNextRpt, pppr) \ + N_CpSearchSz(pbmib, cpFirst, cpLim, pcpNextRpt, pppr) +#define CpSearchSzBackward(pbmib, cpFirst, cpLim) \ + N_CpSearchSzBackward(pbmib, cpFirst, cpLim) +#define FfcFormatFieldPdcp(pdcp, ww, doc, cp, ch) \ + N_FfcFormatFieldPdcp(pdcp, ww, doc, cp, ch) +#define DcpSkipFieldChPflcd(ch, pflcd, fShowResult, fFetch) \ + N_DcpSkipFieldChPflcd(ch, pflcd, fShowResult, fFetch) +#define FShowResultPflcdFvc(pflcd, fvc) \ + N_FShowResultPflcdFvc(pflcd, fvc) +#define IfldFromDocCp(doc, cp, fMatch) \ + N_IfldFromDocCp(doc, cp, fMatch) +#define FillIfldFlcd(hplcfld, ifld, pflcd) \ + N_FillIfldFlcd(hplcfld, ifld, pflcd) +#define GetIfldFlcd(doc, ifld, pflcd) \ + N_GetIfldFlcd(doc, ifld, pflcd) +#define SetFlcdCh(doc, pflcd, ch) \ + N_SetFlcdCh(doc, pflcd, ch) +#define IfldInsertDocCp(doc, cp) \ + N_IfldInsertDocCp(doc, cp) +#define FetchVisibleRgch(pfvb, fvc, fProps, fNested) \ + N_FetchVisibleRgch(pfvb, fvc, fProps, fNested) +#define FetchCpPccpVisible(doc, cp, pccp, fvc, fNested) \ + N_FetchCpPccpVisible(doc, cp, pccp, fvc, fNested) +#define CpVisibleCpField(doc, cp, fvc, fIns) \ + N_CpVisibleCpField(doc, cp, fvc, fIns) +#define FVisibleCp(ww, doc, cp) \ + N_FVisibleCp(ww, doc, cp) +#define DisplayFliCore( ww, rcClip, xl, yl ) \ + N_DisplayFliCore( ww, rcClip, xl, yl ) +#define FMarkLine(psel, hpldr, idr, pedl, cpFirstSel, cpLimSel, cpFirstLine) \ + N_FMarkLine(psel, hpldr, idr, pedl, cpFirstSel, cpLimSel, cpFirstLine) +#define XpFromDcp(dcp1, dcp2, pxpFirst, pich) \ + N_XpFromDcp(dcp1, dcp2, pxpFirst, pich) +#define MapStc(pdod, stc, pchp, ppap) \ + N_MapStc(pdod, stc, pchp, ppap) +#define AddVisiSpaces(hdc, xpLine, ypLine, prcw) \ + N_AddVisiSpaces(hdc, xpLine, ypLine, prcw) +#define ApplyPrlSgc(hpprl, cch, prgbProps, sgc) \ + N_ApplyPrlSgc(hpprl, cch, prgbProps, sgc) +#define FGetParaState(fAll, fAbortOk) \ + N_FGetParaState(fAll, fAbortOk) +#define FGraphicsFcidToPlf(fcid, plf, fPrinterFont) \ + N_FGraphicsFcidToPlf(fcid, plf, fPrinterFont) +#define PnFromPlcbteFc(hplcbte, fc) \ + N_PnFromPlcbteFc(hplcbte, fc) +#define BFromFc(hpfkp, fc, pfcFirst, pfcLim, pifc) \ + N_BFromFc(hpfkp, fc, pfcFirst, pfcLim, pifc) +#define HpchFromFc(fn, fc) \ + N_HpchFromFc(fn, fc) +#define HpchGetPn(fn, pn) \ + N_HpchGetPn(fn, pn) +#define IbpCacheFilePage(fn, pn) \ + N_IbpCacheFilePage(fn, pn) +#define DoPrmSgc(prm, prgbProps, sgc) \ + N_DoPrmSgc(prm, prgbProps, sgc) +#define LoadFcidFull( fcid ) \ + N_LoadFcidFull( fcid ) +#define ResetFont(fPrinterFont) \ + N_ResetFont(fPrinterFont) +#define DisplayFli( ww, hpldr, idr, dl, ypLine ) \ + N_DisplayFli( ww, hpldr, idr, dl, ypLine ) +#define FormatLine( ww, doc, cp ) \ + N_FormatLine( ww, doc, cp ) +#define FormatLineDr( ww, cp, pdr ) \ + N_FormatDrLine( ww, cp, pdr ) +#define FAddRun(fn, fc, pch, cch, pfkpd, fPara, fAllocMac, fPlcMustExp, fWord3) \ + N_FAddRun(fn, fc, pch, cch, pfkpd, (fPara << 2) + (fAllocMac << 1) + fPlcMustExp) +#define AddRun(fn, fc, pch, cch, pfkpd, fPara, fAllocMac, fPlcMustExp, fWord3) \ + N_FAddRun(fn, fc, pch, cch, pfkpd, (fPara << 2) + (fAllocMac << 1) + fPlcMustExp) +#define WriteRgchToFn(fn, pch, cch) \ + N_ScanFnForBytes(fn, (char HUGE *)pch, cch, fTrue /* fWrite */) +#define ReadRgchFromFn(fn, pch, cch) \ + N_ScanFnForBytes(fn, (char HUGE *)pch, cch, fFalse /* fWrite */) +#define WriteHprgchToFn(fn, hpch, cch) \ + N_ScanFnForBytes(fn, hpch, cch, fTrue /* fWrite */) +#define ReadHprgchFromFn(fn, hpch, cch) \ + N_ScanFnForBytes(fn, hpch, cch, fFalse /* fWrite */) +#define FInTableDocCp(doc, cp) \ + N_FInTableDocCp(doc, cp) +#define AdjustCp(pca, dcpIns) \ + N_AdjustCp(pca, dcpIns) +#define IbpLru() \ + N_IbpLru() +#define ClFormatLines(plbs, cpLim, dylFill, dylMax, clLim, dxl, f1, f2) \ + N_ClFormatLines(plbs, cpLim, dylFill, dylMax, clLim, dxl, f1, f2) +#define CacheParaL(doc, cp, fOutline) \ + N_CacheParaL(doc, cp, fOutline) +#define CacheSectL(doc, cp, fOutline) \ + N_CacheSectL(doc, cp, fOutline) +#define FAbortLayout(fOutline, plbs) \ + N_FAbortLayout(fOutline, plbs) +#define PdrFetch(hpldr, idr, pdrf) \ + N_PdrFetch(hpldr, idr, pdrf) +#define PdrFetchAndFree(hpldr, idr, pdrf) \ + N_PdrFetchAndFree(hpldr, idr, pdrf) +#define PdrFreeAndFetch(hpldr, idr, pdrf) \ + N_PdrFreeAndFetch(hpldr, idr, pdrf) +#define FreePdrf(pdrf) \ + N_FreePdrf(pdrf) +#define PtOrigin(hpldr, idr) \ + N_PtOrigin(hpldr, idr) +#define GetCpFirstCpLimDisplayPara(ww, doc, cp, pcpFirst, pcpLim) \ + N_GetCpFirstCpLimDisplayPara(ww, doc, cp, pcpFirst, pcpLim) +#define CpFormatFrom(ww, doc, cp) \ + N_CpFormatFrom(ww, doc, cp) +#define CpVisibleBackCpField(doc, cp, fvc) \ + N_CpVisibleBackCpField(doc, cp, fvc) +#define FAssignLr(plbs, dylFill, fEmptyOK) \ + N_FAssignLr(plbs, dylFill, fEmptyOK) +#define FWidowControl(plbs, plbsNew, dylFill, fEmptyOK) \ + N_FWidowControl(plbs, plbsNew, dylFill, fEmptyOK) +#define IfrdGatherFtnRef(plbs, plbsNew, ifrd, fNormal, ylReject, ylAccept) \ + N_IfrdGatherFtnRef(plbs, plbsNew, ifrd, fNormal, ylReject, ylAccept) +#define FGetFtnBreak(plbs, ifrl, pfrl, fpc) \ + N_FGetFtnBreak(plbs, ifrl, pfrl, fpc) +#define CopyHdtLrs(ihdt, plbs, yl, plbsAbs) \ + N_CopyHdtLrs(ihdt, plbs, yl, plbsAbs) +#define CopyLrs(hpllrFrom, plbsTo, ilrMac, yl, fCopyIgnore, xl) \ + N_CopyLrs(hpllrFrom, plbsTo, ilrMac, yl, fCopyIgnore, xl) +#define ReplaceInPllr(hpllr, ilr, plr) \ + N_ReplaceInPllr(hpllr, ilr, plr) +#define PushLbs(plbsFrom, plbsTo) \ + N_PushLbs(plbsFrom, plbsTo) +#define PopLbs(plbsId, plbsTo) \ + N_PopLbs(plbsId, plbsTo) +#define CopyLbs(plbsFrom, plbsTo) \ + N_CopyLbs(plbsFrom, plbsTo) +#define LbcFormatPara(plbs, dylFill, clLim) \ + N_LbcFormatPara(plbs, dylFill, clLim) +#define FUpdateDr(ww, hpldr, idr, rcwInval, fAbortOK, udmod, cpUpd) \ + N_FUpdateDr(ww, hpldr, idr, rcwInval, fAbortOK, udmod, cpUpd) +#define ScrollDrUp(ww, hpldr, idr, h2, dlFrom, dlTo, yp1, yp2, yp3, yp4) \ + N_ScrollDrUp(ww, hpldr, idr, h2, dlFrom, dlTo, yp1, yp2, yp3, yp4) +#define MiscPlcLoops(hplc, iFirst, iLim, pResult, wRoutine) \ + N_MiscPlcLoops(hplc, iFirst, iLim, pResult, wRoutine) +#define FFillRgwWithSeqLevs(doc, cp, ipad, ifld, hplcpad, hplcfld, rgw) \ + N_FFillRgwWithSeqLevs(doc, cp, ipad, ifld, hplcpad, hplcfld, rgw) +#define WidthHeightFromBrc(brc, grpf) \ + N_WidthHeightFromBrc(brc, grpf) +#define PxsInit(pxs, ixsMax, pxbc) \ + N_PxsInit(pxs, ixsMax, pxbc) +#define PostTn(pxbc, tnt, h, c) \ + N_PostTn(pxbc, tnt, h, c) +#define FDoTns(pxbc) \ + N_FDoTns(pxbc) +#define CloseTns(pxbc) \ + N_CloseTns(pxbc) +#define FReplace(pca, fn, fc, dfc) \ + N_FReplace(pca, fn, fc, dfc) +#define XReplace(fPlan, pxbc, pxsr) \ + N_XReplace(fPlan, pxbc, pxsr) +#define IpcdSplit(hplcpcd, cp) \ + N_IpcdSplit(hplcpcd, cp) +#define XRepl1(fPlan, pxbc, pxsr) \ + N_XRepl1(fPlan, pxbc, pxsr) +#define InvalCaFierce() \ + N_InvalCaFierce() +#define FCpVisiInOutline(ww, doc, cp, ccp, pcpFirstInvisi) \ + N_FCpVisiInOutline(ww, doc, cp, ccp, pcpFirstInvisi) +#define DrawInsertLine(psel) \ + N_DrawInsertLine(psel) +#define FInsertInPlc(hplc, i, cp, pch) \ + N_FInsertInPlc(hplc, i, cp, pch) +#define FOpenPlc(hplc, i, di) \ + N_FOpenPlc(hplc, i, di) +#define ShrinkPlc(hplc, iMaxNew, i, di) \ + N_ShrinkPlc(hplc, iMaxNew, i, di) +#define FStretchPlc(hplc, di) \ + N_FStretchPlc(hplc, di) +#define FNewChpIns(doc, cp, pchp, stc) \ + N_FNewChpIns(doc, cp, pchp, stc) +#define FInsertRgch(doc, cp, rgch, cch, pchp, ppap) \ + N_FInsertRgch(doc, cp, rgch, cch, pchp, ppap) +#define FcAppendRgchToFn(fn, pch, cch) \ + N_FcAppendRgchToFn(fn, pch, cch) +#define CbGrpprlProp(f, p1, cb, p2, p3, cw, mpiwspx, mpiwspxW3) \ + N_CbGrpprlProp(f, p1, cb, p2, p3, cw, mpiwspx) +#define CbGenPrl(pprop, ppropBase, sprm, rgb) \ + N_CbGenPrl(pprop, ppropBase, sprm, rgb) +#define CbGenChpxFromChp(pchpResult, pchp, pchpBase, fWord3) \ + N_CbGenChpxFromChp(pchpResult, pchp, pchpBase) +#define CbGenPapxFromPap(ppapx, ppap, ppapBase, fWord3) \ + N_CbGenPapxFromPap(ppapx, ppap, ppapBase) +#define ItcGetTcxCache(ww, doc, cp, ptap, itc, ptcx) \ + N_ItcGetTcxCache(ww, doc, cp, ptap, itc, ptcx) +#define ItcGetTcx(ww, ptap, itc, ptcx) \ + N_ItcGetTcx(ww, ptap, itc, ptcx) +#define FUpdateTable(ww, doc, h1, idr, pcp, pyp, h2, dl1, dl2, dl3, yp1, yp2, yp3, rc, f) \ + N_FUpdateTable(ww, doc, h1, idr, pcp, pyp, h2, dl1, dl2, dl3, yp1, yp2, yp3, rc, f) +#define FUpdTableDr(ww, hpldr, idr) \ + N_FUpdTableDr(ww, hpldr, idr) +#define FrameEasyTable(ww, doc, cp, hpldr, prclDrawn, pdr, dyl, f1, f2, f3, f4) \ + N_FrameEasyTable(ww, doc, cp, hpldr, prclDrawn, pdr, dyl, f1, f2, f3, f4) +#define RtfIn(hribl, pch, cch) \ + N_RtfIn(hribl, pch, cch) +#define ChMapSpecChar(ch, chs) \ + N_ChMapSpecChar(ch, chs) +#define FSearchRgrsym(sz, pirsym) \ + N_FSearchRgrsym(sz, pirsym) +#define ValFromPropSprm(prgbProps, sprm) \ + N_ValFromPropSprm(prgbProps, sprm) +#define XDelFndSedPgdPad(fPlan, pxbc, pxsr) \ + N_XDelFndSedPgdPad(fPlan, pxbc, pxsr) +#define PchSzRtfMove(iszRtf, pch) \ + N_PchSzRtfMove(iszRtf, pch) +#define FRepl1(pca, fn, fc, dfc) \ + N_FRepl1(pca, fn, fc, dfc) +#define FReplaceCps(pcaDel, pcaIns) \ + N_FReplaceCps(pcaDel, pcaIns) +#define XReplaceCps(fPlan, pxbc, pxsr) \ + N_XReplaceCps(fPlan, pxbc, pxsr) +#define WCompSzSrt(psz1,psz2,fCase) \ + N_WCompSzSrt(psz1,psz2,fCase) +#define WCompChCh(ch1, ch2) \ + N_WCompChCh(ch1, ch2) +#define WCompRgchIndex(hpch1, cch1, hpch2, cch2) \ + N_WCompRgchIndex(hpch1, cch1, hpch2, cch2) +#define IbstFindSzFfn(hsttb, pffn) \ + N_IbstFindSzFfn(hsttb, pffn) +#endif /* !DEBUG */ + +/* Temporary macros to eliminate IInPlcMult, IInPlc2Mult */ +#define IInPlcMult(hplc, cp) \ + IInPlc(hplc, cp) +#define IInPlc2Mult(hplc, cp, iFirst) \ + IInPlc2(hplc, cp, iFirst) +/* Macros to get rid of unneeded argument in DxaFromDxp, DxpFromDxa for WIN */ +#define DxaFromDxp(pwwd, dxp) \ + N_DxaFromDxp(dxp) +#define DxpFromDxa(pwwd, dxa) \ + N_DxpFromDxa(dxa) +/* Macro to get rid of assembler error message in resident.asm */ +#define abs(x) N_abs(x) + +/* D E B U G */ +/* Debug and Debug0 are just ways to make an expression conditional */ +/* used for assignment to j variables e.g. Debug(vjClip = jClipWw) */ +/* Debug0 is useful when null expression disallowed, as in the use + of comma operator in pic.c e.g., if ((Debug(i=2), foo)) +*/ + +#ifdef DEBUG +#define Debug(e) e +#define Debug0(e) e +#else +#define Debug(e) +#define Debug0(e) 0 +#endif + +/* B A T C H */ +/* Batch mode code is defined under #ifdef BATCH, so it can be used */ +/* in non-debug versions. In the debug version, BATCH is always defined, */ +/* but in non-debug versions BATCH must be supplied as an explicit compile */ +/* flag. */ +#ifdef DEBUG +#define BATCH +#endif + +/* Batch is similar to the Debug conditional expression macro */ +#ifdef BATCH +#define Batch(e) e +#else +#define Batch(e) +#endif + +/* M A R K */ +/* call MarkProc conditionally */ +#ifdef DEBUG +#define Mark(e) MarkProc(e) +#else +#define Mark(e) +#endif + +/* F R A R E T */ +/* identifies a value that is rarely true, but if vjRare is set to +the identifying number, a true value will be substituted for testing +purposes. +*/ +#ifdef DEBUG +#define FRareT(n, f) ((f) || FRareProc(n)) +#else +#define FRareT(n, f) (f) +#endif + +/* F R A R E F */ +/* as above, except the value is rarely false. +*/ +#ifdef DEBUG +#define FRareF(n, f) ((f) && !FRareProc(n)) +#else +#define FRareF(n, f) (f) +#endif + +/* E R R O R S */ + +#ifdef DEBUG /* ERRORSTRINGS */ +#define DiskError(idpmt, fn, msg) DiskErrorProc(idpmt, fn, SzShared(msg)) +#else +#define DiskError(idpmt, fn, msg) DiskErrorProc(idpmt, fn) +#endif + +#define SetErrorMat(mat) SetErrorMatProc(mat) + + + +/* C A T E M P */ +#ifdef DEBUG +#define AcquireCaAdjust() { extern int cCaAdjust; ++cCaAdjust; \ + Assert (caAdjust.doc == docNil); \ + Assert (cCaAdjust == 1); } +#define ReleaseCaAdjust() { extern int cCaAdjust; --cCaAdjust; \ + Assert (cCaAdjust == 0); \ + caAdjust.doc = docNil; } +#define AcquireCaAdjustL() { extern int cCaAdjustL; ++cCaAdjustL; \ + Assert (caAdjustL.doc == docNil); \ + Assert (cCaAdjustL == 1); } +#define ReleaseCaAdjustL() { extern int cCaAdjustL; --cCaAdjustL; \ + Assert (cCaAdjustL == 0); \ + caAdjustL.doc = docNil; } +#else +#define AcquireCaAdjust() +#define ReleaseCaAdjust() +#define AcquireCaAdjustL() +#define ReleaseCaAdjustL() +#endif + +/* D O C S C R A T C H */ +#ifdef DEBUG +extern BOOL fDocScratchInUse; +#define ReleaseDocScratch() Assert (!(fDocScratchInUse = !fDocScratchInUse)) +#else +#define ReleaseDocScratch() +#endif /* DEBUG */ + +/* S T A T I C */ +/* STATIC is a way of declaring a procedure that we will only reference within */ +/* a module, but whose symbol we don't want to hide from the debugger. */ +#ifdef DEBUG +#define STATIC +#else +#define STATIC static +#endif + + + +#ifdef DEBUG + +#define dbctFli 0 +#define dbctDisplay 1 +#define dbctLr 2 + +#define cTestsPrefs 36 +#define pchTestMin ((char *)&vdbs.fCkDoc) +#define pchPrefMin ((char *)&vdbs.fCommSz) +#define pchUseCMin ((char *)&vdbs.CFetchCp) + +#define cchDbgBuf1 320 +#define cchDbgBuf2 80 + +#define nDbsuVerCur 7 + +struct DBS /* DeBug State */ + { + struct DBSU + /* This structure forms the stored file, it must be first */ + { + /* version */ +/* 0 */ int nDbsuVer; + + /* Consistency checking routine "on/off" switches */ +/* 2 */ char fCkDoc;/* must be first */ + char fCkFn; + char fCkWw; + char fCkBptb; + + char fCkFkp; + char fCkPlcbte; +/* 8 */ char fCkFli; + char fCkScc; + + char fCkPrm; + char fCkDlg; + char fCkHeap; + char fShakeHeap; + + char fCkStruct; + char fCkFont; +/* 10 */ char fCkMwd; + char fCk16; + + char fCkFldDel; + char fCkFldIdle; + char fCkLHRUpd; + char fCkScroll; /* see scroll.c */ + + char fCkPaph; + char fCkText; +/* 18 */ char fCkTlbx; + char fCkTableSel; +#define cTestsUsed 24 + + char fCk25; + char fCk26; + char fCk27; + char fCk28; + + char fCk29; + char fCk30; +/* 20 */ char fCk31; + char fCk32; + + char fCk33; + char fCk34; + char fCk35; + char fCk36; + + + /* debugging preferences */ + char fCommSz; /* must be first */ + char fMoreComm; +/* 28 */ char fRipToDbgScreen; + char fRetryDef; + + char fReports; + char fRipOnError; + char fFailInMcr; + char fReportHeap; + + char fFixedMem; + char fOutsideCmd; +/* 30 */ char fHeapAct; + char fWinAct; + + char fTraceGDI; + char fNoCoreLoad; + char fNoInfoRTF; + char fFail8087; + + char fCommDde1; + char fCommDde2; +/* 38 */ char fNoEmm; + char fBreakOnFail; + + char fNoFillBlock; + char fCallSetFlm; + char fCommPrint; + char fCoverActive; + + char fShowDirty; + char fCompressOften; /* causes compression to occur more often */ +/* 40 */ char fTrackGdiHandles; + char fUseTextOut; /* Use TextOut instead of ExtTextOut() */ + + char fShowLbs; /* show layout rectangles during layout process */ + char fSmallFileCache; /* File cache same size as if no EMM */ + char fNoRtfConv; + char fAllGraphicsBands; /* Mark all bands as graphics bands */ + + char fExtTextOutNull; /* Use ExtTextOut() but make extra values null */ + char fDumpMessages; /* Output messages in wprocn.asm */ +/* 48 */ char fVerboseHeapInfo; + char fDumpPicInfo; +#define cPrefsUsed 36 + + + /* use C versions flags */ +/* 4A */ char CFetchCp; /* must be first */ + char CCachePara; + char CFormatLine; + char CLoadFont; + + char CCpSearchSz; + char CCpSearchSzBackward; +/* 50 */ char CFfcFormatField; + char CDcpSkipFieldChPflcd; + + char CFShowResultPflcdFvc; + char CIfldFromDocCp; + char CFillIfldFlcd; + char CGetIfldFlcd; + + char CSetFlcdCh; + char CIfldInsertDocCp; +/* 58 */ char CFetchVisibleRgch; + char CFetchCpPccpVisible; + + char CCpVisibleCpField; + char CFVisibleCp; + char CDisplayFliCore; + char CFMarkLine; + + char CXpFromDcp; + char CMapStc; +/* 60 */ char CAddVisiSpaces; + char CApplyPrlSgc; + + char CFGetParaState; + char CFGraphicsFcidToPlf; + char CPnFromPlcbteFc; + char CBFromFc; + + char CHpchFromFc; + char CHpchGetPn; +/* 68 */ char CIbpCacheFilePage; + char CDoPrmSgc; + + char CLoadFcidFull; + char CFDisplayFli; + char CResetFont; + char unused2; +#define cUseCUsed 36 + + /* scribbles */ + int grpfScribble; + +/* 70 */ int rgwSpare [4]; + + /* end stored part of DBS */ + }; + + /* Following are session based only */ + + /* allocation failure control */ + /* code in initwin.c depends on the order of these */ + int cLmemSucceed; + int cLmemFail; + int cWinSucceed; + int cWinFail; + int cLmemCalls; + int cWinCalls; + + int fInfoAssert; /* RTF */ + int fSprmTablesChecked; + int StatLine; + int cdlInval; + int fScan; /* true iff scanning dialogs */ + /* number of lines output to provide debugging status info. + Needed to implement scrolling when outputting status info. */ + int jc1; + int jnScc; /* Scc test number to skip to */ + int fJoinBelow; /* return value from CheckSccs */ + int fJoinAbove; /* return value from CheckSccs */ + /* global stuff to be used with the debugging file read routines */ + FC fcCur; + int osfn; + char stRoutineName[30]; + char stFile[256]; + int fFlushFailed; + + int cbHeapWantedCmd;/* amount of heap wanted for cmd */ + VOID **hDebug;/* heap pointer to wasted heap */ + + /* used to turn off an assert in CkPbptb during quicksave. */ + int fQuicksave; + + /* More failures; stuck at the end to avoid mass make */ + int cBkgndSucceed; + int cBkgndFail; + }; + +extern struct DBS vdbs; +extern int cHpFreeze; +#endif /* DEBUG */ + +#ifdef WIN +typedef struct _aob + { + char aot; + char ifr; + int x, y; + int irgb; + int dxMove; + int dyMove; + int ddy; + int yGuess; + union + { + struct + { + int xGuess; + char dx, dy; + }; + + struct + { + char * st; + int spare; + }; + }; + } AOB; + +#define iaobMax 50 +#endif + +#ifdef BATCH +extern BOOL vfBatchMode; +extern CHAR szBatchString[]; +extern BOOL vfBatchIdle; +#endif /* BATCH */ + +/* R A R E E V E N T S */ + +#ifdef DEBUG +#define reNULL 0 /* RESERVED */ +#define reMemAlert 1 /* used in UpdateWw */ +#define reChngSizeH 2 /* used in FExpandGrpchr */ +#define reMsgPresent1 4 /* used in UpdateWw */ +#define reMsgPresent2 5 /* used in UpdateWw */ +#define reExpandPbmi 27 /* used in FExpandPbmi - can't create bitmap */ +#define reMemAlert1 55 /* used in DocCreateSub */ +#define reMemAlert2 56 /* used in DocCreateSub */ +#define reMemAlert3 57 /* used in DocCreateSub */ +#define reMemAlert4 58 /* used in FChangeAll */ +#define reMemAlert5 59 /* used in CpDoReplace */ +#define reMemAlert6 60 /* used in CpDoReplace */ +#define reMemAlert7 61 /* used in DlgfSearchRepl */ +#define reOpenPlc 123 /* used in AddToHplcEdit */ +#define rePchrNew 324 /* used in FNewChrfChr */ +#define reRibbon 100 /* allocation failure in ribbon */ +#define reRuler 101 /* allocation failure in ruler */ + +/* Rare Event Codes for Save */ +#define reNoSaveHeaders 500 /* could not build superdoc */ +#define reNoSaveTemp 501 /* could not create temp file to save to */ +#define reNoRenameTemp 502 /* could not rename temp file to dest name */ +#define reNoAccessBak 503 /* could not open/delete file that's in the way of the save */ +#define reNoRenameToBak 504 /* could not rename file to .BAK/.TMP */ +#define reNoDelBak 505 /* could not delete old .BAK */ + +/* Rare Event Codes for GDI failure */ + +#define reMiscGDI 600 +#define reGetDC 601 +#define reSelectObject 602 +#define reSaveDC 603 + +#define RareEventMax 10 /* count of concurrent rare events */ + +typedef struct + { + int wEventNumber; /* identifier of event */ + int wRepetitionsMac; /* stop repetition count */ + int wRepetitions; /* current repetition count */ + int fOn; /* count on/off flag */ + } ARG_RAREEVENTS; + +#endif /* DEBUG */ + +/* P R O F I L I N G */ + +#ifdef PROFILE +#define Profile(x) x +extern int vpfi; +#define StartProf(n) (PcodeStartProfiler(),StartProfiler(n,NULL)) +#define StopProf() (StopProfiler(),PcodeStopProfiler()) +#else /* NO PROFILE */ +#define Profile(x) +#define StartProf(n) +#define StopProf() +#undef StartUMeas +#undef StopUMeas +#define StartUMeas(n) +#define StopUMeas(n) +#undef StartProfiler +#undef StopProfiler +#define StartProfiler(n,m) +#define StopProfiler() +#endif /* NO PROFILE */ + +/* profile id's -- allow profiling of major events based on vdbs.pfi */ + +#define pfiInit 0 /* FInitWinInfo */ +#define pfiScroll 1 /* scrolling */ +#define pfiParaDlg 2 /* bringing up paragraph dialog */ +#define pfiTyping 3 /* typing */ +#define pfiSearch 4 /* Cmd Search */ +#define pfiReplace 5 /* Cmd Replace */ +#define pfiPgUp 6 /* Key Curs PgUp */ +#define pfiDebugUpdateRuler 7 /* testing ruler updates */ +#define pfiDebugFieldsDisplay 8 /* testing fields display */ +#define pfiCpSearchSz 9 /* low level search */ +#define pfiMenu 10 /* drop down menu */ +#define pfiFieldRef 11 /* Refresh of fields */ +#define pfiPictDrag 12 /* drag the picture with mouse */ +#define pfiPictDraw 13 /* draw a pic */ +#define pfiPictFmt 14 /* get pic info for formatting */ +#define pfiPictPaste 15 /* paste a pict */ +#define pfiRepag 16 /* CmdRepaginateNow */ +#define pfiInitCmds 17 /* initialize commands */ + +#define pfiSaveFile 40 /* SaveFile */ +#define pfiPromptProf 41 +#define pfiUntitled 42 + +/* User-defined measurement codes */ + +#ifdef PROFILE +#define umTextOut 201 +#define umSelectFont 202 +#define umPeekMessage 203 +#define umGetMessage 204 +#define umCreatePrinterDC 205 +#define umBitBlt 206 +#define umCreateBitmap 207 +#define umRuler1 211 +#define umRuler2 212 +#define umRuler3 213 +#define umRuler4 214 +#define umRuler5 215 +#define umRuler6 216 +#define umField1 221 +#define umField2 222 +#define umField3 223 +#define umOsDateTime 240 +#define umSavePrompt 241 +#define umGetCodeHandle 242 +#define umGlobalLru 243 +#define umAssignFnFc1 250 +#define umAssignFnFc2 251 +#define umAssignFnFc3 252 +#define umPmtRelDC 260 +#define umPmtETO2 261 +#define umPmtGCR 262 +#define umPmtETO 263 +#define umGetMenuStr 270 +#define umChangeMenu 271 +#define umScanFnForBytes 272 +#define umPromptCreateWin 273 +#define umPromptUpdateWin 274 +#define umStatlineTextOut 275 +#define umStatlineDestroy 276 +#define umFileRead 280 +#define umFileWrite 281 +#define umNormPath 291 +#endif + + +#ifdef DEBUG +/* Do-nothing functions, for breakpointing */ +int Dummy(); +NATIVE NatDummy(); +#endif + +#ifndef DEBUG +#ifdef PCJ +#undef PCJ +#endif +#endif + +#ifdef DEBUG +extern int vfInDebug; +#define EnterDebug() (vfInDebug++) +#define ExitDebug() (vfInDebug--) +#else +#define EnterDebug() +#define ExitDebug() +#endif /* DEBUG */ + +/* G D I H A N D L E T R A C K I N G */ + +#ifdef DEBUG +#ifndef NOVHGDIS +extern int vhgdis; +#endif /* NOVHGDIS */ +#define LogGdiHandle(hGdi,wId) (vhgdis ? LogGdiHandleProc(hGdi,wId) : 0) +#define UnlogGdiHandle(hGdi,wId) (vhgdis ? UnlogGdiHandleProc(hGdi,wId) : 0) +#else +#define LogGdiHandle(hGdi,wId) +#define UnlogGdiHandle(hGdi,wId) +#endif /* DEBUG */ + +#ifdef RSH +#ifdef RSHDEFS +extern int vfnUa; + +#define uaCursor 0x2000 +#define uaCursExtend 0x3000 +#define uaLooksKey 0x5000 +#define uaDragMark 0x6000 +#define uaAppMessage 0x7400 +#define uaMwdMessage 0x7800 +#define uaWwdMessage 0x7C00 +#define uaAppCommand 0x8400 +#define uaMwdCommand 0x8800 +#define uaWwdCommand 0x8C00 +#define uaKeyState 0x9000 + +#define uaBcmFollows 0xf001 +#define uaTimesFollow 0xf002 + +#define uaCxtHelp 0x0000 +#define uaTempMacro 0x0001 +/* #define uaGlobalMacro 0x0002 */ +#define uaInsert 0x0003 +#define uaCancelOrError 0x0004 +#define uaIBDlgGetFocus 0x0005 +#define uaIBDlgLoseFocus 0x0006 +#define uaBackspace 0x0007 +#define uaApplyStyleIb 0x0008 +#define uaFontPtIb 0x0009 +#define uaQuickSave 0x000a +#define uaFullSave 0x000b +#define uaIdle 0x000c +#define uaStartDialogSession 0x000d +#define uaStopDialogSession 0x000e + + +/* timing values */ + +#define uamNull -1 +#define uamIdle 0 +#define uamCommand 1 +#define uamNavigation 2 +#define uamTyping 3 +#define uamMax 4 + +#define uasMenu 0 +#define uasDialogOvrhd 1 +#define uasDialogSession 2 +#define uasMax 3 + +struct UAT /* user action timer */ + { + int uam; /* user action mode */ + long msecStartMode; /* time entered this mode */ + long msecTimeout; /* time to enter idle mode */ + long msecStopped; /* time timer was stopped (0 if running) */ + long msecNextReport;/* time to log next report */ + long msecSessionStart; /* time this WinWord session begun */ + long mpuammsec[uamMax]; /* total times for each mode */ + long mpuasmsec[uasMax]; /* total times for sub-timers */ + long mpuasmsecStarted[uasMax]; /* when running, time sub-timer was started */ + }; + +#define msecModeTimeout (3*1000L) +#define msecReports (5*60*1000L) + +extern struct UAT vuat; + +#endif /* RSHDEFS */ +#endif /* RSH */ diff --git a/src/Opus/DLBENUM.C b/src/Opus/DLBENUM.C new file mode 100644 index 0000000..77cfb17 --- /dev/null +++ b/src/Opus/DLBENUM.C @@ -0,0 +1,219 @@ +/****************************************************************************** +** +** COPYRIGHT (C) 1987 MICROSOFT +** +******************************************************************************* +** +** Module: dlbenum.c --- Drop-Down List Box enumeration function +** +** Functions included: +** +** REVISIONS +** +** Date Who Rel Ver Remarks +** 4/17/87 yxy Original +** 5/28/87 bac Put the strings in CS too +** +*****************************************************************************/ + +#define NOMINMAX +#define NOBRUSH +#define NOICON +#define NOPEN +#define NOGDICAPMASKS +#define NOVIRTUALKEYCODES +#define NOSYSMETRICS +#define NOCLIPBOARD +#define NOKEYSTATE +#define NORASTEROPS +#define NOSHOWINDOW +#define NOCREATESTRUCT +#define NODRAWTEXT +#define NOMB +#define NOMEMMGR +#define NOMETAFILE +#define NOWH +#define NOWNDCLASS +#define NOREGION +#define NOSOUND +#define NOCOMM + +#include "word.h" +DEBUGASSERTSZ /* WIN - bogus macro for assert string */ +#include "debug.h" + +#include "dlbenum.h" + +#ifdef OPUS_X64 +/* This table is consumed only through CopyEntblToSz. Keep source labels as + * ordinary native literals and convert at that boundary. */ +#undef StKey +#undef StShared +#undef StSharedKey +#define StKey(text, key) text +#define StShared(text) text +#define StSharedKey(text, key) text +#endif + +csconst ENTBL rgEntbl[] = { + { + cFNPos, + /* Must correspond to ordering of fpc in DOP */ + { + StKey("End of Section",NoteEndSec), + StKey("Bottom of Page",NoteBottom), + StKey("Beneath Text",NoteBeneath), + StKey("End of Document",NoteEndDoc) + } + }, + { + cSkt, + /* WARNING: these must agree with + the skt's in sort.h in + number and order; update cSkt + in sort.h and rgstSkt in sort.c + if you add more */ + { + StKey("Alphanumeric",SortAlphanumeric), + StKey("Numeric",SortNumeric), + StKey("Date",SortDate) + } + }, + { + cDffSave, + /* Must correspond to dffSave order in filecvt.h */ + { + StKey("Normal",SaveNormal), + StKey("Document Template",SaveTemplate), + StKey("Text Only",SaveText), + StKey("Text+breaks",SaveTextBreaks), + StKey("Text Only (PC-8)",SaveText8), + StKey("Text+breaks (PC-8)",SaveText8Breaks), + StKey("RTF",RTF) + } + }, + { /* page number format */ + /* If you change this ordering, also change + mpnfcipg and mpipgnfc in hddwin.c */ + cNfc, + { + StShared("1 2 3..."), + StShared("a b c..."), + StShared("A B C..."), + StShared("i ii iii..."), + StShared("I II III...") + } + }, + { /* Catalog Sort Factor */ + cCatSort, + { + StKey("Name",SortName), + StKey("Author",SortAuthor), + StKey("Creation Date",SortCreateDate), + StKey("Last Saved Date",SortSaveDate), + StKey("Last Saved by",SortSaveBy), + StKey("Size",SortSize) + } + }, + { /* print source */ + cPrSrc, + /* must correspond to ordering in print.h */ + { + StKey("Document",PrintDoc), + StKey("Summary Info",PrintSummary), + StKey("Annotations",PrintAnnotations), + StKey("Styles",PrintStyles), + StKey("Glossary",PrintGlsy), + StKey("Key Assignments",PrintKeys) + } + }, + { /* print feed */ + /* must correspond to iidBin ordering in print.h */ + cPrFeed, + { + StKey("Manual",PrintBinManual), + StKey("Envelope",PrintBinEnvelope), + StKey("Tractor",PrintBinTractor), + StKey("Auto",PrintBinAuto), + StKey("Bin 1",PrintBin1), + StKey("Bin 2",PrintBin2), + StKey("Bin 3",PrintBin3), + StKey("Mixed",PrintMixed) + } + }, + { /* FileOpen converter names */ + /* order must correspond to dffOpen in filecvt.h */ + cDffOpen, + { + StSharedKey("Text",OpenText), + StSharedKey("Text (PC-8)",OpenText8), + StShared("RTF"), + StShared("BIFF (Excel 2.X)"), + StShared("Multiplan 3.0"), + StShared("WKS") + } + }, + { + cBrclTable, + /* For table borders (all except outline) */ + { + StKey("None",BrclNone), + StKey("Single",BrclSingle), + StKey("Thick",BrclThick), + StKey("Double",BrclDouble), + } + }, + +}; + + +/* %%Function: CopyEntblToSz %%Owner: bobz */ + +CopyEntblToSz(iEntbl, isz, sz) +int iEntbl; +int isz; +CHAR *sz; +{ + CHAR FAR *lpch; + + Assert(isz < rgEntbl[iEntbl].iMax && iEntbl < iEntblMax); + + #ifdef OPUS_X64 + strcpy(sz, rgEntbl[iEntbl].rgst[isz]); + #else + bltbx((CHAR FAR *) (rgEntbl[iEntbl].rgst[isz]), (CHAR FAR *) sz, + rgEntbl[iEntbl].rgst[isz][0]+1); + StToSzInPlace(sz); + #endif +} + + +/* %%Function: FEnumIEntbl %%Owner: bobz */ + +BOOL FEnumIEntbl(iEntbl, isz, sz) +int iEntbl; +int isz; +CHAR *sz; +{ + Assert(iEntbl < iEntblMax); + + if (isz < rgEntbl[iEntbl].iMax) + { + CopyEntblToSz(iEntbl, isz, sz); + return (fTrue); + } + else + { + return (fFalse); + } + +} + + +#ifdef PROFILE +/* this is here so that appended native code does not appear in previous + function in pcode profiles. */ +Dlbenum_Last(){} +#endif /* PROFILE */ + +/* ADD NEW CODE *ABOVE* Dlbenum_Last() */ diff --git a/src/Opus/EDIT.C b/src/Opus/EDIT.C new file mode 100644 index 0000000..baf8ce7 --- /dev/null +++ b/src/Opus/EDIT.C @@ -0,0 +1,2750 @@ +/* E D I T . C */ + +#ifdef PCJ +/* #define SHOWCPMAC */ +#endif /* PCJ */ + +#define SCREENDEFS +#include "word.h" +DEBUGASSERTSZ /* WIN - bogus macro for assert string */ +#include "heap.h" +#include "disp.h" +#include "doc.h" +#include "props.h" +#include "border.h" +#include "sel.h" +#include "ch.h" +#include "scc.h" +#include "format.h" +#include "prm.h" +#include "ruler.h" +#include "layout.h" +#include "file.h" +#include "debug.h" +#include "cmd.h" +#include "error.h" +#include "message.h" + +#ifdef WIN +#include "dde.h" +#include "idle.h" +#include "field.h" +#include "status.h" +#define REVMARKING +#include "compare.h" +#define AUTOSAVE +#include "autosave.h" +#define FINDNEXT +#include "search.h" +#endif /* WIN */ + + +/* E X T E R N A L S */ + +extern struct CA caHdt; +extern int vdocHdrEdit; +extern struct CA caSect; +extern struct PAP vpapFetch; +extern struct DOD **mpdochdod[]; +extern struct SAB vsab; +extern struct SEP vsepFetch; +extern int wwMac; +extern struct MERR vmerr; +extern struct RULSS vrulss; +extern int vdocFetch; +extern struct DBS vdbs; +extern struct ESPRM dnsprm[]; + +#ifdef WIN +extern ASD asd; /* autosave descriptor. */ +extern int vdocScratch; +extern struct DDES vddes; +extern BOOL vfDdeIdle; +extern IDF vidf; +extern FNI fni; +extern struct FB vfbSearch; +#endif /* WIN */ + +#ifdef WIN +BOOL vfNoInval=0; /* can be > 1 */ +#else +#define vfNoInval fFalse +#endif /* WIN */ + +#ifdef OPUS_X64 +struct PLC **HplcCreateEdc(); +#else +struct PLC *HplcCreateEdc(); +#endif + + +/* TRANSACTION PROCEDURES: XFoo(fPlan, pxbc, pxs). + +Transactions are atomic operation which may be executed without failure or not +at all. They are implemented by "bifuricating" the procedure into a fPlan +phase and an execution (!fPlan) phase. In the former, a list of "intentions" +of using resources is created. At the end of the first phase, the list is +examined by FDoTns procedure which will check if it can reserve all of +the resources which will be needed and return fTrue iff successful. + + +If fPlan, only idempotent changes may be made, and a failure may be posted on +the intentions list at any time. Obviously planning operations +can not depend on any changes which are delayed until the !fPlan phase. +Useful quantities may be remembered in xs (xaction state) for the !fPlan phase. + +If !fPlan, changes may be made but they must not fail. Any allocations that +were accounted for during the fPlan phase can be asserted to succeed. No +allocations that were not accounted for should be attempted. + +Examples of idempotent operations: + Creation of empty subdocs + stretching of plc's (FStretchPlc) + invalidations: however it is inefficient to execute these twice! + allocating prc's (since they will be deleted) +Non-idempotent operations: + FOpenPlc (even deletions) + PutCpPlc + ... + +Always NOTE: code in XFoo procedures will be executed twice! +*/ + + +BOOL vfInCommit = fFalse; + +#define BeginCommit() AssertDo(!vfInCommit++) +#define EndCommit() AssertDo(!--vfInCommit) + +/* Xaction declarations */ + +#define tntNil 0 +#define tntHplc 1 +#define tntHsttb 2 +#define tntAbort 3 +#define tntCloseHdrWw 4 +#define tntDelBkmk 5 + +/* inTentioN */ +struct TN + { + int tnt; /* intention type */ + void **h; /* affected handle */ + int c; /* number of elements or cb */ +}; +#define itnMax 45 /* GUESS (bump up if we ever overflow) */ + +/* Xaction Bifurication Control */ +struct XBC + { + int ixsMax; + int ixsMac; + char *rgxs; /* set of transaction states to handle recursive calls */ + int itnMac; + struct TN rgtn[itnMax]; /* list of transactions */ +}; + +/* Xaction State for Adding to Hplc's (XAddToHplcEdit) */ +struct XSA + { + int iFirst; + int c; +}; + +/* Xaction State for ApplyGrpprl (XApplyGrpprlDocCp) */ +struct XSP + { + int prm; +/* We don't want fCalledXDeleteHdrText to be DEBUG only, because this would + require DEBUG and non-DEBUG offsets in structs.inc (BradV, 7/26/89). */ +/* used to guarantee XDeleteHdrText doesn't do anything if it is called !fPlan + when it was not called fPlan. */ + BOOL fCalledXDeleteHdrText; +}; + +/* Xaction State for Footnote/Annotation (XAddReferencedText) */ +struct XSF + { + int ifooFirst; + int ifooLim; +}; + +/* Xaction State for fieLds (XDeleteFields) */ +struct XSL + { + int ifld; + int cfld; +}; + +/* Xaction State for Bookmarks (XCopyBkmks) */ +struct XSB + { + int ibklLim; + int ibkfLim; + int ibkf; +}; + +/* Xaction State for Replace */ +struct XSR + { + /* arguments to function */ + /* arrange dfc, fc, fn, pcaDel in this way to shorten .asm init code. */ + FC dfc; + FC fc; + int fn; + struct CA *pcaDel; + struct CA *pcaIns; + + /* state saved */ + BOOL fNotEmptyPcaDel; /* there is text to be deleted */ + int ipcdInsFirst; /* ipcdFirst of piece in source doc to be inserted */ + int ipcdInsLast; /* ipcdLast of piece in source doc to be inserted */ + int cpcd; /* number of pieces being deleted */ + BOOL fReplHidnSect; /* recursive call to copy final sect mark required */ + BOOL fNotDelPassCpMac; /* not deleting past end of dest doc */ + + /* transaction states for subroutine calls */ + struct XSF xsfFtnDel; /* footnotes */ + struct XSF xsfFtnCopy; + struct XSA xsaPgdDel; /* hplcpgd */ + struct XSA xsaPgdCopy; + struct XSA xsaSedCopy; /* hplcsed */ + struct XSA xsaSeaDel; /* hplcsea */ + struct XSA xsaSeaCopy; + struct XSA xsaPadDel; /* hplcpad */ + struct XSA xsaPadCopy; + struct XSA xsaPheDel; /* hplcphe */ + struct XSA xsaPheCopy; + struct XSP xsp; /* XApplyGrpprlDocCp */ +#ifdef WIN + struct XSF xsfAtnDel; /* annotations */ + struct XSF xsfAtnCopy; + struct XSL xslDelete; /* fields */ + struct XSB xsbCopy; /* bookmarks */ +#endif +#ifdef DEBUG +/* used to guarantee the same xs between fPlan and !fPlan */ + int nxs; + int w; +#endif /* DEBUG */ +}; +#define cbXSR sizeof(struct XSR) + +#ifdef DEBUG +#define CheckPxs(fPlan,pxs,nxsT,wT) (fPlan ? (pxs->nxs=nxsT, pxs->w=wT) : \ + Assert(pxs->nxs==nxsT && pxs->w==wT)) +#else +#define CheckPxs(fPlan,pxs,nxsT,wT) +#endif /* DEBUG */ + +#define nxsHidnSect 1 +#define nxsAddRefText 2 +#define nxsDelRefText 3 +#define nxsDelHdrText 4 +#define nxsAddHdrText 5 + + + +#if defined(DEBUG) || defined(OPUS_X64) /* in editn.asm on Win16 */ +/* P X S I N I T */ +/* initialize xbc for an Xaction and return the first pxs */ +/* %%Function:PxsInit %%Owner:peterj %%reviewed: 6/28/89 */ +HANDNATIVE char *C_PxsInit(pxs, ixsMax, pxbc) +char *pxs; +int ixsMax; +struct XBC *pxbc; +{ + pxbc->ixsMax = ixsMax; + pxbc->ixsMac = 1; + pxbc->itnMac = 0; + pxbc->rgxs = pxs; + SetBytes(pxs, 0, ixsMax*cbXSR); + return pxs; +} + + +#endif /* DEBUG || OPUS_X64 */ + + +#if defined(DEBUG) || defined(OPUS_X64) /* in editn.asm on Win16 */ +/* P O S T T N */ +/* add an intention to the intentions list in xbc */ +/* %%Function:PostTn %%Owner:peterj %%reviewed: 6/28/89 */ +HANDNATIVE C_PostTn(pxbc, tnt, h, c) +struct XBC *pxbc; +int tnt; +void **h; /* meaning of h and c depend on tnt */ +int c; +{ + struct TN *ptn = &pxbc->rgtn[pxbc->itnMac++]; +#ifdef DEBUG + Assert(pxbc->itnMac <= itnMax); + switch (tnt) + { + case tntAbort: + case tntNil: + break; + case tntHplc: + case tntHsttb: + AssertH(h); + break; + case tntCloseHdrWw: + Assert((int)h >= wwDocMin && (int)h < wwMac); + Assert(PwwdWw((int)h)->wk == wkHdr); + break; + case tntDelBkmk: + Assert(!PdodDoc((int)h/*doc*/)->fShort); + Assert(c == 0); + break; + default: + Assert(fFalse); + } +#endif /* DEBUG || OPUS_X64 */ + ptn->tnt = tnt; + ptn->h = h; + ptn->c = c; +} + + +#endif /* DEBUG */ + +/* P X S A L L O C */ +/* obtain an additional pxs for use in a recursive call */ +/* %%Function:PxsAlloc %%Owner:peterj %%reviewed: 6/28/89 */ +char *PxsAlloc(pxbc) +struct XBC *pxbc; +{ + Assert(pxbc->ixsMac < pxbc->ixsMax); + return pxbc->rgxs + (cbXSR * pxbc->ixsMac++); +} + + +#if defined(DEBUG) || defined(OPUS_X64) /* in editn.asm on Win16 */ +/* F D O T N S */ +/* "execute" the intentions stored in rgtn. return true if they all succeed */ +/* %%Function:FDoTns %%Owner:peterj %%reviewed: 6/28/89 */ +HANDNATIVE C_FDoTns(pxbc) +struct XBC *pxbc; +{ + int c, cMax; + struct TN *ptn, *ptnT, *ptnMac; + void **h; + int tnt; + BOOL fReturn = fFalse; + + for (ptn = pxbc->rgtn, ptnMac = ptn + pxbc->itnMac; ptn < ptnMac; ptn++) + switch (tnt = ptn->tnt) + { + default: + Assert(fFalse); + /* fall through */ + case tntNil: + case tntCloseHdrWw: + case tntDelBkmk: + continue; + case tntAbort: + goto LReturn; + case tntHplc: + case tntHsttb: +/* coalesce the several intentions to allocate into a single +maximal intention. (i.e., determine the largest that this heap +block will get during the course of the operation by accumlating +all of the intentions that relate to this heap block and taking +the max that that value obtains). */ + c = cMax = ptn->c; + h = ptn->h; + for (ptnT = ptn + 1; ptnT < ptnMac; ptnT++) + if (ptnT->tnt == tnt && ptnT->h == h) + { + if ((c += ptnT->c) > cMax) + cMax = c; + /* to avoid double counting */ + ptnT->tnt = tntNil; + } +/* do allocation, if necessary. fail process if allocation cannot be made */ + if (cMax > 0) + if (tnt == tntHplc && !FStretchPlc(h, cMax)) + goto LReturn; + else if (tnt == tntHsttb && !FStretchSttbCb(h, cMax)) + goto LReturn; + break; + } + + fReturn = fTrue; + +/* reset state in preperation for !fPlan phase */ + pxbc->ixsMac = 1; /* reset to first xs */ + +LReturn: +/* failure or success - don't need to handle this prm special anymore */ + vmerr.prmDontReclaim = prmNil; + + return fReturn; +} + + +#endif /* DEBUG || OPUS_X64 */ + +#if defined(DEBUG) || defined(OPUS_X64) /* in editn.asm on Win16 */ +/* C L O S E T N S */ +/* Close up unneeded space in each hplc or hsttb used by pxbc. */ +/* %%Function:CloseTns %%Owner:peterj %%reviewed: 6/28/89 */ +HANDNATIVE C_CloseTns(pxbc) +struct XBC *pxbc; +{ + struct TN *ptn, *ptnMac; + + Assert(!vfInCommit); + for (ptn = pxbc->rgtn, ptnMac = ptn + pxbc->itnMac; ptn < ptnMac; ptn++) + switch (ptn->tnt) + { +#ifdef DEBUG + case tntAbort: + default: + Assert(fFalse); + case tntNil: + break; +#endif /* DEBUG || OPUS_X64 */ + case tntHplc: + CloseUpPlc(ptn->h); + break; + case tntHsttb: + CloseUpSttb(ptn->h); + break; + case tntCloseHdrWw: + DisposeWwHdr(ptn->h); + break; + case tntDelBkmk: + /* if all bookmarks were deleted, nuke structs */ + { + struct DOD *pdod = PdodDoc((int)(intptr_t)ptn->h/*doc*/); + FreezeHp(); + Assert(!pdod->fShort); + if (pdod->hplcbkf != hNil && IMacPlc(pdod->hplcbkf) == 0) + CloseBkmkStructs(pdod); + MeltHp(); + break; + } + } +} + + +#endif /* DEBUG */ + +/* C L O S E B K M K S T R U C T S */ +/* %%Function:CloseBkmkStructs %%Owner:peterj %%reviewed: 6/28/89 */ +EXPORT CloseBkmkStructs(pdod) +struct DOD *pdod; +{ + + FreePhsttb(&pdod->hsttbBkmk); + FreePhplc(&pdod->hplcbkf); + FreePhplc(&pdod->hplcbkl); +} + + +/* F D E L E T E */ +/* delete everything in *pca */ +/* %%Function:FDelete %%Owner:peterj %%reviewed: 6/28/89 */ +FDelete(pca) +struct CA *pca; +{ + return DcpCa(pca) == 0 || FReplace(pca, fnNil, fc0, fc0); +} + + +#if defined(DEBUG) || defined(OPUS_X64) /* in editn.asm on Win16 */ +/* F R E P L A C E */ +/* Replace *pca by fc through (fc+dfc-1) in fn. returns fFalse if not +successful (in which case document is not changed). */ +/* %%Function:FReplace %%Owner:peterj %%reviewed: 6/28/89 */ +HANDNATIVE BOOL C_FReplace(pca, fn, fc, dfc) +struct CA *pca; +int fn; +FC fc, dfc; +{ + struct XBC xbc; + struct XSR *pxsr; +/* this should be the maximum number of calls to XReplace or XReplaceCps that +can result from a call to FReplace (if it is too low, the assert in PxsAlloc +should go off) */ +#define ixsrReplaceMax 4 + struct XSR rgxsr[ixsrReplaceMax]; + + if (vrulss.caRulerSprm.doc != docNil) + FlushRulerSprms(); + + pxsr = (struct XSR *)PxsInit(rgxsr, ixsrReplaceMax, &xbc); + pxsr->pcaDel = pca; + pxsr->fn = fn; + pxsr->fc = fc; + pxsr->dfc = dfc; + XReplace(fTrue, &xbc, pxsr); + if (!FDoTns(&xbc)) + { + SetErrorMat(matReplace); + return fFalse; + } + BeginCommit(); + XReplace(fFalse, &xbc, pxsr); + EndCommit(); + CloseTns(&xbc); + + return fTrue; +} + + +#endif /* DEBUG || OPUS_X64 */ + +#if defined(DEBUG) || defined(OPUS_X64) /* in editn.asm on Win16 */ +/* X R E P L A C E */ +/* Perform a bifuricated replacement. arguments are in pxsr */ +/* %%Function:XReplace %%Owner:peterj %%reviewed: 6/28/89 */ +HANDNATIVE C_XReplace(fPlan, pxbc, pxsr) +BOOL fPlan; +struct XBC *pxbc; +struct XSR *pxsr; +{ + struct CA *pca = pxsr->pcaDel; + + Assert(pca->cpFirst >= cp0 && pca->cpLim <= CpMac1Doc(pca->doc)); +#ifdef WIN + /* check that deleted portion may be deleted WRT fields */ + AssertSz(!vdbs.fCkFldDel || + FCkFldForDelete(pca->doc, pca->cpFirst, pca->cpLim), + "Attempt to delete unmatched field char! " ); +#endif + + if (DcpCa(pca) != 0) +/* delete structures for text being deleted */ + XDeleteStruct(fPlan, pxbc, pxsr); + +#ifdef WIN + if (!fPlan && !vfNoInval) + /* may call CachePara or FetchCp, must call BEFORE changing piece tbl */ + InvalText (pca, fTrue /* fEdit */); +#endif /* WIN */ + + XRepl1(fPlan, pxbc, pxsr); + +/* invalidate (only needed if !fPlan) */ + if (!fPlan) + { + if (!vfNoInval) + InvalCp1(pca); + else + /* inval the caches even if vfNoInval on */ + InvalCaFierce(); + + AdjustCp(pca, pxsr->dfc); + } +} + + +#endif /* DEBUG || OPUS_X64 */ + + +#if defined(DEBUG) || defined(OPUS_X64) /* in editn.asm on Win16 */ +/* F R E P L 1 */ +/* delete pca and insert the specified piece (does not do checking, +adjustment or invalidation). returns fFalse on failure (in which case +document is unchanged). */ +/* %%Function:FRepl1 %%Owner:peterj %%reviewed: 6/28/89 */ +HANDNATIVE BOOL C_FRepl1(pca, fn, fc, dfc) +struct CA *pca; +int fn; +FC fc, dfc; +{ + struct XBC xbc; + struct XSR *pxsr; +/* this should be the maximum number of calls to XReplace or XReplaceCps that +can result from a call to FRepl1 (if it is too low, the assert in PxsAlloc +should go off) */ +#define ixsrRepl1Max 1 + struct XSR rgxsr[ixsrRepl1Max]; + + pxsr = (struct XSR *)PxsInit(rgxsr, ixsrRepl1Max, &xbc); + pxsr->pcaDel = pca; + pxsr->fn = fn; + pxsr->fc = fc; + pxsr->dfc = dfc; + XRepl1(fTrue, &xbc, pxsr); + if (!FDoTns(&xbc)) + { + SetErrorMat(matReplace); + return fFalse; + } + BeginCommit(); + XRepl1(fFalse, &xbc, pxsr); + EndCommit(); + CloseTns(&xbc); + + return fTrue; +} + + +#endif /* DEBUG || OPUS_X64 */ + + +#if defined(DEBUG) || defined(OPUS_X64) /* in editn.asm on Win16 */ +/* I P C D S P L I T */ +/* Ensure cp is the beginning of a piece. Return index of that piece. */ +/* %%Function:IpcdSplit %%Owner:peterj %%reviewed: 6/28/89 */ +HANDNATIVE int C_IpcdSplit(hplcpcd, cp) +struct PLC **hplcpcd; +CP cp; +{ + int ipcd; + struct PCD pcd; + CP dcp; + + vdocFetch = docNil; /* ensure fetch cache isn't lying */ + if ((ipcd = IInPlcCheck(hplcpcd, cp)) == -1) + return(IMacPlc(hplcpcd)); + if ((dcp = cp - CpPlc(hplcpcd, ipcd)) != cp0) + { + Assert(!vfInCommit); +/* Insert a new piece flush with the one at ipcd */ + if (!FOpenPlc(hplcpcd, ++ipcd, 1)) + { + SetErrorMat( matReplace ); + return iNil; + } + PutCpPlc(hplcpcd, ipcd, cp); + /* We are doing effectively: + pcd.fn = pcdPrev.fn; + pcd.fc = pcdPrev.fc + dcp; + pcd.prm = pcdPrev.prm; + pcd.fNoParaLastValid = pcdPrev.fNoParaLast; + pcd.fNoParaLast = pcdPrev.fNoParaLast; + */ + GetPlc(hplcpcd, ipcd - 1, &pcd); + pcd.fc += dcp; + PutPlc(hplcpcd, ipcd, &pcd); + } + return ipcd; +} + + +#endif /* DEBUG || OPUS_X64 */ + + +#if defined(DEBUG) || defined(OPUS_X64) /* in editn.asm on Win16 */ +/* X R E P L 1 */ +/* perform Bifuricated replacement. arguments are in pxsr */ +/* %%Function:XRepl1 %%Owner:peterj %%reviewed: 6/28/89 */ +HANDNATIVE C_XRepl1(fPlan, pxbc, pxsr) +BOOL fPlan; +struct XBC *pxbc; +struct XSR *pxsr; +{ + struct PLC **hplcpcd; + int ipcdFirst, ipcdLim; + int cpcd; + struct PCD pcd; + struct PCD pcdPrev; + + hplcpcd = PdodDoc(pxsr->pcaDel->doc)->hplcpcd; + + if (fPlan) + { + pxsr->fNotEmptyPcaDel = (pxsr->pcaDel->cpFirst != pxsr->pcaDel->cpLim); + + if ((ipcdFirst = IpcdSplit(hplcpcd, pxsr->pcaDel->cpFirst)) + == iNil) + { +LPostAbort: + PostTn(pxbc, tntAbort, NULL, 0); + return; + } + + if (!pxsr->fNotEmptyPcaDel) + cpcd = 0; + else + { + int ipcdLim; + if ((ipcdLim = IpcdSplit(hplcpcd, pxsr->pcaDel->cpLim)) + == iNil) + goto LPostAbort; + cpcd = ipcdFirst - ipcdLim; + } + pxsr->cpcd = cpcd; + } + else + { + /* ipcd not stored because recursive calls can cause it to change */ + ipcdFirst = IpcdSplit(hplcpcd, pxsr->pcaDel->cpFirst); + cpcd = pxsr->cpcd; + /* make sure that the range to be deleted is already split out */ + Assert(!pxsr->fNotEmptyPcaDel || + IInPlc(hplcpcd, pxsr->pcaDel->cpLim) == ipcdFirst - cpcd); + /* set so vhprc chain is checked when we run out of memory */ + vmerr.fReclaimHprcs = fTrue; + } + + /* number of pieces to be added (negative or zero) */ + Assert(cpcd <= 0); + + if (fPlan) + /* simplified, may be one less */ + PostTn(pxbc, tntHplc, hplcpcd, cpcd+1); + + else + { + if (ipcdFirst > 0) + GetPlc(hplcpcd, ipcdFirst - 1, &pcdPrev); + + if (pxsr->dfc == fc0 || + (ipcdFirst > 0 && pcdPrev.fn == pxsr->fn && + pcdPrev.prm == prmNil && pcdPrev.fc + + (pxsr->pcaDel->cpFirst - CpPlc(hplcpcd,ipcdFirst-1)) + == pxsr->fc)) + /* Either pure delete or extension of previous piece */ + { + FOpenPlc(hplcpcd, ipcdFirst, cpcd); + if (pxsr->dfc != fc0) + /* If extending, say we might have inserted Eop*/ + { + Debug(pcdPrev.fNoParaLastValid = fFalse); + pcdPrev.fNoParaLast = fFalse; + PutPlc(hplcpcd, ipcdFirst - 1, &pcdPrev); + } + } + else + /* Insert one piece */ + { + AssertDo(FOpenPlc(hplcpcd, ipcdFirst, cpcd + 1)); + GetPlc(hplcpcd, ipcdFirst, &pcd); + PutCpPlc(hplcpcd, ipcdFirst, pxsr->pcaDel->cpFirst); + pcd.fn = pxsr->fn; + pcd.fc = pxsr->fc; + pcd.prm = prmNil; + Debug(pcd.fNoParaLastValid = fFalse); + pcd.fNoParaLast = fFalse; /* Para state unknown */ + pcd.fPaphNil = fFalse; + PutPlc(hplcpcd, ipcdFirst, &pcd); + ipcdFirst++; + } + AdjustHplc(hplcpcd, pxsr->pcaDel->cpLim, pxsr->dfc-pxsr->pcaDel->cpLim + + pxsr->pcaDel->cpFirst, ipcdFirst); +#ifdef WIN + InvalVisiCache(); + InvalCellCache(); +#endif /* WIN */ + } +} + + +#endif /* DEBUG || OPUS_X64 */ + +#if defined(DEBUG) || defined(OPUS_X64) +/* X D E L E T E S T R U C T */ +/* Delete structures from the deletion range */ +/* %%Function:XDeleteStruct %%owner:peterj %%reviewed: 6/28/89 */ +XDeleteStruct(fPlan, pxbc, pxsr) +BOOL fPlan; +struct XBC *pxbc; +struct XSR *pxsr; +{ + struct CA *pca = pxsr->pcaDel; + +/* check for deleting para and sect boundaries; delete entries from parallel +structures */ + if (!fPlan && !vfNoInval) + InvalParaSect(pca, pca, fTrue); +#ifdef WIN + if (FFieldsInPca(pca)) + XDeleteFields(fPlan, pxbc, &pxsr->xslDelete, pca); + + if (!PdodDoc(pca->doc)->fShort) + if (PdodDoc(pca->doc)->hsttbBkmk != hNil) + XDeleteBkmks(fPlan, pxbc, pca, fFalse); +#endif + XDelFndSedPgdPad(fPlan, pxbc, pxsr); +} + + +#endif /* DEBUG || OPUS_X64 */ + + +/* F R E P L A C E C P S R M */ +/* General replace routine -- takes revision marking into account */ +/* adjusts pcaDel to what's left after the delete. */ +/* %%Function:FReplaceCpsRM %%Owner:peterj %%reviewed: 6/28/89 */ +BOOL FReplaceCpsRM(pcaDel, pcaIns) +struct CA *pcaDel, *pcaIns; +{ + struct CA caT; + char grpprl[2]; + + if (vmerr.fMemFail) + return fFalse; + +#ifdef WIN + if (PdodMother(pcaDel->doc)->dop.fRevMarking) + { + AssureLegalSel( pcaDel ); + if (DcpCa(pcaDel) != cp0) + { + if (!FRemoveRevMarking(pcaDel, rrmDelete, fFalse /* fSubDocs */)) + return fFalse; + } + if (DcpCa(pcaIns) != cp0) + { + caT = *pcaDel; + caT.cpLim = caT.cpFirst; + if (!FReplaceCps(&caT, pcaIns)) + return fFalse; + caT.cpLim = caT.cpFirst + DcpCa(pcaIns); + grpprl[0] = sprmCFRMark; + grpprl[1] = TRUE; + ApplyGrpprlCa(grpprl, sizeof(grpprl), &caT); + } + } + else +#endif + { + if (!FReplaceCps(pcaDel, pcaIns)) + return fFalse; + pcaDel->cpLim = pcaDel->cpFirst; + } + return !vmerr.fMemFail; +} + + +#if defined(DEBUG) || defined(OPUS_X64) /* in editn.asm on Win16 */ +/* F R E P L A C E C P S */ +/* General replace routine */ +/* Replace characters from pcaDel with characters from pcaIns. returns fFalse +on failure (in which case document is unchanged) */ +/* %%Function:FReplaceCps %%Owner:peterj %%reviewed: 6/28/89 */ +HANDNATIVE BOOL C_FReplaceCps(pcaDel, pcaIns) +struct CA *pcaDel, *pcaIns; +{ + struct XBC xbc; + struct XSR *pxsr; +/* this should be the maximum number of calls to XReplace or XReplaceCps that +can result from a call to FReplaceCps (if it is too low, the assert in PxsAlloc +should go off). Win is greater than Mac because of annotations. */ +#define ixsrReplaceCpsMax WinMac(10,8) + struct XSR rgxsr[ixsrReplaceCpsMax]; + + Assert(pcaDel->cpFirst >= cp0 && pcaDel->cpLim <= CpMac1Doc(pcaDel->doc)); + Assert(DcpCa(pcaDel) >= 0 && DcpCa(pcaIns) >= cp0); + + if (vrulss.caRulerSprm.doc != docNil) + FlushRulerSprms(); + + pxsr = (struct XSR *)PxsInit(rgxsr, ixsrReplaceCpsMax, &xbc); + pxsr->pcaDel = pcaDel; + pxsr->pcaIns = pcaIns; + XReplaceCps(fTrue, &xbc, pxsr); + if (!FDoTns(&xbc)) + { + SetErrorMat(matReplace); + return fFalse; + } + BeginCommit(); + XReplaceCps(fFalse, &xbc, pxsr); + EndCommit(); + CloseTns(&xbc); + + return fTrue; +} + + +#endif /* DEBUG || OPUS_X64 */ + + +#if defined(DEBUG) || defined(OPUS_X64) /* in editn.asm on Win16 */ +/* X R E P L A C E C P S */ +/* perform bifuricated replacement. arguments are in pxsr */ +/* %%Function:XReplaceCps %%Owner:peterj %%reviewed: 6/28/89 */ +HANDNATIVE C_XReplaceCps(fPlan, pxbc, pxsr) +BOOL fPlan; +struct XBC *pxbc; +struct XSR *pxsr; +{ + struct PLC **hplcpcdDest, **hplcpcdSrc; + int ipcdFirst, ipcdInsFirst, ipcdLim; + int cpcd; + struct CA *pcaDel = pxsr->pcaDel; + struct CA *pcaIns = pxsr->pcaIns; + int docDel = pcaDel->doc; + int docIns = pcaIns->doc; + CP dcpDel = DcpCa(pcaDel); + CP dcpIns = DcpCa(pcaIns); + struct DOD **hdodSrc = mpdochdod[docIns]; + struct DOD **hdodDest = mpdochdod[docDel]; + struct PCD pcd; + +#ifdef DEBUG + if (fPlan) + /* no point doing all this twice! */ + { + Assert(pcaDel->cpFirst >= cp0 && pcaDel->cpLim <= CpMac1Doc(docDel)); + Assert(dcpDel >= 0 && dcpIns >= cp0); + Assert(docDel != docIns); + /* assured by caller */ + Assert(vrulss.caRulerSprm.doc == docNil); +#ifdef WIN + /* assure that if vdocScratch is being used, it has been "Acquired" */ + Assert ((vdocScratch == docNil || (docDel != vdocScratch && + docIns != vdocScratch) || fDocScratchInUse)); + /* check that deleted portion is legal WRT fields */ + AssertSz(!vdbs.fCkFldDel || FCkFldForDelete(docDel, pcaDel->cpFirst, pcaDel->cpLim) + && FCkFldForDelete(pcaIns->doc, pcaIns->cpFirst, pcaIns->cpLim), + "Attempt to delete unmatched field char!"); +#endif + } +#endif /* DEBUG */ + + if (dcpIns == 0) + /* This is just too easy . . . */ + { + pxsr->fn = fnNil; + pxsr->fc = fc0; + pxsr->dfc = fc0; + XReplace(fPlan, pxbc, pxsr); + return; + } + + hplcpcdDest = (*hdodDest)->hplcpcd; + hplcpcdSrc = (*hdodSrc)->hplcpcd; + + if (dcpDel != cp0) +/* delete structures for text being deleted */ + XDeleteStruct(fPlan, pxbc, pxsr); + + if (!fPlan && !vfNoInval) + InvalParaSect(pcaDel, pcaIns, fFalse); + +/* Get the first and last pieces for insertion */ + if (fPlan) + { + ipcdInsFirst = pxsr->ipcdInsFirst = + IInPlc(hplcpcdSrc, pcaIns->cpFirst); + pxsr->ipcdInsLast = IInPlc(hplcpcdSrc, pcaIns->cpLim - 1); + pxsr->fNotEmptyPcaDel = (dcpDel != 0); + } + else + ipcdInsFirst = pxsr->ipcdInsFirst; + +/* get the limiting pieces for deletion */ + if (fPlan) + { + ipcdFirst = IpcdSplit(hplcpcdDest, pcaDel->cpFirst); + ipcdLim = (pxsr->fNotEmptyPcaDel) ? + IpcdSplit(hplcpcdDest, pcaDel->cpLim) : ipcdFirst; + +/* check for failure of IpcdSplit */ + if (ipcdFirst == iNil || ipcdLim == iNil) + { + PostTn(pxbc, tntAbort, NULL, 0); + return; + } + + /* number of pieces to be added */ + pxsr->cpcd = cpcd = ipcdFirst - ipcdLim + pxsr->ipcdInsLast - ipcdInsFirst +1; + } + else + { + /* ipcd not stored because recursive calls can cause it to change */ + ipcdFirst = IpcdSplit(hplcpcdDest, pcaDel->cpFirst); + cpcd = pxsr->cpcd; + /* make sure that the range to be deleted is already split out */ + Assert(cpcd == ipcdFirst + pxsr->ipcdInsLast - ipcdInsFirst + 1 + - ((pxsr->fNotEmptyPcaDel) ? + IpcdSplit(hplcpcdDest, pcaDel->cpLim) : ipcdFirst)); + } + + if (fPlan) + PostTn(pxbc, tntHplc, hplcpcdDest, cpcd); + + else + { +#ifdef WIN + if (!vfNoInval) + /* may call CachePara or FetchCp, must call BEFORE changing piece tbl */ + InvalText (pcaDel, fTrue /* fEdit */); +#endif /* WIN */ + +/* set so vhprc chain is checked when we run out of memory */ + vmerr.fReclaimHprcs = fTrue; + +/* adjust pctb size; get pointer to the first new piece, ppcdDest, and to the +first piece we are inserting. */ + AssertDo(FOpenPlc(hplcpcdDest, ipcdFirst, cpcd)); + + FreezeHp(); +/* ensure rgcp in hplcpcdSrc is adjusted before we copy cps. */ + if (((struct PLC *)*hplcpcdSrc)->icpAdjust < ipcdInsFirst + 1) + AdjustHplcCpsToLim(hplcpcdSrc, ipcdInsFirst + 1); + +/* fill first new piece and split it appropriately */ + GetPlc(hplcpcdSrc, ipcdInsFirst, &pcd); + pcd.fc += (pcaIns->cpFirst - CpPlc(hplcpcdSrc, ipcdInsFirst)); + PutPlc(hplcpcdDest, ipcdFirst, &pcd); + PutCpPlc(hplcpcdDest, ipcdFirst, pcaDel->cpFirst); + + ipcdLim = ipcdFirst + 1; + if ((cpcd = pxsr->ipcdInsLast - ipcdInsFirst) != 0) + { +/* fill in rest of inserted pieces */ + ipcdLim += cpcd; + CopyMultPlc(cpcd, hplcpcdSrc, ipcdInsFirst + 1, + hplcpcdDest, ipcdFirst + 1, + pcaDel->cpFirst - pcaIns->cpFirst, 0, 0); + } + +/* adjust rest of pieces in destination doc */ + AdjustHplc(hplcpcdDest, pcaDel->cpLim, /*dcpAdj*/dcpIns - dcpDel, + ipcdLim); + +/* and inform anyone else who cares */ + + (*hdodDest)->fFormatted |= (pcaIns->doc == docScrap) ? + vsab.fFormatted : (*hdodSrc)->fFormatted; + PdodMother(docDel)->fMayHavePic |= (docIns == docScrap) ? + vsab.fMayHavePic : PdodMother(docIns)->fMayHavePic; + if (!vfNoInval) + InvalCp1(pcaDel); + else + /* inval the caches even if vfNoInval on */ + InvalCaFierce(); + +#ifdef WIN + /* invalidate FetchCpPccpVisible */ + InvalVisiCache(); + InvalCellCache(); +#endif /* WIN */ + + MeltHp(); + + AdjustCp(pcaDel, dcpIns); +/* NOTE after this point pcaDel->cpLim may be untrustworthy because it may + have been adjusted as a side effect of AdjustCp (eg. selCur.ca) */ + } + + +/* copy enclosed structures and subdocs */ + +#ifdef WIN +/* copy any enclosed fields */ + if (FFieldsInPca(pcaIns)) + XCopyFields(fPlan, pxbc, pcaIns, pcaDel); +#endif + +/* page table: if there is a table to be updated, call routine. Even if +the source table is empty, the destination will have to be invalidated. */ + if ((*hdodDest)->hplcpgd) + { + XAddToHplcEdit(fPlan, pxbc, &pxsr->xsaPgdCopy, pcaIns, pcaDel, + edcPgd); + InvalLlc(); + } + + if (!(*hdodSrc)->fShort && !(*hdodDest)->fShort) + { +#ifdef WIN +/* copy any bookmarks in the source document which are fully enclosed + in the insertion range to the destination document */ + if ((*hdodSrc)->hsttbBkmk != hNil) + XCopyBkmks(fPlan, pxbc, &pxsr->xsbCopy, pcaIns, pcaDel); + +/* copy any anotations along with their reference marks */ + if ((*hdodSrc)->docAtn != docNil) + XAddReferencedText(fPlan, pxbc, &pxsr->xsfAtnCopy, pcaIns, pcaDel, + edcDrpAtn); +#endif + +/* copy any footnotes along with their reference marks */ + if ((*hdodSrc)->docFtn != docNil) + XAddReferencedText(fPlan, pxbc, &pxsr->xsfFtnCopy, pcaIns, pcaDel, + edcDrpFtn); + +/* if there are any sections call AddHplcEdit to copy entries from +one hplcsed to the other */ + if ((*hdodSrc)->hplcsed) + { + caSect.doc = docNil; + if ((*hdodSrc)->docHdr != docNil || (*hdodDest)->docHdr != docNil) + { + XAddHdrText(fPlan, pxbc, pcaIns, pcaDel); + caSect.doc = docNil; /* XAdd.. called CacheSect */ + } + + XAddToHplcEdit(fPlan, pxbc, &pxsr->xsaSedCopy, pcaIns, pcaDel, + edcSed); + InvalLlc(); + } + if ((*hdodSrc)->fSea && (*hdodSrc)->hplcsea) + XAddToHplcEdit(fPlan, pxbc, &pxsr->xsaSeaCopy, pcaIns, pcaDel, + edcSea); +/* outline table: as for page table */ + if (fPlan) + pxsr->fNotDelPassCpMac = (pcaDel->cpFirst < (CpMacDoc(docDel)+dcpIns-dcpDel)); + if (((*hdodDest)->hplcpad || (*hdodSrc)->hplcpad) && + pxsr->fNotDelPassCpMac && (*hdodDest)->dk != dkGlsy) + { + XAddToHplcEdit(fPlan, pxbc, &pxsr->xsaPadCopy, pcaIns, pcaDel, + edcPad); + } + +/* height table */ + if ((*hdodDest)->hplcphe) + XAddToHplcEdit(fPlan, pxbc, &pxsr->xsaPheCopy, pcaIns, pcaDel, + edcPhe); + +/* we will replace docDest's hidden section character with the hidden section + mark from docSrc only if we are not already copying the section mark, + we are copying the tail of docIns to the tail of docDel, the text + copied from docIns does not end with a section mark, and if docSrc is + guarded (ie. == docScrap or docUndo) the hidden section character had to + have been copied from the original document. */ + + if (fPlan) + { + CP cpTailIns = CpTail(docIns); + struct DOD *pdodIns; +/* Note that no cps have been adjusted yet */ + pxsr->fReplHidnSect = + pcaDel->cpFirst + dcpDel <= CpMacDoc(docDel) && + pcaIns->cpFirst < CpMacDoc(docIns) && + pcaIns->cpLim >= cpTailIns && + !FSectLimAtCp(docIns, cpTailIns) && + pcaDel->cpLim >= CpTail(docDel) - + ((!PdodDoc(docDel)->fGuarded) ? ccpEop : cp0) && + (!(pdodIns=PdodDoc(docIns))->fGuarded || + (pdodIns->fSedMacEopCopied && (dcpDel > cp0 || dcpIns == CpMacDocEdit(docIns)))); + } + if (pxsr->fReplHidnSect) + { + struct XSR *pxsrT = PxsAlloc(pxbc); + struct CA caDel, caIns; + CheckPxs(fPlan, pxsrT, nxsHidnSect, 0); + pxsrT->pcaDel = PcaSetDcp(&caDel, docDel, CpMac1Doc(docDel)-ccpEop, + ccpEop); + pxsrT->pcaIns = PcaSetDcp(&caIns, docIns, CpMac1Doc(docIns)-ccpEop, + ccpEop); + XReplaceCps(fPlan, pxbc, pxsrT); + if (!fPlan && PdodDoc(docDel)->fGuarded) + PdodDoc(docDel)->fSedMacEopCopied = fTrue; + } + } +} + + +#endif /* DEBUG */ + + +#if defined(DEBUG) || defined(OPUS_X64) +/* X D E L F N D S E D P G D P A D */ +/* Delete all footnote/annotation text corresponding to refs in pcaDel +Also delete SED's for section marks and invalidate PGD's in the page table. +*/ +/* %%Function:XDelFndSedPgdPad %%Owner:peterj %%reviewed: 6/28/89 */ +HANDNATIVE C_XDelFndSedPgdPad(fPlan, pxbc, pxsr) +BOOL fPlan; +struct XBC *pxbc; +struct XSR *pxsr; +{ + struct PLC **hplc; + struct DOD **hdod; + struct CA caT; + + caT = *pxsr->pcaDel; + hdod = mpdochdod[caT.doc]; + +/* FUTURE: why does this have to be done here? Can it be done below with the +rest of the !fShort processing? */ + if (!(*hdod)->fShort) + if ((hplc = (*hdod)->hplcsed) != 0) + { + if ((*hdod)->docHdr != docNil) + XDeleteHdrText(fPlan, pxbc, &pxsr->xsp, pxsr->pcaDel); + XDelInHplcEdit(fPlan, pxbc, NULL, pxsr->pcaDel, hplc, + edcNone); + InvalLlc(); + } + +/* protect PLCs from lookups with cp > cpMac */ + Assert(caT.cpLim <= CpMac2Doc(caT.doc)); + caT.cpLim = CpMin(caT.cpLim, CpMac2Doc(caT.doc)); + if (caT.cpLim <= caT.cpFirst) + return; + +/* these PLCs are in short and long docs */ + if ((hplc = (*hdod)->hplcpgd) != 0) + { + XDelInHplcEdit(fPlan, pxbc, &pxsr->xsaPgdDel, &caT, hplc, edcPgd); + InvalLlc(); + } + if ((hplc = (*hdod)->hplcphe) != 0) + XDelInHplcEdit(fPlan, pxbc, &pxsr->xsaPheDel, &caT, hplc, edcPhe); + + if ((*hdod)->fShort) + return; +/* PLCs for long docs only */ + + if ((*hdod)->docFtn != docNil) + XDelReferencedText(fPlan, pxbc, &pxsr->xsfFtnDel, &caT, edcDrpFtn); +#ifdef WIN + if ((*hdod)->docAtn != docNil) + XDelReferencedText(fPlan, pxbc, &pxsr->xsfAtnDel, &caT, edcDrpAtn); +#endif /* WIN */ + + if ((hplc = (*hdod)->hplcpad) != 0 && caT.cpFirst < CpMacDoc(caT.doc)) + XDelInHplcEdit(fPlan, pxbc, &pxsr->xsaPadDel, &caT, hplc, edcPad); + if ((*hdod)->fSea && (hplc = (*hdod)->hplcsea) != 0) + XDelInHplcEdit(fPlan, pxbc, &pxsr->xsaSeaDel, &caT, hplc, edcSea); +} + + +#endif /* DEBUG || OPUS_X64 */ + +/* X A D D T O H P L C E D I T */ +/* inserts at Dest the section (paragraph, etc..) bounds found in the Src */ +/* %%Function:XAddToHplcEdit %%Owner:peterj %%reviewed: 6/28/89 */ +EXPORT XAddToHplcEdit(fPlan, pxbc, pxsa, pcaSrc, pcaDest, edc) +BOOL fPlan; +struct XBC *pxbc; +struct XSA *pxsa; +struct CA *pcaSrc, *pcaDest; +int edc; +{ + struct PLC **hplcSrc; + struct PLC **hplcDest; + struct DOD **hdodDest = mpdochdod[pcaDest->doc]; + int ipgd, cIns, iFirst; + CP cpDest = pcaDest->cpFirst; + CP cpFirst; + union + { + struct PGD pgd; + struct PAD pad; + struct PHE phe; + struct SED sed; + } foo; + +/* source and destination tables */ +#ifdef OPUS_X64 + hplcDest = *(struct PLC ***)((CHAR *)(*hdodDest) + edc * sizeof(int)); + hplcSrc = *(struct PLC ***)((CHAR *)PdodDoc(pcaSrc->doc) + + edc * sizeof(int)); +#else + hplcDest = *((int *)(*hdodDest) + edc); + hplcSrc = *((int *)PdodDoc(pcaSrc->doc) + edc); +#endif + + cpDest = CpMin(cpDest, CpMacDoc(pcaDest->doc)); + + if (hplcSrc == 0 || edc == edcPgd) + { + Assert(hplcDest); + if (!fPlan) + { +/* entry at iDest will become unknown. fUnk bit will be in the same place +in all relevant structures: PGD, PAD +*/ + if (edc != edcSea) + { + if ((ipgd=IInPlcMult(hplcDest, cpDest)) >= IMacPlc(hplcDest)) + return; + GetPlc(hplcDest, ipgd, &foo); + foo.pad.fUnk = fTrue; + PutPlcLast(hplcDest, ipgd, &foo); + } + if (edc == edcPad) + (*hdodDest)->fOutlineDirty = fTrue; + } + return; + } + + cpFirst = pcaSrc->cpFirst; + + if (fPlan) + { + CP cpLim; + + cpLim = CpMin(pcaSrc->cpLim, ((edc != edcSed) ? + CpMacDoc(pcaSrc->doc) : CpMac1Doc(pcaSrc->doc))); + + iFirst = pxsa->iFirst = IInPlcMult(hplcSrc, cpFirst); + pxsa->c = IInPlc2Mult(hplcSrc, cpLim, iFirst) - iFirst; + } + else + iFirst = pxsa->iFirst; + + if ((cIns = pxsa->c) == 0) + return; + + if (fPlan) + { +/* assure we have a plc then plan for space */ + if (hplcDest == hNil) + { + if ((hplcDest = HplcCreateEdc(hdodDest, edc)) == hNil) + { + PostTn(pxbc, tntAbort, NULL, 0); + return; + } + + /* this is now guaranteed (all long-dod docs always have a sed) */ + Assert(edc != edcSed); +#ifdef DISABLE_PJ + /* delete the bogus SED entry added by HplcCreateEdc */ + if (edc == edcSed) + FOpenPlc(hplcDest, 1, -1); +#endif /* DISABLE_PJ */ + } + PostTn(pxbc, tntHplc, hplcDest, cIns); + } + + AssertH(hplcDest); + + if (!fPlan) + { + int iDest = IInPlcMult(hplcDest, cpDest); + AssertDo(FOpenPlc(hplcDest, iDest + 1, cIns)); + CopyMultPlc(1, hplcDest, iDest, hplcDest, iDest + cIns, cp0, 0, 0); + CopyMultPlc(cIns, hplcSrc, iFirst, hplcDest, iDest, cpDest - cpFirst, + 1, 0); + + if (edc == edcPhe) + { +/* PHE update: entry at iDest will become invalid */ + GetPlc(hplcDest, iDest, &foo); + foo.phe.fUnk = fTrue; + PutPlcLast(hplcDest, iDest, &foo.phe); +/* last entry inserted will be invalid */ + if (cIns > 1) + { + GetPlc(hplcDest, iDest + cIns - 1, &foo); + foo.phe.fUnk = fTrue; + PutPlcLast(hplcDest, iDest + cIns - 1, &foo); + } + } + } +} + + +/* X D E L I N H P L C E D I T */ +/* removes bounds in the plc. cp is removed from plc iff +cpFirst < cp <= cpLim, since cp's point to beginnings of sections (pages, etc.) +Returns iFirst into plc. +*/ +/* %%Function:XDelInHplcEdit %%Owner:peterj %%reviewed: 6/28/89 */ +EXPORT XDelInHplcEdit(fPlan, pxbc, pxsa, pca, hplc, edc) +BOOL fPlan; +struct XBC *pxbc; +struct XSA *pxsa; +struct CA *pca; +struct PLC **hplc; +int edc; +{ + int iFirst, cDel, iMacPlc; + union /* NOTE: pgd and phe fUnQk must be coincident */ + { + struct PGD pgd; + struct PHE phe; + } pxx; + + Debug(cDel = 0x8000); + + Assert(pca->cpFirst < pca->cpLim); + AssertH(hplc); + + if ((iMacPlc = IMacPlc(hplc)) == 0) + return; + + if (fPlan || pxsa == NULL) + { + if ((iFirst = IInPlcMult(hplc, pca->cpFirst)) < iMacPlc) + cDel = IInPlc2Mult(hplc, pca->cpLim, iFirst) - iFirst; + if (pxsa != NULL) + { + pxsa->iFirst = iFirst; + pxsa->c = cDel; + } + } + else + { + iFirst = pxsa->iFirst; + cDel = pxsa->c; + } + + if (iFirst >= iMacPlc) + return; + + /* there is a potential path where cDel is unitialized. assert we can + never follow that path. */ + Assert(cDel != 0x8000); + + if (cDel != 0) + { +/* Close up plc */ +/* delete cp's starting at iFirst + 1, delete entries starting at iFirst. +OpenPlc deletes them starting at the same place, so we have to save/restore +the unadjusted cp at iFirst, except at end of plc (rgcp[iMac] should remain +undisturbed) */ + if (fPlan) + PostTn(pxbc, tntHplc, hplc, -cDel); + else + { + CP cpT = CpPlc(hplc, iFirst); + if (edc == edcPgd && iFirst > 0) + { +/* we are invalidating the page before the page boundary that was deleted. +deleting a page boundary casts doubt on the extend and layout of the previous +page. for example layout of previous page is blown if we remove a paragraph +with Page Break Before set to true. */ + GetPlc(hplc, iFirst - 1, &pxx); + pxx.pgd.fUnk = fTrue; + PutPlcLast(hplc, iFirst - 1, &pxx); + } + FOpenPlc(hplc, iFirst, -cDel); + if (iFirst != IMacPlc(hplc)) + PutCpPlc(hplc, iFirst, cpT); + } + } +/* in the page table, invalidate the page where the deletion starts */ +/* in the height table, invalidate height where the deletion starts and ends*/ + if (!fPlan && (edc == edcPgd || edc == edcPhe) && iFirst < IMacPlc(hplc)) + { + if (edc == edcPgd) + AdjustIpgds(pca->doc, iFirst, cDel, fTrue); + GetPlc(hplc, iFirst, &pxx); + pxx.pgd.fUnk = fTrue; + PutPlcLast(hplc, iFirst, &pxx); + } +} + + +/* X A D D R E F E R E N C E D T E X T */ +/* Add footnote/annotation text to correspond with inserted references. +Called after inserting docSrc[cpFirst:cpLim) into docDest@cpDest +At this point we know only that the source doc has docFtn/docAtn != docNil. +*/ +/* %%Function:XAddReferencedText %%Owner:peterj %%reviewed: 6/28/89 */ +EXPORT XAddReferencedText(fPlan, pxbc, pxsf, pcaSrc, pcaDest, edcDrp) +BOOL fPlan; +struct XBC *pxbc; +struct XSF *pxsf; +struct CA *pcaSrc, *pcaDest; +int edcDrp; +{ + struct DOD **hdodDest; + struct PLC **hplcRefDest, **hplcDest, **hplcRefSrc, **hplcSrc; + int docSubDest, docSubSrc; + int cfoo, ifooDest; + CP cpSubSrc, cpSubDest; + int docDest = pcaDest->doc; + struct CA caT1, caT2; + struct XSR *pxsr2; + + /* BLOCK - heap pointer */ + { + struct DRP *pdrp; + pdrp = ((int *) PdodDoc(pcaSrc->doc)) + edcDrp; + docSubSrc = pdrp->doc; + if ((hplcRefSrc = pdrp->hplcRef) == hNil) + return; + } + hplcSrc = PdodDoc(docSubSrc)->hplcfnd; + +/* compute: + ifooFirst: first ref included in the interval [cpFirst, cpLim) + ifooLim: last ref in the interval + 1. +*/ + + if (fPlan) + { + pxsf->ifooFirst = IInPlcRef(hplcRefSrc, pcaSrc->cpFirst); + Assert(pxsf->ifooFirst >= 0); + pxsf->ifooLim = IInPlcCheck(hplcRefSrc, pcaSrc->cpLim - 1) + 1; + } +/* we are inserting cfoo = ifooLim-ifooFirst footnotes/annotations... +*/ + if ((cfoo = pxsf->ifooLim - pxsf->ifooFirst) <= 0) + return; + + hdodDest = mpdochdod[docDest]; + + if (fPlan && DocSubEnsure(docDest, edcDrp) == docNil) + { +LPostAbort: + PostTn(pxbc, tntAbort, NULL, 0); + return; + } + + /* BLOCK - heap pointer */ + { + struct DRP *pdrp; + pdrp = ((int *) (*hdodDest)) + edcDrp; + docSubDest = pdrp->doc; + Assert(docSubDest != docNil); + hplcRefDest = pdrp->hplcRef; + } + AssertH(hplcRefDest); + hplcDest = PdodDoc(docSubDest)->hplcfnd; + AssertH(hplcDest); + + if (fPlan) + { + /* caller guarantees that hdodDest is a long-dod doc, which + guarantees that these flags are off. */ + Assert(!(*hdodDest)->fFtn && !(*hdodDest)->fAtn); +#ifdef DISABLE_PJ + if ((*hdodDest)->fFtn) + { /* Inserting refs inside footnotes? No way! */ + ErrorEid(eidInvalForFN,"AddReferencedText"); + goto LPostAbort; + } +#ifdef WIN + if ((*hdodDest)->fAtn) + { /* Inserting refs inside annotations? No way! */ + ErrorEid(eidNotValidForAnn,"AddReferencedText"); + goto LPostAbort; + } +#endif +#endif /* DISABLE_PJ */ + PostTn(pxbc, tntHplc, hplcRefDest, cfoo); + PostTn(pxbc, tntHplc, hplcDest, cfoo); + } +/* Find ifoo to insert new foo's */ + ifooDest = IInPlcRef(hplcRefDest, pcaDest->cpFirst); + +/* Insert new referenced text in docSub of docDest from docSubSrc +from ifooFirst to ifooLim. +*/ + pxsr2 = PxsAlloc(pxbc); + CheckPxs(fPlan, pxsr2, nxsAddRefText, edcDrp); + pxsr2->pcaDel = PcaPoint(&caT1, docSubDest, cpSubDest = + CpPlc(hplcDest,ifooDest)); + pxsr2->pcaIns = PcaSet(&caT2, docSubSrc, cpSubSrc = + CpPlc(hplcSrc, pxsf->ifooFirst), CpPlc(hplcSrc, pxsf->ifooLim)); + XReplaceCps(fPlan, pxbc, pxsr2); + + if (!fPlan) + { +/* Insert new foo's in docDest from docSrc */ +/* open space in destination plc */ + AssertDo(FOpenPlc(hplcRefDest, ifooDest, cfoo)); + AssertDo(FOpenPlc(hplcDest, ifooDest+1, cfoo)); + + CopyMultPlc(cfoo, hplcRefSrc, pxsf->ifooFirst, hplcRefDest, ifooDest, + pcaDest->cpFirst - pcaSrc->cpFirst, 0, 0); + CopyMultPlc(cfoo, hplcSrc, pxsf->ifooFirst, hplcDest, ifooDest, + cpSubDest - cpSubSrc, 1, 0); + InvalAutoReferences(docDest, ifooDest, edcDrp); + } +} + + +/* X D E L R E F E R E N C E D T E X T */ +/* Remove the text of referenced subdocs (footnote or annotation) + that is referenced in *pca */ +/* %%Function:XDelReferencedText %%Owner:peterj %%reviewed: 6/28/89 */ +EXPORT XDelReferencedText(fPlan, pxbc, pxsf, pca, edcDrp) +BOOL fPlan; +struct XBC *pxbc; +struct XSF *pxsf; +struct CA *pca; +int edcDrp; +{ + struct PLC **hplc, **hplcRef; + int cfoo; + int cRef; + int docSub; + struct DRP *pdrp; + struct CA caT; + struct XSR *pxsr2; + + pdrp = ((int *)PdodDoc(pca->doc)) + edcDrp; + docSub = pdrp->doc; +/* test if footnote table exists at all */ + if ((hplcRef = pdrp->hplcRef) == hNil) return; + + if (fPlan) + { + pxsf->ifooFirst = IInPlcRef(hplcRef, pca->cpFirst); + pxsf->ifooLim = IInPlcCheck(hplcRef, pca->cpLim - 1) + 1; + } + + /* this could be positive because of a -1 return value from IInPlcCheck */ + if ((cfoo = pxsf->ifooFirst - pxsf->ifooLim) >= 0) + return; + +#ifdef DEBUG + if (!fPlan) + { + Assert(pxsf->ifooFirst == IInPlcRef(hplcRef, pca->cpFirst)); + Assert(pxsf->ifooLim == IInPlcCheck(hplcRef, pca->cpLim - 1) + 1); + } +#endif /* DEBUG */ + +/* we are deleting cfoo footnotes/annotations... +cp* now refers to footnote/annotation text, not document text.*/ + + hplc = PdodDoc(docSub)->hplcfnd; /* union with hplcand */ + AssertH(hplc); + + pxsr2 = PxsAlloc(pxbc); + CheckPxs(fPlan, pxsr2, nxsDelRefText, edcDrp); + pxsr2->pcaDel = PcaSet(&caT, docSub, CpPlc(hplc, pxsf->ifooFirst), + CpPlc(hplc, pxsf->ifooLim)); + pxsr2->fn = fnNil; + pxsr2->fc = fc0; + pxsr2->dfc = fc0; + XReplace(fPlan, pxbc, pxsr2); + + if (fPlan) + { + PostTn(pxbc, tntHplc, hplc, cfoo); + PostTn(pxbc, tntHplc, hplcRef, cfoo); + } + else + { + AssertDo(FOpenPlc(hplc, pxsf->ifooFirst, cfoo)); + AssertDo(FOpenPlc(hplcRef, pxsf->ifooFirst, cfoo)); + InvalAutoReferences(pca->doc, pxsf->ifooFirst, edcDrp); + } +} + + +/* X D E L E T E H D R T E X T */ +/* deletes the hdd entries/text referenced for the sections about to be +deleted. +*/ +/* %%Function:XDeleteHdrText %%Owner:peterj %%reviewed: 6/28/89 */ +EXPORT XDeleteHdrText(fPlan, pxbc, pxsp, pca) +BOOL fPlan; +struct XBC *pxbc; +struct XSP *pxsp; +struct CA *pca; +{ + int doc = pca->doc; + struct DOD *pdod = PdodDoc(doc); + int docHdr = pdod->docHdr, docHdrDisp, ww; + struct PLC **hplchdd; + struct PLC **hplcsed; + int ihddLim, ihddFirst; + int chdd, ised, isedLim; + struct CA caFirst, caT; + CP cpLim; +#ifdef WIN + struct CA caSectNext; + int grpfIhdtPrev, grpfIhdtNext; + CP cpPrev; +#endif + +/* WARNING: this routine could get called during the !fPlan phase even though it +was not called during the fPlan phase because of the creation of docHdr in +XAddHdrText. make sure that we will return without doing anything anyway (and +don't save any state) */ + + if (!pdod->fMother || docHdr == docNil) + return; + +#ifdef DEBUG + if (fPlan) + pxsp->fCalledXDeleteHdrText = fTrue; +#endif /* DEBUG */ + +/* close or invalidate all header displays whose section is about to be +deleted */ + caHdt.doc = docNil; + hplcsed = pdod->hplcsed; + ised = IInPlc(hplcsed, pca->cpFirst); + isedLim = IInPlc(hplcsed, pca->cpLim); + + if (ised == isedLim) + return; + + docHdrDisp = docHdr; + +/* walk the linked list of display documents displaying this header (there may +be zero, one or more). the linked list is maintained through the docHdr entry +of each dod (note that short DODs have a docHdr too). the chain looks like: + docMother->docHdr->docHdrDisp->docHdrDisp->...->docNil +when entering these loops docHdrDisp is initially docHdr. +*/ + + if (fPlan) + { + while ((docHdrDisp = PdodDoc(docHdrDisp)->docHdr) != docNil) + { + pdod = PdodDoc(docHdrDisp); + if (pdod->ised < ised) + continue; + if (pdod->ised < isedLim) + { + for (ww = WwDisp(docHdrDisp, wwNil, fTrue); ww != wwNil; + ww = WwDisp(docHdrDisp, ww, fTrue)) + if (PwwdWw(ww)->fHdr && + PdrGalley(PwwdWw(ww))->doc == docHdrDisp) + { + PostTn(pxbc, tntCloseHdrWw, ww, 0); + } + } + } + } + + else /* !fPlan */ + { + vdocHdrEdit = docNil; /* stave off rename */ + while ((docHdrDisp = PdodDoc(docHdrDisp)->docHdr) != docNil) + { + pdod = PdodDoc(docHdrDisp); + if (pdod->ised < ised) + continue; + if (pdod->ised >= isedLim) + pdod->ised -= isedLim - ised; + else + { + pdod->ised = -1; /* section no longer exists */ + InvalPageView(docHdrDisp); + } + } + } + +#ifdef REFERENCE /* Mac version (non-bifurcated) */ + if (!fPlan /*&& ised != isedLim*/) + { + docHdrDisp = docHdr; + vdocHdrEdit = docNil; /* stave off rename */ + while ((docHdrDisp = PdodDoc(docHdrDisp)->docHdr) != docNil) + { + pdod = PdodDoc(docHdrDisp); + if (pdod->ised < ised) + continue; + if (pdod->ised >= isedLim) + pdod->ised -= isedLim - ised; + else + { + pdod->ised = -1; /* section no longer exists */ + InvalPageView(docHdrDisp); + for (ww = WwDisp(docHdrDisp, wwNil, fTrue); ww != wwNil; + ww = WwDisp(docHdrDisp, ww, fTrue)) + if (PwwdWw(ww)->fHdr && + PdrGalley(PwwdWw(ww))->doc == docHdrDisp) + { + /* header window or split - close it */ + DisposeWwHdr(ww); + if (mpdochdod[docHdrDisp] == hNil) + { + docHdrDisp = docHdr; + break; /* start over */ + } + ww = wwNil; /* start over */ + } + } + } + } +#endif + +/* we may be applying properites to the section following the section deleted */ +/* ...SedMac used because caSectNext used ultimately for applyGrpPrl */ + CacheSectSedMac(doc, pca->cpLim); + cpLim = caSect.cpFirst; + caSect.doc = docNil; /* to invalidate caSect because SedMac used */ + +#ifdef WIN +/* promote headers if deleting head of chain */ + if (isedLim + 1 < IMacPlc(hplcsed)) /* we had sections following */ + { + grpfIhdtPrev = 0; + grpfIhdtNext = vsepFetch.grpfIhdt; + caSectNext = caSect; + caSectNext.doc = doc; + + if (grpfIhdtNext == 0) + { +/* the deleting sections may be the head of the link for sections +following.*/ + + while (grpfIhdtPrev == 0) + { +/* search backward for the head of the link within the deleting sections. */ + cpPrev = caSect.cpFirst - 1; + if (cpPrev < pca->cpFirst) + break; + Assert(cpPrev >= cp0); + CacheSect(doc, cpPrev); + grpfIhdtPrev = vsepFetch.grpfIhdt; + } + +/* set the grpfIhdt to the remaining section so it becomes the +head of the link. Setup cpLim to collect the ihdds that should +be deleted if necessary. +*/ + if (grpfIhdtPrev != 0) + { + XSetGrpfIhdtPca(fPlan, pxbc, pxsp, grpfIhdtPrev, &caSectNext); + if (cpPrev < pca->cpFirst || + (cpLim = caSect.cpFirst) <= pca->cpFirst) + { + vdocHdrEdit = doc; + return; /* no hdd needs to be deleted, they are being + refered to by the new head of link */ + } + } + } + } + Assert(pca->cpFirst <= cpLim); +#endif /* WIN */ + + ihddLim = IhddFromDocCp(PcaSet(&caT, doc, pca->cpFirst, cpLim), &ihddFirst, 0); + if ((chdd = ihddLim - ihddFirst) > 0) + { + struct XSR *pxsr2; + + /* if we get here, make sure we planed for this (see warning above) */ + Assert(pxsp->fCalledXDeleteHdrText); + + CaFromIhddFirstLim(docHdr, ihddFirst, ihddLim, &caFirst); + + /* Delete the text in docHdr */ + + pxsr2 = PxsAlloc(pxbc); + CheckPxs(fPlan, pxsr2, nxsDelHdrText, 0); + pxsr2->pcaDel = &caFirst; + pxsr2->fn = fnNil; + pxsr2->fc = fc0; + pxsr2->dfc = fc0; + + XReplace(fPlan, pxbc, pxsr2); + + if (fPlan) + PostTn(pxbc, tntHplc, PdodDoc(docHdr)->hplchdd, -chdd); + else + FOpenPlc(PdodDoc(docHdr)->hplchdd, ihddFirst, -chdd); + } + vdocHdrEdit = doc; +} + + +/* X A D D H D R T E X T */ +/* copies any headers in the source to the designated section in the +destination. It is assumed that the sed's/sep's have already been copied. +*/ +/* %%Function:XAddHdrText %%Owner:peterj %%reviewed: 6/28/89 */ +EXPORT XAddHdrText(fPlan, pxbc, pcaSrc, pcaDest) +BOOL fPlan; +struct XBC *pxbc; +struct CA *pcaSrc, *pcaDest; +{ + struct DOD *pdod = PdodDoc(pcaSrc->doc); + int docHdrSrc = pdod->docHdr; + int docHdrDest, docHdr, ww; + struct PLC **hplchddHdrDest; + int ihddDest; + int ihddLim, ihddFirst; + int chdd; + int docDest = pcaDest->doc; + struct PLC **hplcsed; + int csed, ised; + CP cpLim; + struct CA caFirst, caLim, caDest, caT; + struct XSR *pxsr2; + + if (!pdod->fMother) + return(fTrue); + + hplcsed = PdodDoc(pcaSrc->doc)->hplcsed; + if ((csed = IInPlc(hplcsed, pcaSrc->cpLim)-IInPlc(hplcsed, pcaSrc->cpFirst)) + <= 0) + return; + + docHdrDest = PdodDoc(docDest)->docHdr; + if (docHdrSrc == docNil) + { + if (docHdrDest == docNil || fPlan) + return; + goto LCheckSects; + } + +/* count headers up to beginning of last section included in copy. if + copy includes end of section, count headers to end of section */ + caT = *pcaSrc; + CacheSectSedMac(caT.doc, caT.cpLim - 1); + if (caT.cpLim < caSect.cpLim) + caT.cpLim = caSect.cpFirst; + ihddLim = IhddFromDocCp(&caT, &ihddFirst, 0); + + if ((chdd = ihddLim - ihddFirst) > 0) + { + CaFromIhddFirstLim(docHdrSrc, ihddFirst, ihddLim, &caFirst); + +/* now we have Src text. Find destination. */ + if (fPlan) + { + if (docHdrDest == docNil) + { + if ((docHdrDest = DocCreateSub(docDest, dkHdr)) == docNil) + { +LPostAbort: + PostTn(pxbc, tntAbort, NULL, 0); + goto LRet; + } + PdodDoc(docDest)->docHdr = docHdrDest; + } + if ((hplchddHdrDest = PdodDoc(docHdrDest)->hplchdd) == hNil && + (hplchddHdrDest = HplcCreateEdc(mpdochdod[docHdrDest], edcHdd)) + == hNil) + goto LPostAbort; + } + else + { + Assert(docHdrDest != docNil); + hplchddHdrDest = PdodDoc(docHdrDest)->hplchdd; + AssertH(hplchddHdrDest); + } + + CacheSect(docDest, pcaDest->cpFirst); + if ((ihddDest = IhddFromDocCp(PcaSet(&caT,docDest,cp0,caSect.cpFirst), + 0, 0)) == -1) + { + Assert(fFalse); /* this should never happen (?) */ + goto LRet; + } + CaFromIhdd(docHdrDest, ihddDest, &caDest); + caDest.cpLim = caDest.cpFirst; + + pxsr2 = PxsAlloc(pxbc); + CheckPxs(fPlan, pxsr2, nxsAddHdrText, 0); + pxsr2->pcaDel = &caDest; + pxsr2->pcaIns = &caFirst; + + XReplaceCps(fPlan, pxbc, pxsr2); + + if (fPlan) + PostTn(pxbc, tntHplc, hplchddHdrDest, chdd); + else + { +/* note: AdjustCp left ihddDest unadjusted */ + PutCpPlc(hplchddHdrDest, ihddDest, + CpPlc(hplchddHdrDest, ihddDest) + DcpCa(&caFirst)); + +/* open up space in the destination and copy the cp's from the source */ + AssertDo(FOpenPlc(hplchddHdrDest, ihddDest, chdd)); + + CopyMultPlc(chdd, PdodDoc(docHdrSrc)->hplchdd, ihddFirst, + hplchddHdrDest, ihddDest, + caDest.cpFirst - caFirst.cpFirst, 0, 0); + } + } + + if (fPlan) + goto LRet; + +/* invalidate page view for all displayed headers */ +LCheckSects: + if (docHdrDest != docNil) + { + ised = IInPlc(PdodDoc(pcaDest->doc)->hplcsed, pcaDest->cpFirst); + docHdr = docHdrDest; + while ((docHdr = PdodDoc(docHdr)->docHdr) != docNil) + { + pdod = PdodDoc(docHdr); + if (pdod->ised < ised) + continue; + pdod->ised += csed; + InvalPageView(docHdr); + } + } + +LEnd: /* need to do this in !fPlan case only... */ + vdocHdrEdit = docDest; +LRet: + caSect.doc = docNil; /* protection -- used CacheSectSedMac */ +} + + +#ifdef WIN +/* X S E T G R P F I H D T P C A */ +/* apply a grpprl to pca to change the grpfIhdt */ +/* %%Function:XSetGrpfIhdtPca %%Owner:peterj %%reviewed: 6/28/89 */ +XSetGrpfIhdtPca(fPlan, pxbc, pxsp, grpfIhdt, pca) +BOOL fPlan; +struct XBC *pxbc; +struct XSP *pxsp; +int grpfIhdt; +struct CA *pca; +{ + CHAR rgb[2]; +#ifdef DEBUG + struct ESPRM *pesprm; + pesprm = &dnsprm[sprmSGrpfIhdt]; + Assert(pesprm->b == offset(SEP,grpfIhdt)); + Assert(pesprm->sgc == sgcSep); + Assert(pesprm->cch == 2); +#endif + + Assert(!PdodDoc(pca->doc)->fShort); + rgb[0] = sprmSGrpfIhdt; + rgb[1] = (CHAR)grpfIhdt; + XApplyGrpprlDocCp(fPlan, pxbc, pxsp, rgb, 2, pca->doc, pca->cpLim-1); + if (!fPlan && caSect.doc == pca->doc) + caSect.doc = docNil; /* blow cache */ +} + + +/* X A P P L Y G R P P R L D O C C P */ +/* perform a bifuricated applygrpprl. Only good for section sprms currently. +passed in pca must include only one piece. */ +/* %%Function:XApplyGrpprlDocCp %Owner:peterj %%reviewed: 6/28/89 */ +XApplyGrpprlDocCp(fPlan, pxbc, pxsp, grpprl, cb, doc, cp) +BOOL fPlan; +struct XBC *pxbc; +struct XSP *pxsp; +char *grpprl; +int cb; +int doc; +CP cp; +{ + int ipcd; + CP dcp; + struct DOD **hdod = mpdochdod[doc]; + struct PLC **hplcpcd = (*hdod)->hplcpcd; + struct PCD pcd; + + Assert(cb > 0); + + if (cp > CpMacDoc(doc)) + { + cp = CpMacDoc(doc); + dcp = ccpEop; + } + else + dcp = 1; + +/* ensure that, for section sprms, the section table exists */ + Assert(dnsprm[*grpprl/*psprm*/].sgc == sgcSep && + !(*hdod)->fShort && (*hdod)->hplcsed != hNil); + +/* First get address of piece table and split off desired pieces. */ + ipcd = ipcd = IpcdSplit(hplcpcd, cp); + if (ipcd == iNil || IpcdSplit(hplcpcd, cp+dcp) != ipcd+1) + { + Assert(fPlan); +LAbort: + PostTn(pxbc, tntAbort, NULL, 0); + return; + } + +/* Now just add this sprm to the piece. */ + GetPlc(hplcpcd, ipcd, &pcd); + if (fPlan) + { + pxsp->prm = PrmAppend(pcd.prm, grpprl, cb); + /* check for failure of PrmAppend */ + if (vmerr.fFmtFailed) + goto LAbort; + /* don't reclaim this prc if FreeUnusedPrcs is called */ + vmerr.prmDontReclaim = pxsp->prm; + } + else + { + pcd.prm = pxsp->prm; + PutPlc(hplcpcd, ipcd, &pcd); + } + +#ifdef WIN + InvalVisiCache(); +#endif /* WIN */ +} + + +#endif /* WIN */ + +#ifdef WIN + +/* X D E L E T E F I E L D S */ +/* Delete any live fields which begin in the range [cpFirst,cpLim) from the + plcfld. + + NOTE: It is assumed that cpFirst:cpLim is a valid range. A valid range + is one where there are no unmatched field begin-ends. +*/ +/* %%Function:XDeleteFields %%Owner:peterj %%reviewed: 6/28/89 */ +EXPORT XDeleteFields(fPlan, pxbc, pxsl, pca) +BOOL fPlan; +struct XBC *pxbc; +struct XSL *pxsl; +struct CA *pca; +{ + struct PLC **hplcfld = PdodDoc(pca->doc)->hplcfld; + + AssertH(hplcfld); + + if (fPlan) + { + int ifldLim, ifldFirst, ifldMac; + ifldFirst = IInPlcRef (hplcfld, pca->cpFirst); + Assert (ifldFirst <= IMacPlc(hplcfld)); + Assert (ifldFirst >= -1); + if (ifldFirst > -1) + { + ifldLim = IInPlcRef(hplcfld, pca->cpLim); + if ((pxsl->cfld = ifldFirst - ifldLim) < 0) + PostTn(pxbc, tntHplc, hplcfld, pxsl->cfld); + } + else + pxsl->cfld = 0; + } + else if (pxsl->cfld < 0) + { + PdodDoc(pca->doc)->fFldNestedValid = fFalse; + pxsl->ifld = IInPlcRef (hplcfld, pca->cpFirst); + Assert(pxsl->ifld >= 0); + Assert(pxsl->ifld - pxsl->cfld <= IMacPlc(hplcfld)); + FOpenPlc (hplcfld, pxsl->ifld, pxsl->cfld); + if (vddes.cDclClient > 0) + vfDdeIdle = fTrue; + if (!PdodDoc(pca->doc)->fHasNoSeqLev) + vidf.fInvalSeqLev = PdodDoc(pca->doc)->fInvalSeqLev = fTrue; + } +} + + +/* X C O P Y F I E L D S */ +/* Copy all live fields from pcaSrc to pcaDest. */ +/* %%Function:XCopyFields %%Owner:peterj %%reviewed: 6/28/89 */ +EXPORT XCopyFields(fPlan, pxbc, pcaSrc, pcaDest) +BOOL fPlan; +struct XBC *pxbc; +struct CA *pcaSrc, *pcaDest; +{ + int ifld = IfldNextField (pcaSrc->doc, pcaSrc->cpFirst); + CP dcpAdj = pcaDest->cpFirst - pcaSrc->cpFirst; + struct FLCD flcd; + int cfld = 0; + + GetIfldFlcd (pcaSrc->doc, ifld, &flcd); + + while (ifld != ifldNil && flcd.cpFirst < pcaSrc->cpLim) + { + /* else not a valid range to be copying */ + Assert (flcd.cpFirst + flcd.dcpInst + flcd.dcpResult <= pcaSrc->cpLim); + + /* copy this field to docDest */ + if (fPlan) + cfld += 2 + (flcd.dcpResult ? 1 : 0); + else + { + FInsertFltDcps (flcd.flt, pcaDest->doc, flcd.cpFirst+dcpAdj, + flcd.dcpInst, flcd.dcpResult, &flcd); + + if ((uns)(flcd.flt-fltSeqLevOut)<=(fltSeqLevNum-fltSeqLevOut)) + /* invalidate auto numbered fields */ + vidf.fInvalSeqLev = PdodDoc(pcaDest->doc)->fInvalSeqLev = fTrue; + } + + ifld = IfldAfterFlcd (pcaSrc->doc, ifld, &flcd); + } + if (cfld > 0) + { + Assert(fPlan); + if (!FAssureHplcfld(pcaDest->doc, 0)) + PostTn(pxbc, tntAbort, NULL, 0); + else + PostTn(pxbc, tntHplc, PdodDoc(pcaDest->doc)->hplcfld, cfld); + } +} + + +/* X D E L E T E B K M K S */ +/* Delete bookmarks in enclosed in pca. truncate bookmarks that are +partially in the range. */ +/* %%Function:XDeleteBkmks %%Owner:peterj %%reviewed: 6/28/89 */ +EXPORT XDeleteBkmks(fPlan, pxbc, pca, fAll) +BOOL fPlan; +struct XBC *pxbc; +struct CA *pca; +BOOL fAll; /* if true an ins pt bkmk at cpFirst will be deleted */ +{ + CP cpFirstBkmk; + CP cpLimBkmk; + CP cpFirst = pca->cpFirst; + CP cpLim = pca->cpLim; + struct DOD *pdod = PdodDoc(pca->doc); + struct PLC **hplcbkf = pdod->hplcbkf; + struct PLC **hplcbkl = pdod->hplcbkl; + struct STTB **hsttb = pdod->hsttbBkmk; + int ibkf; + int cBkmkDel, cbSttbDel; + struct BKF bkf; + + Assert (!pdod->fShort); + + if (hplcbkf == hNil || hplcbkl == hNil || hsttb == hNil) + return; /* no bookmarks to delete */ + + if (fPlan) + { + cBkmkDel = 0; + cbSttbDel = 0; + } + +/* scan backwards through bookmarks deleting those that are in the range +(backwards so we don't have to adjust when we delete) */ + for (ibkf=IMacPlc(hplcbkf)-1; ibkf >= 0; --ibkf) + if ((cpFirstBkmk = CpPlc(hplcbkf, ibkf)) >= cpFirst && + cpFirstBkmk < cpLim) + { + GetPlc(hplcbkf, ibkf, &bkf); + if ((cpLimBkmk = CpPlc(hplcbkl, bkf.ibkl)) <= cpLim && + (cpLimBkmk > cpFirst || fAll)) + if (fPlan) + { + /* 2=overhead of sttb entry (ibst), 1=length byte of st */ + cbSttbDel += 2 + 1 + *HpstFromSttb(hsttb, ibkf); + cBkmkDel++; + } + else + { +#ifdef PCJ + CommSzNum(SzShared("deleting ibkf = "), ibkf); +#endif /* PCJ */ + DeleteIbkf(pca->doc, ibkf, hsttb, hplcbkf, hplcbkl, NULL); + } + } + + if (!fPlan) + { + /* truncate intersecting portions of bookmarks which are only partially + enclosed in the range */ + ChangeCpsInRange(hplcbkf, cpFirst+1, cpLim, cpLim); + ChangeCpsInRange(hplcbkl, cpFirst+1, cpLim, cpFirst); + } + else if (cBkmkDel) + { + PostTn(pxbc, tntHsttb, hsttb, -cbSttbDel); + PostTn(pxbc, tntHplc, hplcbkf, -cBkmkDel); + PostTn(pxbc, tntHplc, hplcbkl, -cBkmkDel); + PostTn(pxbc, tntDelBkmk, pca->doc, 0); + } +} + + +/* C H A N G E C P S I N R A N G E */ +/* change all rgcp entries in the range [cpFirst,cpLim) to be cpNew. */ +/* %%Function:ChangeCpsInRange %%Owner:peterj %%reviewed: 6/28/89 */ +ChangeCpsInRange(hplc, cpFirst, cpLim, cpNew) +struct PLC **hplc; +CP cpFirst, cpLim, cpNew; +{ + int icp, iMac; + + iMac = IMacPlc(hplc); + for (icp = max(IInPlcCheck(hplc, cpFirst), 0); icp < iMac; icp++) + { + CP cp = CpPlc(hplc, icp); + if (cp >= cpLim) + break; + if (cp >= cpFirst) + { +#ifdef PCJ + CommSzNum(SzShared("Changing icp = "), icp); +#endif /* PCJ */ + PutCpPlc(hplc, icp, cpNew); + } + } +} + + +/* X C O P Y B K M K S */ +/* Copy bookmarks in pcaSrc to pcaDest. (pcaDest->cpLim ignored) */ +/* %%Function:XCopyBkmks %%Owner:peterj %%reviewed: 6/28/89 */ +EXPORT XCopyBkmks(fPlan, pxbc, pxsb, pcaSrc, pcaDest) +BOOL fPlan; +struct XBC *pxbc; +struct XSB *pxsb; +struct CA *pcaSrc, *pcaDest; + +{ + int docDest = pcaDest->doc; + struct DOD *pdod = PdodDoc(pcaSrc->doc); + struct STTB **hsttb = pdod->hsttbBkmk; + struct PLC **hplcbkf = pdod->hplcbkf; + struct PLC **hplcbkl = pdod->hplcbkl; + struct STTB **hsttbDest = hNil; + struct PLC **hplcbkfDest; + struct PLC **hplcbklDest; + int ibkf, ibkfLim, ibklLim, iMac; + struct BKF bkf; + struct CA caT; + CP dcp; + int cBkmkIns, cbSttbIns; + + caT = *pcaSrc; + + Assert (docDest != caT.doc); + Assert (!PdodDoc (docDest)->fShort && !PdodDoc (caT.doc)->fShort); + Assert (caT.cpLim > caT.cpFirst); + + if (caT.cpFirst >= CpMacDoc(caT.doc)) + return; + + if (caT.cpLim > CpMacDoc(caT.doc)) + caT.cpLim = CpMacDoc(caT.doc); + + if (hplcbkf == hNil || hplcbkl == hNil || hsttb == hNil) + return; /* no bookmarks to copy */ + + /* adjustment for starting cp in the different documents */ + dcp = pcaDest->cpFirst - caT.cpFirst; + + /* hplcbkf and hplcbkl are related plcs. they should have the same iMac */ + Assert(IMacPlc(hplcbkf) == IMacPlc(hplcbkl)); + if ((iMac = IMacPlc(hplcbkf)) == 0) + return; + + if (fPlan) + { + cBkmkIns = 0; + cbSttbIns = 0; + + pxsb->ibkf = pxsb->ibkfLim = 0; + + /* ibklLim is first ibkl st cp > caT.cpLim */ + if (CpPlc(hplcbkl, 0) <= caT.cpLim) + { + ibklLim = IInPlc (hplcbkl, caT.cpLim); + while (CpPlc(hplcbkl, ibklLim) <= caT.cpLim && ibklLim < iMac) + ibklLim++; + } + else + return; /* none fully enclosed */ + + /* ibkfLim is first ibkf st cp >= caT.cpLim */ + if (CpPlc(hplcbkf, 0) < caT.cpLim) + { + ibkfLim = IInPlcMult (hplcbkf, caT.cpLim); +/* FUTURE davidlu(pj): this should be unnecessary when the new implementation + if IInPlc(Mult)Ref is in place (change the above to Ref) */ + while (CpPlc(hplcbkf, ibkfLim) < caT.cpLim && ibkfLim < iMac) + ibkfLim++; + } + else + return; /* none fully enclosed */ + + /* ibkf is first ibkf st cp >= caT.cpFirst */ + if (CpPlc(hplcbkf, 0) <= caT.cpFirst) + { + ibkf = IInPlcMult (hplcbkf, caT.cpFirst); +/* FUTURE davidlu(pj): this should be unnecessary when the new implementation + if IInPlc(Mult)Ref is in place (change the above to Ref) */ + while (CpPlc(hplcbkf, ibkf) < caT.cpFirst && ibkf < iMac) + ibkf++; + } + else + ibkf = 0; + + pxsb->ibkf = ibkf; + pxsb->ibkfLim = ibkfLim; + pxsb->ibklLim = ibklLim; + } + else + { + ibkf = pxsb->ibkf; + ibkfLim = pxsb->ibkfLim; + ibklLim = pxsb->ibklLim; + } + + while (ibkf < ibkfLim) + { + GetPlc(hplcbkf, ibkf, &bkf); + if (bkf.ibkl < ibklLim) + if (fPlan) + { + if (hsttbDest == hNil) + /* get the destination handles */ + { + if (!FAssureBkmksForDoc(docDest)) + { + PostTn(pxbc, tntAbort, NULL, 0); + return; + } + else + { + struct DOD *pdodT = PdodDoc(docDest); + hsttbDest = pdodT->hsttbBkmk; + hplcbkfDest = pdodT->hplcbkf; + hplcbklDest = pdodT->hplcbkl; + } + } + cbSttbIns += 3 + *HpstFromSttb(hsttb, ibkf); + cBkmkIns++; + } + else + { + char *pst, st [cchBkmkMax]; + struct CA caBkmk; + + PcaSet(&caBkmk, caT.doc, CpPlc(hplcbkf, ibkf), + CpPlc(hplcbkl, bkf.ibkl)); + + Assert( FCaInCa( &caBkmk, pcaSrc ) ); + + caBkmk.cpFirst += dcp; /* convert to dest units */ + caBkmk.cpLim += dcp; + caBkmk.doc = docDest; + + GetStFromSttb(hsttb, ibkf, st); + Assert(st[0] < cchBkmkMax); + + Assert (DcpCa(&caBkmk) >= 0 && caBkmk.cpFirst >= cp0 ); + AssertDo(FInsertStBkmk(&caBkmk, st, NULL)); + } + ibkf++; + } + + if (fPlan && cBkmkIns) + { + PostTn(pxbc, tntHsttb, hsttbDest, cbSttbIns); + PostTn(pxbc, tntHplc, hplcbkfDest, cBkmkIns); + PostTn(pxbc, tntHplc, hplcbklDest, cBkmkIns); + } +} + + +/* F A S S U R E B K M K S F O R D O C */ +/* Assure that the necessary structures for bookmarks exist for the passed in +doc. */ +/* %%Function:FAssureBkmksForDoc %%Owner:peterj %%reviewed: 6/28/89 */ +FAssureBkmksForDoc(doc) +int doc; +{ + struct DOD *pdod = PdodDoc(doc); + + Assert(!pdod->fShort); + + if (pdod->hsttbBkmk == hNil) + { + struct STTB **hsttb = hNil; + struct PLC **hplcbkf = hNil; + struct PLC **hplcbkl = hNil; + + Assert (pdod->hplcbkl == hNil && pdod->hplcbkf == hNil); + if ((hsttb = HsttbInit (0, fTrue)) == hNil || + (hplcbkf=HplcInit(cbBKF, 1, CpMac2Doc(doc), fTrue/*fExt*/)) == hNil || + (hplcbkl=HplcInit(cbBKL, 1, CpMac2Doc(doc), fTrue/*fExt*/)) == hNil) + { + FreeHsttb (hsttb); + FreeHplc (hplcbkf); + FreeHplc (hplcbkl); + return fFalse; + } + Win((*hplcbkf)->fMult = fTrue); + Win((*hplcbkl)->fMult = fTrue); + pdod = PdodDoc(doc); + pdod->hsttbBkmk = hsttb; + pdod->hplcbkf = hplcbkf; + pdod->hplcbkl = hplcbkl; + pdod->fFormatted = fTrue; + } + return fTrue; +} + + +/* F I N S E R T S T B K M K */ +/* Insert st into the bookmark structures of document doc. Limits st +to cchBkmkMax characters. Initializes the bookmark structures of doc +if not already initialized. If pfUndoCancel is non-null then the +undo document will be set up, and the flag returned in pfUndoCancel +will be true iff the user refused to continue without undo. +*/ +/* %%Function:FInsertStBkmk %%Owner:peterj %%reviewed: 6/28/89 */ +FInsertStBkmk (pca, st, pfUndoCancel) +struct CA *pca; +char *st; +int *pfUndoCancel; +{ + int doc = pca->doc; + struct DOD **hdod = mpdochdod [doc]; + struct STTB **hsttb; + struct PLC **hplcbkf; + struct PLC **hplcbkl; + int ibkf, ibkl, ibkfMac; + struct BKF bkf; + struct CA caUndo; + + Assert (hdod != hNil); + Assert (!(*hdod)->fShort); + Assert (pca->cpFirst >= cp0 && + pca->cpLim < CpMac1Doc(pca->doc) && + pca->cpFirst <= pca->cpLim); + + if (pfUndoCancel) + { + *pfUndoCancel = fFalse; + if (!FSetPcaForBkmkUndo(&caUndo, doc, pca->cpFirst, pca->cpLim, fTrue)) + /* alas, cannot undo some bookmark actions */ + { + SetUndoNil(); + pfUndoCancel = NULL; + } + } + + /* insure st ok size */ + if (*st >= cchBkmkMax) + *st = cchBkmkMax - 1; + + /* only insert legal bookmark names */ + if (!FLegalBkmkName (st)) + return fFalse; + + /* initialize bookmarks if needed */ + if (!FAssureBkmksForDoc(doc)) + return fFalse; + + hsttb = (*hdod)->hsttbBkmk; + hplcbkf = (*hdod)->hplcbkf; + hplcbkl = (*hdod)->hplcbkl; + + if (IMacPlc(hplcbkf) >= ibkmkMax) + /* limit on number of bookmarks has been reached */ + return fFalse; + + /* if bookmark already exists, delete it */ + if (FSearchSttbUnsorted (hsttb, st, &ibkf)) + { + /* keep same case as it had before */ + GetStFromSttb(hsttb, ibkf, st); + DeleteIbkf (doc, ibkf, hsttb, hplcbkf, hplcbkl, pfUndoCancel); + if (pfUndoCancel && *pfUndoCancel) + return fFalse; + } + + else if (pfUndoCancel) + { + AssureLegalSel(&caUndo); + if (!FSetUndoB1(ucmChangeBkmk, uccFormat, &caUndo)) + { + *pfUndoCancel = fTrue; + return fFalse; + } + } + + /* Insert new bookmark */ + + /* determine if we can grow everything enough */ + if (!vfInCommit) + /* already guaranteed if vfInCommit */ + { + if (!FStretchSttb(hsttb, 1, *st) || !FStretchPlc(hplcbkf, 1) + || !FStretchPlc(hplcbkl, 1)) + /* cannot grow structs to contain new data, bag out! */ + return fFalse; + } + + if (CpPlc(hplcbkl, 0) < pca->cpLim) + { +/* FUTURE davidlu(pj): a call to the fixed IInPlcRef should replace this */ + ibkl = IInPlc (hplcbkl, pca->cpLim); + while (CpPlc(hplcbkl, ibkl) < pca->cpLim) + ibkl++; + } + else + ibkl = 0; + ibkfMac = IMacPlc(hplcbkf); + for (ibkf = 0; ibkf < ibkfMac; ibkf++) + { + GetPlc(hplcbkf, ibkf, &bkf); + if (bkf.ibkl >= ibkl) + { + bkf.ibkl++; + PutPlcLast(hplcbkf, ibkf, &bkf); + } + } + + if (CpPlc(hplcbkf, 0) < pca->cpFirst) + { +/* FUTURE davidlu(pj): a call to the fixed IInPlcRef should replace this */ + ibkf = IInPlc (hplcbkf, pca->cpFirst); + while (CpPlc(hplcbkf, ibkf) < pca->cpFirst) + ibkf++; + } + else + ibkf = 0; + + /* fix up dde server pl (refers to ibkfs) */ + if (vddes.hplddli != hNil) + { + int iddli; + struct DDLI ddli; + + for ( iddli = 0 ; iddli < IMacPl(vddes.hplddli); iddli++ ) + { + GetPl( vddes.hplddli, iddli, &ddli ); + if (ddli.ibkf >= ibkf && ddli.ibkf != ibkmkNil && + PdcldDcl(ddli.dcl)->doc == doc) + { + ddli.ibkf++; + PutPl( vddes.hplddli, iddli, &ddli ); + } + } + + if (vddes.fInvalidDdli) /* so we will try to validate later */ + vfDdeIdle = fTrue; + } + + bkf.ibkl = ibkl; + Assert (ibkf <= ibkfMac && ibkl <= ibkfMac); + + /* these will work because of the stretches above */ + AssertDo(FInsStInSttb (hsttb, ibkf, st)); + AssertDo(FInsertInPlc (hplcbkf, ibkf, pca->cpFirst, &bkf)); + AssertDo(FInsertInPlc (hplcbkl, ibkl, pca->cpLim, NULL)); + + /* check to see if we need to adjust Find Next info */ + if (fni.is == isGotoBkmk && fni.doc == pca->doc && ibkf <= fni.ibkf) + fni.ibkf++; + + /* dirty the document */ + (*hdod)->fDirty = fTrue; + if (pfUndoCancel) + SetUndoAfter(&caUndo); + return fTrue; +} + + +/* D E L E T E I B K F */ +/* Delete a bookmark indexed by ibkf. does not delete structures and +assumes bookmark structures exist. */ +/* %%Function:DeleteIbkf %%Owner:peterj %%reviewed: 6/28/89 */ +DeleteIbkf (doc, ibkfDel, hsttb, hplcbkf, hplcbkl, pfUndoCancel) +int doc; +int ibkfDel; +struct STTB **hsttb; +struct PLC **hplcbkf; +struct PLC **hplcbkl; +int *pfUndoCancel; +{ + int ibkl, ibkfT, ibkfMac; + struct BKF bkf; + struct CA caUndo; + + Assert (ibkfDel >= 0 && ibkfDel < ibkmkMax); + + GetPlc(hplcbkf, ibkfDel, &bkf); + ibkl = bkf.ibkl; + + if (pfUndoCancel) + { + *pfUndoCancel = fFalse; + if (!FSetPcaForBkmkUndo(&caUndo, doc, CpPlc(hplcbkf, ibkfDel), + CpPlc(hplcbkl, ibkl), fFalse)) + /* alas, cannot undo some bookmarks */ + { + SetUndoNil(); + pfUndoCancel = NULL; + } + else + { + AssureLegalSel(&caUndo); + if (!FSetUndoB1(ucmChangeBkmk, uccFormat, &caUndo)) + { + *pfUndoCancel = fTrue; + return; + } + } + } + + /* delete string and cpFirst entry */ + DeleteIFromSttb (hsttb, ibkfDel); + FOpenPlc (hplcbkf, ibkfDel, -1); + + /* update pointers from cpFirst plc to cpLim plc */ + ibkfMac = IMacPlc(hplcbkf); + for (ibkfT = 0; ibkfT < ibkfMac; ibkfT++) + { + GetPlc(hplcbkf, ibkfT, &bkf); + Assert (bkf.ibkl != ibkl); + if (bkf.ibkl > ibkl) + { + bkf.ibkl--; + PutPlcLast(hplcbkf, ibkfT, &bkf); + } + } + + /* delete entry from cpLim plc */ + FOpenPlc (hplcbkl, ibkl, -1); + + /* fix up dde server pl */ + if (vddes.hplddli != hNil) + { + int iddli; + struct DDLI ddli; + + for ( iddli = 0; iddli < IMacPl( vddes.hplddli ); iddli++ ) + { + GetPl( vddes.hplddli, iddli, &ddli ); + if (ddli.ibkf >= ibkfDel && ddli.ibkf != ibkmkNil && + PdcldDcl (ddli.dcl)->doc == doc) + { + if (ddli.ibkf == ibkfDel) + { + ddli.ibkf = ibkmkNil; + vddes.fInvalidDdli = fTrue; /* dde link points to nothing */ + DdeDbgCommAtom ("Invalidating Link", ddli.dcl, ddli.atomItem); + } + else + ddli.ibkf--; + PutPl( vddes.hplddli, iddli, &ddli ); + } + } + } + + /* adjust Find Next info */ + if (fni.is == isGotoBkmk && fni.doc == doc) + { + if (ibkfDel == fni.ibkf) + { + if (vfbSearch.fInfo) + fni.is = isSearch; + else + fni.is = isNever; + } + else if (ibkfDel < fni.ibkf) + fni.ibkf--; + } + + if (pfUndoCancel) + SetUndoAfter(&caUndo); +} + + +/* F S E T P C A F O R B K M K U N D O */ +/* because of the way bookmark invalidation/adjustment is performed, some +bookmark deletions cannot be undone. */ +/* %%Function:FSetPcaForBkmkUndo %%Owner:peterj %%reviewed: 6/28/89 */ +FSetPcaForBkmkUndo(pcaUndo, doc, cpFirst, cpLim, fInsertion) +struct CA *pcaUndo; +int doc; +CP cpFirst, cpLim; +BOOL fInsertion; /* true for insertion of bkmk, false of deletion */ +{ + Assert(fInsertion == 0 || fInsertion == 1); + + if (cpLim >= CpMacDoc(doc) || (fInsertion && cpFirst == cp0)) + return fFalse; + + PcaSet(pcaUndo, doc, cpFirst-fInsertion, cpLim+1); + return fTrue; +} + + +#endif /* WIN */ + + +#ifdef PROFILE +/* this is here so that appended native code does not appear in previous + function in pcode profiles. */ +Edit_Last(){} +#endif /* PROFILE */ + +/* ADD NEW CODE *ABOVE* Edit_Last() */ diff --git a/src/Opus/FIELDCMD.C b/src/Opus/FIELDCMD.C new file mode 100644 index 0000000..a867399 --- /dev/null +++ b/src/Opus/FIELDCMD.C @@ -0,0 +1,1431 @@ +/* F I E L D C M D . C */ +/* Field commands module */ + +#ifdef DEBUG +#ifdef PCJ +/* #define SHOWCALC */ +/* #define DFLDS */ +#endif /* PCJ */ +#endif /* DEBUG */ + +#include "word.h" +DEBUGASSERTSZ /* WIN - bogus macro for assert string */ +#include "heap.h" +#include "props.h" +#include "doc.h" +#include "sel.h" +#include "ch.h" +#include "message.h" +#define EXTMATH +#include "ourmath.h" +#include "format.h" +#include "inter.h" +#include "print.h" +#include "disp.h" +#include "dde.h" +#include "file.h" +#include "strtbl.h" +#define FINDNEXT +#include "search.h" +#include "doslib.h" +#include "border.h" +#include "error.h" +#include "debug.h" +#include "field.h" +#include "toc.h" +#include "opuscmd.h" +#include "pic.h" + +#ifdef PROTOTYPE +#include "fieldcmd.cpt" +#endif /* PROTOTYPE */ + +/* E X T E R N A L S */ + +extern struct SEL selCur; +extern struct PREF vpref; +extern struct CA caAdjust; /* used while traversing fields during calc */ +extern int docMac; +extern struct CA caPara; +extern struct CHP vchpFetch; +extern CHAR szError[]; +extern struct MERR vmerr; +extern CP vcpFirstLayout; +extern CP vcpLimLayout; +extern HCURSOR vhcArrow; +extern struct DOD **mpdochdod []; +extern struct CA caSect; +extern int vfExtendSel; +extern int vwFieldCalc; +extern union RRU vrruCalc; +extern struct PMD *vppmd; +extern int wwCur; +extern struct WWD **hwwdCur; +extern struct DDES vddes; +extern BOOL vfDdeIdle; +extern struct UAB vuab; +extern ENV *penvMathError; +extern CHAR rgchEop[]; +extern struct TCC vtcc; +extern BOOL vfSeeSel; +extern struct PIC vpicFetch; /* picture prefix from FetchPe */ + + +/* C M D L E V E L F U N C T I O N S */ + + + +/* C M D I N S E R T F I E L D */ +/* Insert a open field and close field character at the current selection + (if !fIns, fieldify selection). Place an insertion point between + the inserted characters. +*/ +/* %%Function:CmdInsertField %%Owner:peterj */ +CMD CmdInsertField (pcmb) +CMB *pcmb; +{ + int cmd; + struct CA ca, caT; + CP dcp; + struct DOD *pdod; + BOOL fInsertEmpty; /* insert empty field characters */ + + if ((*hwwdCur)->fPageView && (*hwwdCur)->grpfvisi.grpfShowResults + && !(*hwwdCur)->grpfvisi.fvisiShowAll) + /* force ViewFieldCodes on */ + SetViewResultsFltg(wwCur, fltgOther, fFalse); + + ca = selCur.ca; + + /* selCur.chp is used to determine the chp for the field chars */ + GetSelCurChp (fFalse); + + TurnOffSel (&selCur); + + if (fInsertEmpty = (selCur.sk == skIns)) + { + if (!FSetUndoB1(imiInsField, uccPaste, PcaPoint(&caT, selCur.doc, selCur.cpFirst))) + return cmdCancelled; + ca.cpLim = ca.cpFirst; + } + else + { + if (!FSetUndoBefore(imiInsField, uccPaste)) + return cmdCancelled; + ca.cpLim = CpMin (ca.cpLim, CpMacDocEdit (ca.doc)); + } + + if (((pdod = PdodDoc(ca.doc))->fFtn || pdod->fAtn) && + !FCheckRefDoc(ca.doc, ca.cpFirst, ca.cpLim, fTrue)) + return cmdError; + + if (fInsertEmpty) + { + FInsertFieldDocCp (ca.doc, ca.cpFirst, fFalse/*fSeparator*/); + ca.cpLim += 2; + } + else + { + /* don't allow field char w/o intervening para mark before a table */ + if (FInTableDocCp(ca.doc, ca.cpLim)) + { + CacheTc(wwNil, ca.doc, ca.cpLim, fFalse, fFalse); + if (ca.cpFirst < vtcc.cpFirst) + { + Beep(); + return cmdError; + } + } + if (FInTableDocCp(ca.doc, ca.cpFirst)) + { + CacheTc(wwNil, ca.doc, ca.cpFirst, fFalse, fFalse); + if (ca.cpLim >= vtcc.cpLim) + { + Beep(); + return cmdError; + } + } + dcp = DcpCa(&ca); + FPutCpsInField (fltUnknownKwd, ca.doc, ca.cpFirst, &dcp, cp0, NULL); + ca.cpLim = ca.cpFirst + dcp + 2; + } + + if (vmerr.fMemFail || vmerr.fDiskFail) + return cmdNoMemory; + + DirtyDoc (ca.doc); + SelectIns(&selCur, ca.cpFirst+1); + PushInsSelCur(); + TurnOnSelCur(); + SetUndoAfter(&ca); + + return cmdOK; +} + + +/* D C P U N L I N K I F L D */ +/* Replace field ifld with its result. +*/ +/* %%Function:DcpUnlinkIfld %%Owner:peterj */ +CP DcpUnlinkIfld(doc, ifld) +int doc, ifld; +{ + struct EFLT eflt; + struct FLCD flcd; + CP dcpInst, dcpResult=0; + int cch = 0; + struct CA caT; + +#ifdef DFLDS + CommSzNum(SzShared("DcpUnlinkIfld: ifld = "), ifld); +#endif /* DFLDS */ + + GetIfldFlcd (doc, ifld, &flcd); + eflt = EfltFromFlt (flcd.flt); + + if (flcd.flt == fltImport) + { + /* let import metafiles (post winword 1.1, which stored bogus + metafiles) be unlinked and left behind. + Just restrict TIFF and the old format metafiles. + */ + CP cpImport = flcd.cpFirst + flcd.dcpInst; /* cp of chPic char */ + +#ifdef BZ + CommSzLong(SzShared("unlink import cp "), cpImport); +#endif /* BZ */ + + if (ChFetch(doc, cpImport, fcmChars + fcmProps) == + chPicture && vchpFetch.fSpec) + { + FetchPe(&vchpFetch, doc, cpImport); + + // false if TIFF or old format metafile, else true + eflt.fResult = + !(vpicFetch.mfp.mm == MM_TIFF || + (vpicFetch.mfp.mm < MM_META_MAX && + !FEmptyRc(&vpicFetch.rcWinMF))); + } + +#ifdef DEBUG + else + Assert (fFalse); +#endif /* DEBUG */ + + } + + + if (eflt.fResult) + { /* preserve the result */ + cch = CchRmFieldAtDocCp (doc, flcd.cpFirst, &dcpInst, &dcpResult); + + if (dcpInst != 0) + FDelete( PcaSetDcp( &caT, doc, flcd.cpFirst, dcpInst )); + } + else + /* no result, delete whole field */ + FDelete( PcaSetDcp( &caT, doc, flcd.cpFirst, + flcd.dcpInst+flcd.dcpResult) ); + + return cch + DcpCa(&caT); /* number chars deleted */ + +} + + +/* C M D R E P L A C E F I E L D */ +/* Replace fields with their last result */ + +/* %%Function:CmdReplaceField %%Owner:peterj */ +CMD CmdReplaceField (pcmb) +CMB *pcmb; +{ + int ifldFirst = IfldSelCur (); + int ifld; + struct FLD fld; + struct PLC **hplcfld = PdodDoc(selCur.doc)->hplcfld; + struct CA caT; + int cfld = 0; + CP cpLimSel = selCur.cpLim + (selCur.fIns ? 1 : 0); + CP cpFirst, cpLim = -1, cpT; + BOOL fUndo = fTrue; + + if (selCur.fBlock || ifldFirst == ifldNil) + /* no live field in the current selection. FUTURE: would it be + interesting to do something with dead fields? i.e. Delete them? + Note that if the user is in a dead field nested in a live field + then the live field will be replaced. + */ + { + Beep(); + return cmdError; + } + + TurnOffSel(&selCur); + +#ifdef DFLDS + CommSzRgNum(SzShared("ca Before: "), &caAdjust, 5); +#endif /* DFLDS */ + + cpFirst = CpFirstField(selCur.doc, ifldFirst); + + ifld = IInPlcCheck(hplcfld, cpLimSel-1); + cpLim = CpMax(CpLimField(selCur.doc, IfldFromDocCp(selCur.doc, CpPlc(hplcfld, + ifld), fTrue)), CpLimField(selCur.doc, ifldFirst)); + + /* BLOCK */ + { + struct DOD *pdod = PdodDoc(selCur.doc); + PcaSet(&caT, selCur.doc, cpFirst, cpLim); + if ((pdod->fFtn || pdod->fAtn) && !FCheckLargeEditFtn(&caT, &fUndo)) + return cmdCancelled; + if (fUndo && !FSetUndoB1(bcmDerefField, uccPaste, &caT)) + return cmdCancelled; + } + + AcquireCaAdjust(); + caAdjust = selCur.ca; + + if (caAdjust.cpFirst > cpFirst || caAdjust.cpLim < cpLim) + caAdjust.doc = docNil; + + while (ifld >= ifldFirst && !vmerr.fMemFail && !vmerr.fDiskFail) + { + GetPlc(hplcfld, ifld, &fld); + if (fld.ch == chFieldBegin) + cpLim -= DcpUnlinkIfld(selCur.doc, ifld); + ifld--; + } + +#ifdef DFLDS + CommSzRgNum(SzShared("ca After: "), &caAdjust, 5); +#endif /* DFLDS */ + + if (caAdjust.doc == docNil) + { + caAdjust.cpFirst = cpFirst; + caAdjust.cpLim = cpLim; + } + + Select (&selCur, caAdjust.cpFirst, caAdjust.cpLim); + ReleaseCaAdjust(); + + if (fUndo) + SetUndoAfter(PcaSet(&caT, selCur.doc, cpFirst, cpLim)); + else + SetUndoNil(); + DirtyDoc (selCur.doc); + + return cmdOK; + +} + + +/* C M D N E X T F I E L D */ +/* Goto the next live field from selCur.cpFirst +*/ + +/* %%Function:CmdNextField %%Owner:peterj */ +CMD CmdNextField (pcmb) +CMB *pcmb; +{ + if (!FNextField()) + { + Beep(); + return cmdError; + } + + return cmdOK; +} + + +/* %%Function:FNextField %%Owner:peterj */ +FNextField() +{ + + int ifld; + CP cp; + struct WWD *pwwd = *hwwdCur; + struct CA ca; + extern FNI fni; + + Assert (PselActive() == &selCur); + + if (selCur.fBlock) + return fFalse; + +/* If sel is off screen, start from first cp on screen */ + EnsureSelInWw(fTrue, &selCur); + + cp = vfExtendSel ? selCur.cpLim : selCur.cpFirst+1; + if ((ifld = IfldNextField (selCur.doc, cp)) == ifldNil) + return fFalse; + + /* else select field ifld */ + + PcaField( &ca, selCur.doc, ifld ); + MakeExtendSel(&selCur, ca.cpFirst, ca.cpLim, 0 /*grpf*/); + + if (vfSeeSel && hwwdCur != hNil) + { + SeeSel1(fTrue); + vfSeeSel = fFalse; + } + + fni.is = isNextFld; + return fTrue; +} + + +/* C M D P R E V I O U S F I E L D */ +/* Goto the previous live field from selCur.cpFirst +*/ + +/* %%Function:CmdPreviousField %%Owner:peterj */ +CMD CmdPreviousField (pcmb) +CMB *pcmb; +{ + if (!FPrevField()) + { + Beep(); + return cmdError; + } + + return cmdOK; +} + + +/* %%Function:FPrevField %%Owner:peterj */ +FPrevField() +{ + CP cp; + int ifld; + struct WWD *pwwd = *hwwdCur; + struct PLC **hplcfld = PdodDoc (selCur.doc)->hplcfld; + extern FNI fni; + struct FLD fld; + + Assert (PselActive() == &selCur); + + if (selCur.fBlock) + return fFalse; + +/* If sel is off screen, start from first cp on screen */ + EnsureSelInWw(fTrue, &selCur); + + cp = vfExtendSel ? selCur.cpLim : selCur.cpFirst+1; + if ((ifld = IfldSelCur ()) == ifldNil) + if ((ifld = IfldNextField (selCur.doc, cp)) == ifldNil) + if (hplcfld != hNil) + ifld = IMacPlc(hplcfld); + + while (--ifld >= 0) + { + GetPlc (hplcfld, ifld, &fld); + if (fld.ch == chFieldBegin) + break; + } + + if (ifld < 0) + return fFalse; + + /* else select field ifld */ + + MakeExtendSel(&selCur, CpFirstField (selCur.doc, ifld), CpLimField (selCur.doc, ifld), 0 /*grpf*/); + + if (vfSeeSel && hwwdCur != hNil) + { + SeeSel1(fTrue); + vfSeeSel = fFalse; + } + + fni.is = isPrevFld; + return fTrue; +} + + +/* C M D F I E L D C O D E S */ +/* This toggles the show results mode for fields in fltgOther. +*/ + +/* %%Function:CmdFieldCodes %%Owner:peterj */ +CMD CmdFieldCodes(pcmb) +CMB *pcmb; +{ + if (hwwdCur == hNil || (*hwwdCur)->grpfvisi.fvisiShowAll) + { + Beep(); + return cmdError; + } + + SetViewResultsFltg(wwCur, fltgOther, + !FFromIGrpf(fltgOther, (*hwwdCur)->grpfvisi.grpfShowResults)); + MakeSelCurVisi(fTrue /*fForceBlockToIp*/); + return cmdOK; +} + + + + +/* C M D T O G G L E F I E L D D I S P L A Y */ +/* This function toggles the Show Results/Show Instructions mode for all + fields in the current selection. Toggles the first field and + brings all others into alingment with that one. +*/ + +/* %%Function:CmdToggleFieldDisplay %%Owner:peterj */ +CMD CmdToggleFieldDisplay (pcmb) +CMB *pcmb; +{ + int doc = selCur.doc; + CP cpFirst, cpLim = cpNil; + CP cpImport; + struct CA ca; + int ifld = IfldSelCur (); + int dcpIns = selCur.fIns ? 1 : 0; + BOOL fDifferNew; + struct FLCD flcd; + + if (selCur.fBlock || hwwdCur == hNil || (*hwwdCur)->grpfvisi.fvisiShowAll) + { + goto LBeep; + } + + if ((*hwwdCur)->fPageView) + return CmdFieldCodes(pcmb); + + GetIfldFlcd (doc, ifld, &flcd); + fDifferNew = !flcd.fDiffer; + cpFirst = flcd.cpFirst; + + while (ifld != ifldNil && flcd.cpFirst < selCur.cpLim+dcpIns) + { + flcd.fDiffer = fDifferNew; + SetFlcdCh (doc, &flcd, chFieldEnd); /* write out the new fDiffer */ + cpLim = CpMax (cpLim, flcd.cpFirst + flcd.dcpInst + flcd.dcpResult); + ifld = IfldAfterFlcd (doc, ifld, &flcd); + } + + if (cpLim == cpNil) + { + /* no fields in selection feedback */ +LBeep: + Beep (); + return cmdError; + } + + PcaSet( &ca, doc, cpFirst, cpLim ); + CheckInvalCpFirst (&ca); + InvalCp (&ca); + MakeSelCurVisi(fFalse/*fForceBlockToIp, since selCur.fBlock already being rejected */); + /* when toggling a picture import field, we might not call select, + and so the graphics bit would not be set when it should be + and vice versa + */ + if (FCaIsGraphics(&selCur.ca, selCur.ww, &cpImport)) + selCur.sk = skGraphics; + else + /* can't change the sk in this case, don't know what to + set other bits to + */ + selCur.fGraphics = fFalse; + + + return cmdOK; +} + + + + + +/* C M D F I E L D L O C K S O N */ +/* Turn on the field locks in the current selection. +*/ + +/* %%Function:CmdFldLocksOn %%Owner:peterj */ +CMD CmdFldLocksOn (pcmb) +CMB *pcmb; +{ + int dcpIns = selCur.fIns ? 1 : 0; + + if (selCur.fBlock) + { + Beep(); + return cmdError; + } + + if (!FSetFieldLocks (fTrue, selCur.doc, IfldSelCur(), + selCur.cpLim+dcpIns)) + Beep (); + else + DirtyDoc (selCur.doc); + return cmdOK; +} + + + +/* C M D F I E L D L O C K S O F F */ +/* Turn off the field locks in the current selection. +*/ + +/* %%Function:CmdFldLocksOff %%Owner:peterj */ +CMD CmdFldLocksOff (pcmb) +CMB *pcmb; +{ + int dcpIns = selCur.fIns ? 1 : 0; + + if (selCur.fBlock) + { + Beep(); + return cmdError; + } + + if (!FSetFieldLocks (fFalse, selCur.doc, IfldSelCur(), + selCur.cpLim+dcpIns)) + Beep (); + else + DirtyDoc (selCur.doc); + return cmdOK; +} + + + + +/* F S E T F I E L D L O C K S */ +/* Set all field locks starting with ifld and before cpLim to fOn. +*/ + +/* %%Function:FSetFieldLocks %%Owner:peterj */ +FSetFieldLocks (fOn, doc, ifld, cpLim) +BOOL fOn; +int doc, ifld; +CP cpLim; + +{ + BOOL fFound = fFalse; + struct FLCD flcd; + + GetIfldFlcd (doc, ifld, &flcd); + while (ifld != ifldNil && flcd.cpFirst < cpLim) + { + flcd.fLocked = fOn; + SetFlcdCh (doc, &flcd, chFieldEnd); + fFound = fTrue; + ifld = IfldAfterFlcd (doc, ifld, &flcd); + } + + return fFound; /* no fields in selection feedback */ +} + + +/* C M D U P D A T E S O U R C E */ +/* For all dirty INCLUDE fields in the current selection, copy their + result back into the source document. +*/ + +/* %%Function:CmdUpdateSource %%Owner:peterj */ +CmdUpdateSource (pcmb) +CMB *pcmb; +{ + int doc = selCur.doc; + int ifld = IfldSelCur (); + int dcpIns = selCur.fIns ? 1 : 0; + BOOL fFound = fFalse; + struct FLCD flcd; + + if (selCur.fBlock) + { + Beep(); + return cmdError; + } + + StartLongOp (); + + GetIfldFlcd (doc, ifld, &flcd); + while (ifld != ifldNil && flcd.cpFirst < selCur.cpLim+dcpIns && + !vmerr.fMemFail && !vmerr.fDiskFail) + { + if (flcd.flt == fltInclude && flcd.fResultDirty) + fFound |= FUpdateSourceIfld (doc, ifld); + ifld = IfldAfterFlcd (doc, ifld, &flcd); + } + + if (!fFound) + Beep (); + else + SetUndoNil(); + + EndLongOp (fFalse); + + return cmdOK; +} + + +/* F U P D A T E S O U R C E I F L D */ +/* Open the document ifld's result came from and stuff it back. +*/ + +/* %%Function:FUpdateSourceIfld %%Owner:peterj */ +FUpdateSourceIfld (doc, ifld) +int doc, ifld; + +{ + int docDest, fn, iBkmk; + CHAR chSw; + struct CA caSrc, caDest; + struct FFB ffb; + CHAR stFile [ichMaxFile+1]; + CHAR stNorm [ichMaxFile]; + CHAR stBkmk [cchBkmkMax+1]; + + PcaFieldResult (&caSrc, doc, ifld); + if (DcpCa(&caSrc) <= 0) + return fFalse; + + InitFvb (&ffb.fvb); + SetFfbIfld (&ffb, doc, ifld); + SkipArgument (&ffb); + + /* filename */ + InitFvbBufs (&ffb.fvb, stFile+1, ichMaxFile, NULL, 0); + if (!FFetchArgText (&ffb, fTrue/*fTruncate*/) || !ffb.cch) + return fFalse; + stFile [0] = ffb.cch; + + /* bookmark */ + InitFvbBufs (&ffb.fvb, stBkmk+1, cchBkmkMax, NULL, 0); + FFetchArgText (&ffb, fTrue); + stBkmk [0] = ffb.cch; + + /* converter switch */ + ExhaustFieldText (&ffb); + while ((chSw = ChFetchSwitch (&ffb, fFalse/*fSys*/)) != chNil) + if (chSw == chFldSwConverter) + /* user specified converter--don't bother */ + return fFalse; + + /* open file/doc */ + if (!FNormalizeStFile (stFile, stNorm, nfoNormal)) + return fFalse; + + if ((docDest = DocOpenStDof (stNorm, dofBackground|dofNativeOnly, NULL)) == docNil) + return fFalse; + +#ifdef DEBUG + if ((fn = PdodDoc (docDest)->fn) != fnNil && + (PfcbFn(fn)->fForeignFormat || !PfcbFn(fn)->fHasFib)) + { /* assured by dofNativeOnly in DocOpenStDof() */ + Assert (fFalse); + goto LFailed; + } +#endif /* DEBUG */ + + if (!*stBkmk || !FSearchBookmark (caDest.doc = docDest, stBkmk, &caDest.cpFirst, + &caDest.cpLim, &iBkmk, bmcUser)) + { + stBkmk [0] = 0; + PcaSet( &caDest, docDest, cp0, CpMacDocEdit(docDest) ); + } + else + /* get real bookmark name */ + { + GetStFromSttb(PdodDoc(docDest)->hsttbBkmk, iBkmk, stBkmk); + Assert (*stBkmk < cchBkmkMax); + caDest.cpLim = CpMin (caDest.cpLim, CpMacDocEdit(docDest)); + } + + + AssureLegalSel (&caSrc); + AssureLegalSel (&caDest); + + FReplaceCps (&caDest, &caSrc ); + caDest.cpLim = caDest.cpFirst + DcpCa(&caSrc); + + DirtyDoc(docDest); + + if (vmerr.fMemFail || vmerr.fDiskFail) + { +LFailed: + DisposeDoc (docDest); + KillExtraFns(); + return fFalse; + } + + if (*stBkmk) + /* must replace the bookmark (if this fails, life is tough but just the + bkmk is lost). */ + FInsertStBkmk (&caDest, stBkmk, NULL ); + + if (WwDisp(docDest,wwNil, fFalse) == wwNil) + DoSaveDoc(docDest, fFalse); + + DisposeDoc (docDest); + KillExtraFns(); + + return fTrue; +} + + + + + + + + + +/* F I E L D R E S U L T M O D E F U N C T I O N S */ + + + +/* S E T V I E W R E S U L T S F L T G */ +/* Set the view preference state for showing results for + field type group fltg. +*/ + +/* %%Function:SetViewResultsFltg %%Owner:peterj */ +SetViewResultsFltg (ww, fltg, f) +int ww, fltg, f; +{ + struct WWD *pwwd = PwwdWw(ww); + + Assert( (uns)f <= 1 ); + pwwd->grpfvisi.grpfShowResults &= ~(1<grpfvisi.grpfShowResults |= f << fltg; + vpref.grpfvisi.grpfShowResults &= ~(1<hplcfld; + struct FLD fld; + + Assert (hplcfld != hNil); + + if (ifld < 0 || ifld >= IMacPlc( hplcfld )) + return ifldNil; + + while (--ifld > ifldNil) + { + GetPlc( hplcfld, ifld, &fld ); + if (fld.ch == chFieldBegin) + { + if (cChBegin++ == 0) + break; + } + else if (fld.ch == chFieldEnd) + cChBegin--; + } + + return ifld; + +} + + + + +/* I F L D S E L C U R */ +/* Determine what field the current selection is in. Takes into + consideration insertion points and looks for presence of fields starting + after selCur.cpFirst. +*/ + +/* %%Function:IfldSelCur %%Owner:peterj */ +IfldSelCur () + +{ + int dcpIns = selCur.fIns ? 1 : 0; + CP cp = CpMax (cp0, selCur.cpFirst - dcpIns); + int ifld = IfldFromDocCp (selCur.doc, cp, fFalse); + + if (selCur.fBlock) + return ifldNil; + + if (ifld == ifldNil || CpLimField (selCur.doc, ifld) <= selCur.cpFirst) + /* no field at cp, look for one later */ + ifld = IfldFromDocCp (selCur.doc, selCur.cpFirst, fFalse); + + if (ifld == ifldNil || CpLimField (selCur.doc, ifld) <= selCur.cpFirst) + /* no field at cp, look for one later */ + ifld = IfldNextField (selCur.doc, cp); + + /* assure the field isn't after the current selection */ + if (ifld != ifldNil && CpFirstField (selCur.doc, ifld) < selCur.cpLim + + dcpIns) + return ifld; + else + return ifldNil; + +} + + + + +/* I F L D D O C I F L D C H */ +/* Returns index to the FLD for entry ch of field ifld. +*/ + +/* %%Function:IfldDocIfldCh %%Owner:peterj */ +int IfldDocIfldCh (doc, ifld, ch) +int doc, ifld; +CHAR ch; + +{ + struct PLC **hplcfld = PdodDoc (doc)->hplcfld; + struct FLCD flcd; + struct FLD fld; + + Assert (hplcfld != hNil); + Assert (IMacPlc( hplcfld ) > ifld); + + GetPlc( hplcfld, ifld, &fld ); + if (fld.ch == ch) + return ifld; + + FillIfldFlcd (hplcfld, ifld, &flcd); + Assert (ch != chFieldBegin); + if (ch == chFieldSeparate) + return flcd.ifldChSeparate; + else + return flcd.ifldChEnd; +} + + + + + + +/* S E T F I E L D P C H P */ +/* Set the standard values for a field character to be inserted at doc, cp. + If cpFirst != cpNil, cpFirst is the field begin character of the field.*/ + +/* %%Function:SetFieldPchp %%Owner:peterj */ +SetFieldPchp (doc, cp, pchp, cpFirst) +int doc; +CP cp; +struct CHP *pchp; +CP cpFirst; + +{ + /* If the field characters are being inserted at the insertion point, + use selCur.chp (this allows transient insertion point props to + apply). Otherwise use the "insertion point" properties at doc,cp. + Apply fSpec in any case. + + Special aperances are handled at formatline level to prevent the + user from changing them. + */ + + if (cpFirst == cpNil) + if (doc == selCur.doc && cp == selCur.cpFirst) + { + GetSelCurChp (fFalse); + *pchp = selCur.chp; + } + else + GetPchpDocCpFIns (pchp, doc, cp, fTrue /* fIns */, wwNil); + else + GetPchpDocCpFIns (pchp, doc, cpFirst, fFalse, wwNil); + + pchp->fSpec = fTrue; + +} + + + + + + + + +/* F I E L D I N S E R T I O N / D E L E T I O N U T I L I T I E S */ + + + + +/* F I N S E R T F I E L D D O C C P */ +/* Place an empty field in doc at cp. This field contains a chFieldBegin, + a chFieldEnd and, if fSeparator, a chFieldSeparate between them. + Instruction text can then be inserted at cp + 1, or, if fSeparator, + result text can be inserted at cp + 2. +*/ + +/* %%Function:FInsertFieldDocCp %%Owner:peterj */ +BOOL FInsertFieldDocCp (doc, cp, fSeparator) +int doc; +CP cp; +BOOL fSeparator; + +{ + int ich = 0; + CHAR rgch [3]; + struct CHP chp; + + Assert (doc != docNil && !vmerr.fMemFail && !vmerr.fDiskFail); + + if (cp > CpMacDocEdit (doc)) + cp = CpMacDocEdit (doc); + + rgch [ich++] = chFieldBegin; + if (fSeparator) + rgch [ich++] = chFieldSeparate; + rgch [ich++] = chFieldEnd; + + SetFieldPchp (doc, cp, &chp, cpNil); + chp.fRMark = PdodMother(doc)->dop.fRevMarking; + if (!FInsertRgch (doc, cp, rgch, ich, &chp, NULL)) + return fFalse; + /* using fltUnknownKwd forces parse which forces inst visibility */ + if (!FInsertFltDcps (fltUnknownKwd, doc, cp, (CP)2, + (fSeparator ? (CP)1 : (CP)0), NULL)) + { + struct CA ca; + /* delete what we just added */ + FDelete(PcaSetDcp(&ca, doc, cp, (CP)ich)); + return fFalse; + } + return fTrue; +} + + + + +/* F P U T C P S I N F I E L D */ +/* Given two contiguous ranges of cps, make them a field. Insert + a chFieldBegin at the beginning, a chFieldEnd at the end and, if + there is a second range, a chFieldSeparate between them. Insert the + resulting field into the plcfld with type flt. + + If the caller 1) does not know (for sure) the type of the field they + are inserting OR 2) wants to guarantee that the field will be displayed + in SHOW INSTRUCTIONS mode, use fltUnknownKwd. + + Adjusts *pdcpInst if necessary to include EOP inserted before table. +*/ + +/* %%Function:FPutCpsInField %%Owner:peterj */ +FPutCpsInField (flt, doc, cpFirst, pdcpInst, dcpResult, pchp) +int flt, doc; +CP cpFirst, *pdcpInst, dcpResult; +struct CHP *pchp; +{ + CHAR ch; + struct CHP chp; + struct PAP pap; + struct CA caT; + + Assert (*pdcpInst >= cp0 && dcpResult >= cp0); + + if (pchp == NULL) + SetFieldPchp (doc, cpFirst, &chp, cpNil); + else + chp = *pchp; + + chp.fSpec = fTrue; + chp.fRMark = PdodMother(doc)->dop.fRevMarking; + + ch = chFieldEnd; + if (!FInsertRgch (doc, cpFirst + *pdcpInst + dcpResult, &ch, 1, &chp, NULL)) + return fFalse; + + if (dcpResult != 0) + { + ch = chFieldSeparate; + if (!FInsertRgch (doc, cpFirst + *pdcpInst, &ch, 1, &chp, NULL)) + goto LFail1; + dcpResult++; + } + + ch = chFieldBegin; + if (!FInsertRgch (doc, cpFirst, &ch, 1, &chp, NULL)) + goto LFail2; + + if (!FInsertFltDcps (flt, doc, cpFirst, *pdcpInst + 2, dcpResult, NULL)) + { + /* Insert failed, get rid of field characters */ + FDelete(PcaSetDcp(&caT, doc, cpFirst, 1)); +LFail2: + if (dcpResult) + { + --dcpResult; + FDelete(PcaSetDcp(&caT, doc, cpFirst + *pdcpInst, 1)); + } +LFail1: + FDelete(PcaSetDcp(&caT, doc, cpFirst + *pdcpInst + dcpResult, 1)); + return fFalse; + } + + InvalTableProps(doc, cpFirst, *pdcpInst + dcpResult + 2, fTrue/*fFierce*/); + + return fTrue; +} + + + +/* C C H R M F I E L D A T D O C C P */ +/* Remove the field characters in and around a field. Remove it from + the plcfld if it is there. Doc, cp is cpFirst of some field (dead or + live). Number of resulting instruction and result + characters is returned in *pdcpInst and *pdcpResult. +*/ + +/* %%Function:CchRmFieldAtDocCp %%Owner:peterj */ +CchRmFieldAtDocCp (doc, cp, pdcpInst, pdcpResult) +int doc; +CP cp, *pdcpInst, *pdcpResult; + +{ + int ifld = IfldFromDocCp (doc, cp, fTrue); + int cch = 2; + struct CA ca; + CP cpFirst, cpLim; + struct FLCD flcd; + +#ifdef DEBUG + /* This is hack--this function does something that is normally + not allowed. It deletes unmatched field delimiters. It is + ok for it to do so (it is its job). To do it we must turn off + the debugging check that assures we don't! */ + BOOL fCkFldDel = vdbs.fCkFldDel; +#endif /* DEBUG */ + + if (ifld == ifldNil) + { /* dead field */ + cpFirst = cp; + cpLim = CpLimDeadField (doc, cp); + +#ifdef DEBUG + { + extern struct CHP vchpFetch; + extern CHAR HUGE *vhpchFetch; + + CachePara (doc, cpFirst); + FetchCp (doc, cpFirst, fcmProps+fcmChars); + + if (!vchpFetch.fSpec || *vhpchFetch != chFieldBegin || cpFirst != cp) + { + Assert (fFalse); + return 0; + } + } +#endif /* DEBUG */ + + *pdcpInst = cpLim - cpFirst; + *pdcpResult = cp0; + } + + else /* live field */ + { + GetIfldFlcd (doc, ifld, &flcd); + cpFirst = flcd.cpFirst; + + if (cpFirst != cp) + { + Assert (fFalse); + return 0; + } + + cpLim = cpFirst + flcd.dcpInst + flcd.dcpResult; + *pdcpInst = flcd.dcpInst; + *pdcpResult = flcd.dcpResult; + + DeleteFld (doc, ifld); + } + + /* turn off debug checks during illegal deletes! */ + Debug (vdbs.fCkFldDel = fFalse); + FDelete( PcaSet( &ca, doc, cpLim - 1, cpLim ) ); + if (*pdcpResult) + { + FDelete(PcaSetDcp( &ca, doc, cpFirst + *pdcpInst - 1, (CP)1)); + *pdcpResult -= 1; + cch++; + } + FDelete( PcaSetDcp( &ca, doc, cpFirst, (CP)1)); + *pdcpInst -= 2; + Debug (vdbs.fCkFldDel = fCkFldDel); + + return cch; +} + + +/* C M D I N S F L T S Z A T S E L C U R */ +/* Perform auto deletion at selCur. Insert a field of type flt. + If szArg is non-null, insert it as the field's arguments. If + fCalc cause the field to be calculated (frmUser). If !fShowDefault, + force the view mode to be fShowResult. SetUndo for the entire + operation. + + If flt is a dead field the field is killed and fCalc and fShowFoo are + ignored. If flt==fltNil, szArg is assumed to contain a keyword (not + fatal if it doesn't). +*/ + +/* %%Function:CmdInsFltSzAtSelCur %%Owner:peterj */ +CMD CmdInsFltSzAtSelCur (flt, szArg, bcm, fCalc, fShowDefault, fShowResult) +int flt, bcm; +CHAR *szArg; +BOOL fCalc, fShowDefault, fShowResult; + +{ + CMD cmdRet; + int ifld; + int cch; + int doc = selCur.doc; + CP cpIns, cpField, cpLimField, dcpInserted; + struct EFLT eflt; + struct CA ca, caRM; + CHAR szKeyword [cchMaxFieldKeyword + 1]; + extern struct UAB vuab; + + Assert ((flt >= fltMinParse && flt < fltMax) || flt == fltNil); + Assert (doc != docNil); + + CheckCollapseBlock(); + + if (FTtpPsel(&selCur)) + { + Beep(); + return cmdError; + } + + if (!FSetUndoBefore(bcm, uccPaste)) + return cmdCancelled; + + if ((cmdRet = CmdAutoDelete(&caRM)) != cmdOK) + return cmdRet; + + /* insert the field and get the correct keyword */ + cpField = selCur.cpFirst; + cpIns = cpField + 1; + if (!FInsertFieldDocCp (doc, cpField, fFalse /* fSeparator */)) + return cmdNoMemory; + + dcpInserted = 2; + + if (flt != fltNil) + GetFltKeyword (flt, szKeyword); + + if (szArg != NULL) + /* Argument portion given. Insert it first. */ + { + /* add a space to the keyword */ + if (flt != fltNil) + { + CHAR *pch = szKeyword + CchSz (szKeyword) - 1; + *pch++ = chSpace; + *pch = '\0'; + } + + /* insert the argument into the field */ + if (!FInsertRgch(doc,cpIns,szArg,(cch=CchSz(szArg)-1),&selCur.chp,NULL)) + goto LNoMem; + dcpInserted += cch; + } + + /* now insert the keyword, in front of argument if present */ + if (flt != fltNil) + { + if (!FInsertRgch (doc, cpIns, szKeyword, (cch=CchSz(szKeyword)-1), + &selCur.chp, NULL)) + goto LNoMem; + } + + /* if we run out of memory after this point we aren't too concerned */ + + /* parse the new field */ + ifld = IfldFromDocCp (doc, cpField, fTrue); + Assert (ifld != ifldNil); + flt = FltParseDocCp (doc, cpField, ifld, fFalse, fFalse); + + /* get info about the new field */ + eflt = EfltFromFlt (flt); + + if (!eflt.fDead) + /* new field live. set fDiffer and possibly calculate */ + { + if (fCalc) + { + vwFieldCalc |= fclInsert; + FCalcFieldIfld (doc, ifld, frmUser, 0, fFalse); + vwFieldCalc &= ~fclInsert; + } + + if (!fShowDefault) + { + struct FLCD flcd; + GetIfldFlcd (doc, ifld, &flcd); + flcd.fDiffer = (!PwwdWw(wwCur)->grpfvisi.fvisiShowAll) && + (FShowResultPflcdFvc (&flcd, selCur.ww/*fvcScreen*/) + ^ fShowResult); + SetFlcdCh (doc, &flcd, chFieldEnd); + } + + cpLimField = CpLimField (doc, ifld); + } + else /* dead field */ + cpLimField = CpLimDeadField(doc, cpField); + + DirtyDoc (doc); + PcaSet( &ca, doc, cpField, cpLimField ); + InvalCp (&ca); + SelectIns( &selCur, cpLimField); + caRM.cpLim += DcpCa(&ca); + SetUndoAfter(&caRM); + + return cmdOK; + +LNoMem: + FDelete(PcaSetDcp(&ca, selCur.doc, cpField, dcpInserted)); + return cmdNoMemory; +} + + + + +/* T R A N S L A T E F I E L D S */ +/* Translate keywords of fields to the current local's keywords. +*/ + +/* %%Function:TranslateFields %%Owner:peterj */ +TranslateFields (doc) +int doc; + +{ + int ifld = ifldNil; + int fltT, cchNew; + struct CA ca; + FC fcIns; + struct CHP chp; + struct FFB ffb; + struct FLCD flcd; + CHAR szKwd [cchMaxFieldKeyword+1]; + +#ifdef DEBUG +#ifdef LOCALETEST + CommSz (SzShared("Translating fields\n\r")); +#endif /* LOCALETEST */ +#endif /* DEBUG */ + + ca.doc = doc; + while ((ifld = IfldAfterFlcd (doc, ifld, &flcd)) != ifldNil && + !vmerr.fMemFail && !vmerr.fDiskFail) + { + Assert (!flcd.fDirty); + if ((cchNew = CchSzFromSzgId (szKwd+1, szgFltNormal, flcd.flt, + cchMaxFieldKeyword)) <= 1) + /* we cannot translate this field */ + continue; + + szKwd [0] = chFieldEscape; + InitFvb (&ffb.fvb); + SetFfbIfld (&ffb, doc, ifld); + ffb.foc = focNone; + if (!FFetchArgExtents (&ffb, &ca.cpFirst, &ca.cpLim, fFalse)) + { + Assert (fFalse); + continue; + } + + AssureLegalSel(&ca); + GetPchpDocCpFIns (&chp, ca.doc, ca.cpFirst, fFalse, wwNil); + if (!FNewChpIns (ca.doc, ca.cpFirst, &chp, stcNil)) + return; + fcIns = FcAppendRgchToFn (fnScratch, szKwd, cchNew); + if (vmerr.fDiskFail || !FReplace( &ca, fnScratch, fcIns, (FC)cchNew)) + return; + + fltT = flcd.flt; + GetIfldFlcd (doc, ifld, &flcd); + flcd.flt = fltT; + SetFlcdCh (doc, &flcd, chFieldBegin); + + DirtyDoc (doc); + } + + /* translate sub-docs */ + if (!PdodDoc (doc)->fShort) + { + if (PdodDoc (doc)->docFtn != docNil) + TranslateFields (PdodDoc (doc)->docFtn); + if (PdodDoc (doc)->docAtn != docNil) + TranslateFields (PdodDoc (doc)->docAtn); + if (PdodDoc (doc)->docHdr != docNil) + TranslateFields (PdodDoc (doc)->docHdr); + if (PdodDoc (doc)->fDot) + { + if (PdodDoc (doc)->docGlsy != docNil) + TranslateFields (PdodDoc (doc)->docGlsy); + if (PdodDoc (doc)->docMcr != docNil) + TranslateFields (PdodDoc (doc)->docMcr); + } + } +} + + + +/* G E T F L T K E Y W O R D */ +/* Fill a buffer with the keyword of a given flt. sz must have at + least room for cchMaxFieldKeyword characters. +*/ + +/* %%Function:GetFltKeyword %%Owner:peterj */ +GetFltKeyword (flt, sz) +int flt; +CHAR *sz; + +{ + int cch; + Assert (flt >= 0 && flt < fltMax); + + /* try for single character keyword */ + if ((cch = CchSzFromSzgId (sz, szgFltSingle, flt, cchMaxFieldKeyword)) + == 0) + cch = CchSzFromSzgId (sz, szgFltNormal, flt, cchMaxFieldKeyword); + + Assert (cch); +} + + diff --git a/src/Opus/FILE2.C b/src/Opus/FILE2.C new file mode 100644 index 0000000..274a3a6 --- /dev/null +++ b/src/Opus/FILE2.C @@ -0,0 +1,1327 @@ +/* F I L E 2 . C */ +/* Non-core file routines */ + +#ifdef PCJ +/* #define SHOWFC */ +#define DFILEPATHS +#endif /* PCJ */ + +#define NOGDICAPMASKS +#define NOVIRTUALKEYCODES +#define NOWINMESSAGES +#define NOWINSTYLES +#define NOSYSMETRICS +#define NOMENUS +#define NOICON +#define NOKEYSTATE +#define NOSYSCOMMANDS +#define NORASTEROPS +#define NOSHOWWINDOW +#define NOSYSMETRICS +#define NOBITMAP +#define NOBRUSH +#define NOCLIPBOARD +#define NOCOLOR +#define NOCREATESTRUCT +#define NOCTLMGR +#define NODRAWTEXT +#define NOFONT +#define NOGDI +#define NOHDC +#define NOMEMMGR +#define NOMENUS +#define NOMETAFILE +#define NOMSG +#define NOPEN +#define NOPOINT +#define NORECT +#define NOREGION +#define NOSCROLL +#define NOSOUND +#define NOTEXTMETRIC +#define NOWH +#define NOWINOFFSETS +#define NOWNDCLASS +#define NOCOMM +#define NOKANJI + +#include "word.h" +DEBUGASSERTSZ /* WIN - bogus macro for assert string */ +#include "heap.h" +#include "doslib.h" +#include "doc.h" +#include "file.h" +#include "winddefs.h" +#include "props.h" +#include "fkp.h" +#include "debug.h" +#include "error.h" + + +extern int fnMac; +extern int cfnTMP; /* current temporary file number */ +extern struct BPTB vbptbExt; +extern struct FKPD vfkpdChp; +extern struct FKPD vfkpdPap; +extern struct FKPD vfkpdText; +extern struct MERR vmerr; +extern int docMac; +extern int vdocTemp; +extern int vdocScratch; +extern FC vfcSpec; +extern struct DOD **mpdochdod[]; +extern TS tsMruOsfn; +extern struct FCB **mpfnhfcb[]; +extern int vfScratchFile; +extern struct EFPI dnfpi[]; +extern CHAR szEmpty[]; +extern CHAR szApp[]; +extern CHAR szDoc[]; +extern BOOL vfInsertMode; + + + +/* F C M A C F N */ +/* Return the fcMac of fn according to the file system (not too interesting +for native format files). Return fcNil if cannot seek. +*/ +/* %%Function:FcMacFn %%Owner:peterj */ +FC FcMacFn(fn) +int fn; +{ + FC fcMac; + unsigned osfn; + + Assert( (fn != fnNil) && mpfnhfcb [fn] != NULL); + + if ((osfn = OsfnValidAndSeek(fn,0L)) == osfnNil) + return fcNil; + else if ((fcMac = DwSeekDw(osfn, 0L, SF_END)) < 0L) + { + DiskError(eidSDE, fn, "FcMacFn"); + return fcNil; + } + + return fcMac; +} + + + +/* %%Function:FCloseFn %%Owner:peterj */ +FCloseFn( fn ) +int fn; +{ /* Close file fn if it is currently open */ + struct FCB *pfcb = PfcbFn(fn); + + Assert( fn != fnNil && mpfnhfcb [fn] != NULL ); + if (pfcb->osfn != osfnNil) + { + /* Close may fail if windows already closed the file for us, + but that's OK */ + FCloseDoshnd( pfcb->osfn ); + pfcb->osfn = osfnNil; + } + return fTrue; +} + + + + +/* %%Function:OpenEveryHardFn %%Owner:peterj */ +OpenEveryHardFn() + { /* For each fn representing a file on nonremoveable media, + try to open it. It is not guaranteed that any or all such files + will be open on return from this routine -- we are merely attempting + to assert our ownership of these files on a network by keeping them open */ + + extern int fnMac; + int fn; + struct FCB **hfcb; + + for ( fn = 0; fn < fnMac; fn++ ) + if ((hfcb = mpfnhfcb [fn]) != NULL) + { + struct FCB *pfcb = *hfcb; + + if (pfcb->osfn == osfnNil && pfcb->ofh.fFixedDisk) + FAccessFn( fn, 0 ); + } +} + + + + + +/* %%Function:FCreateStFile %%Owner:peterj */ +FCreateStFile( stFile ) +CHAR *stFile; + { /* Create a new, unique file. + Return the name in szFile. + Leaves the file open + Returns TRUE on success, FALSE on failure. + If stFile begins "X:...", creates the file on the specified drive; + otherwise, creates the file on a drive of Windows' choice */ + /* ERROR reporting is the responsibility of the caller; however, + this routine will report a WARNING if the temp file creation + could not be done on the default directory. */ + + + extern CHAR stDOSPath[]; + int tf; + CHAR szT [ichMaxFile]; + + tf = ((stFile [0] > 1 && stFile [2] == ':') ? stFile [1] | TF_FORCEDRIVE : 0); + + if ( !GetTempFileName( (BYTE) tf, (LPSTR)szDoc + 1, 0, (LPSTR)szT )) + { + if (!tf) + { + ErrorEid (eidCantCreateTempFile, "FCreateStFile"); + UpdateStDOSPath(); + if (!GetTempFileName( TF_FORCEDRIVE | stDOSPath [1], + (LPSTR)szDoc + 1, 0, (LPSTR)szT)) + return fFalse; + } + else + return fFalse; + } + + /* Succeeded in creating file */ + + SzToStInPlace( szT ); + + return FNormalizeStFile( szT, stFile, nfoNormal); +} /* end of F C r e a t e S t F i l e */ + + + +/* %%Function:FEnsureOnLineFn %%Owner:peterj */ +FEnsureOnLineFn( fn ) +int fn; + { /* Ensure that file fn is on line (i.e. on a disk that is accessible). + Return TRUE if we were able to guarantee this, FALSE if not */ + + struct FCB *pfcb = PfcbFn(fn); + + Assert(fn != fnNil && mpfnhfcb[fn] != NULL); + + if (pfcb->ofh.fFixedDisk) + /* If it's on nonremovable media, we know it's on line */ + return fTrue; + else + /* otherwise verify */ + return OsfnValidAndSeek(fn,0L) != osfnNil; +} + + +/* S E T E O F F N - sets end of file */ +/* NOTE: under DOS, can't reduce file size; we just change the FCB fields */ +/* %%Function:SetEofFn %%Owner:peterj */ +SetEofFn(fn, fc) +int fn; +FC fc; +{ + struct FCB *pfcb = PfcbFn(fn); + + pfcb->cbMac = pfcb->fcPos = fc; +} + + +/* K I L L E X T R A F N S */ +/* %%Function:KillExtraFns %%Owner:peterj */ +KillExtraFns() +{ + MarkAllReferencedFn(); + DeleteNonReferencedFns(0); +} + + +/* M A R K A L L R E F E R E N C E D F N */ +/* %%Function:MarkAllReferencedFn %%Owner:peterj */ +MarkAllReferencedFn() +{ + int fn; + struct FCB **hfcb, *pfcb; + int doc; + int ifoo; + struct DOD **hdod, *pdod; + struct PCD *ppcd; + struct PCD pcd; + struct SED sed; + struct PLC **hplcpcd; + struct PLC **hplcsed; + struct CA caT; + +/* remove any references that might be in vdocTemp */ +/* for WIN, remove from vdocScratch too */ + + + DisableInval(); + + if (vdocTemp != docNil) + { + PdodDoc(vdocTemp)->doc = docScrap; /* ensure valid chain */ + FDelete(PcaSetWholeDoc(&caT, vdocTemp)); + } + +#ifdef WIN + if (vdocScratch != docNil) + { + Assert (!fDocScratchInUse); + FDelete(PcaSetWholeDoc(&caT, vdocScratch)); + } +#endif /* WIN */ + + EnableInval(); + + for (fn = 1; fn < fnMac; fn++) + if ((hfcb = mpfnhfcb[fn]) != hNil) + { + /* dictionaries are not closed */ + pfcb = *hfcb; +#ifdef MAC + pfcb->fRefDocScrap = fFalse; + pfcb->fRefNonScrap = !pfcb->fDoc && !pfcb->fGlsy && !pfcb->fTemp; +#else /* WIN */ + pfcb->fRef = !pfcb->fDoc && !pfcb->fTemp; +#endif + } + + for (doc = 1; doc < docMac; doc++) + { + if ((hdod = mpdochdod[doc])) + { + int iMac; + int fnT; + char *pfRef; + char rgfRef[fnMax]; + + FreezeHp(); /* for pdod */ + if (!(pdod = *hdod)->fShort && pdod->fn != fnNil) + PfcbFn(pdod->fn)->fRef = fTrue; + + hplcpcd = pdod->hplcpcd; + iMac = IMacPlc(hplcpcd); + SetBytes(&rgfRef, 0, fnMax); + MiscPlcLoops(hplcpcd, 0, iMac, + &rgfRef, 2 /* MarkAllReferencedFn */); + Assert(fnNil == 0); + for (fnT = 1, pfRef = &rgfRef[1]; fnT < fnMac; fnT++) + if (*pfRef++) + PfcbFn(fnT)->fRef = fTrue; + + if (!pdod->fShort) + { + hplcsed = pdod->hplcsed; + AssertH(hplcsed); + iMac = IMacPlc(hplcsed); + for (ifoo = 0; ifoo < iMac; ifoo++) + { + GetPlc(hplcsed, ifoo, &sed); + if (sed.fn != fnNil && sed.fcSepx != fcNil) + PfcbFn(sed.fn)->fRef = fTrue; + } + } + MeltHp(); + } + } +} + + + +#ifdef MAC +/* M A R K F C B R E F */ +/* %%Function:MarkFcbRef %%Owner:UNUSED */ +MarkFcbRef(fn, doc) +int fn; +int doc; +{ + struct FCB *pfcb; + + if (fn != fnNil) + { + pfcb = PfcbFn(fn); + if (doc == docScrap) + pfcb->fRefDocScrap = fTrue; + else + pfcb->fRefNonScrap = fTrue; + } +} + + +#endif /* MAC */ + + +/* D E L E T E N O N R E F E R E N C E D F N S */ +/* %%Function:DeleteNonReferencedFns %%Owner:peterj */ +DeleteNonReferencedFns(volSpec) +int volSpec; /* Opus doesn't need this */ +{ +/* delete all unused temp files; closed all unused doc files */ + + int fn; + struct FCB **hfcb, *pfcb; + struct PLCBTE **hplcbteChp, **hplcbtePap, **hplcbte; + + extern int vfnNonDel; +#ifdef RSH + extern int vfnUa; +#endif /* RSH */ + +/* handle all non-scratch files */ + for (fn = fnScratch + 1; fn < fnMac; fn++) + { + if ((hfcb = mpfnhfcb[fn]) == hNil) + continue; + pfcb = *hfcb; + if (pfcb->fRef) + continue; + if (fn == vfnNonDel) /* used by rtfin */ + continue; +#ifdef RSH + if (fn == vfnUa) /* used by user-action measurement code */ + continue; +#endif /* RSH */ + + DeleteFn(fn, pfcb->fTemp); + } + +/* reset the scratch file if nothing references it */ + Assert(mpfnhfcb[fnScratch] != 0); + pfcb = PfcbFn(fnScratch); +#ifdef MAC + Assert(pfcb->vol == vvolSystem); +#endif + /* Since we can have text on the scratch file which is not + referenced by any doc during PrintMerge, don't reset + scratch file in this case. */ + if (!pfcb->fRef + && (!vfInsertMode) + && pfcb->cbMac > 0 ) + { + ReportSz("deleting scratch file contents"); + vfcSpec = fcNil; + DeleteFnHashEntries(fnScratch); + pfcb = PfcbFn(fnScratch); /* reload pointer */ + hplcbteChp = pfcb->hplcbteChp; + hplcbtePap = pfcb->hplcbtePap; + + /* using FOpenPlc guarantees no allocations will fail */ + FOpenPlc(hplcbteChp, 0, -IMacPlc(hplcbteChp)); + PutCpPlc(hplcbteChp, 0, fc0); + FOpenPlc(hplcbtePap, 0, -IMacPlc(hplcbtePap)); + PutCpPlc(hplcbtePap, 0, fc0); + + if (vmerr.fScratchFileInit) + { + SetEofFn(fnScratch, fc0); + vfScratchFile = fTrue; + } + vmerr.fDiskEmerg = fFalse; + pfcb = PfcbFn(fnScratch); /* reload pointer */ + pfcb->cbMac = 0; + pfcb->pnXLimit = pn0; + pfcb->nFib = nFibCurrent; +/* the scratch file will start with cbMac = 0. The fkpd's will be set +up so that any insertion will start a new page */ + SetBytes(&vfkpdChp, 0, sizeof(struct FKPD)); + SetBytes(&vfkpdPap, 0, sizeof(struct FKPD)); + SetBytes(&vfkpdText, 0, sizeof(struct FKPDT)); + vfkpdPap.bFreeFirst = 1; + /* .bFreeLim = 0; .fcFirst = 0 */ + vfkpdChp.bFreeFirst = 1; + /* .bFreeLim = 0; .fcFirst = 0 */ + vfkpdText.pn = pnNil; + StandardChp(&vfkpdChp.chp); + } +} + + +/* D E L E T E F N */ +/* %%Function:DeleteFn %%Owner:peterj */ +DeleteFn(fn, fDelete) +int fn; +int fDelete; /* delete the file */ +{ +/* Remove all file cache references for file fn. Close and optionally delete + file. Mark this fn as reusable. Note that we free the fn even if we + couldn't actually delete the file from the disk for whatever reason. */ + struct FCB *pfcb = PfcbFn(fn); + struct PLCBTE **hplcbteChp = pfcb->hplcbteChp; + struct PLCBTE **hplcbtePap = pfcb->hplcbtePap; + int vol; + char st[cchMaxFile]; + +/* save file description if we're deleting it */ + if (fDelete) + { + CopySt(pfcb->stFile, st); + FEnsureOnLineFn(fn); + } + +/* delete all references to this file in the internal and external caches */ + DeleteFnHashEntries(fn); + +/* kill the fn */ + if (FCloseFn(fn)) + { + FreeHplc(hplcbteChp); + FreeHplc(hplcbtePap); + FreeCls(clsFCB, fn); + } + +/* the sad truth is that we couldn't care less whether the file is deleted; + better to let the user see temp files than warn him the delete failed */ + if (fDelete) + EcOsDelete(st, vol); +} /* end DeleteFn */ + + + +/* %%Function:EcOsDelete %%Owner:peterj */ +EcOsDelete(stFile, vol) +CHAR stFile[]; +int vol; /* unused */ + { /* Delete the file stFile, return error code or fpeNoErr if no error. + return ecNoErr(0) if the file was successfully deleted or if it failed + because the file could not be found; an error code otherwise. +*/ + + int ec; + + StToSzInPlace( stFile ); + ec = EcDeleteSzFfname( stFile ); + SzToStInPlace( stFile ); + if (ec == ecFnfError) + /* Failure to delete because the file was not found is considered + a success at getting the file out of the way */ + ec = ecNoErr; + + return ec; +} + + +/* D E L E T E F N H A S H E N T R I E S */ +/* %%Function:DeleteFnHashEntries %%Owner:peterj */ +NATIVE DeleteFnHashEntries(fn) +int fn; +{ + int ibp; + struct BPS HUGE *hpbps; + + for (ibp = 0, hpbps = vbptbExt.hpmpibpbps; + ibp < vbptbExt.ibpMac; ibp++, hpbps++) + if (hpbps->fn == fn) + DeleteIbpHashEntry(ibp); + + Debug(vdbs.fCkBptb ? CkPbptb(&vbptbExt, fFalse) : 0); +} + + + +#ifdef DEBUG /* Coded in line if !DEBUG */ +/* %%Function:C_PnWhoseFcGEFc%%Owner:peterj */ +NATIVE PN C_PnWhoseFcGEFc(fc) /* WINIGNORE - DEBUG only */ +FC fc; +{ + return ((fc + (cbSector - 1)) >> shftSector); +} + + +#endif /* DEBUG */ + + +/* F C H E C K F C L E G A L */ +/* %%Function:FCheckFcLegal %%Owner:peterj */ +FCheckFcLegal (fc) +FC fc; +{ +#ifdef SHOWFC + CommSzLong (SzShared("FCheckFcLegal: fc = "), fc); +#endif /* SHOWFC */ + + if (fc >= fcMax) + { + ErrorEid(eidFcTooBig, " FCheckFcLegal"); + vmerr.fDiskAlert = fTrue; + return fFalse; + } + return fTrue; +} + + +#ifdef OPUS_X64 +/* Counted string formerly emitted by the localization StringMap pass. */ +csconst char stDotSlash[] = { 2, '.', '\\' }; +#else +csconst char stDotSlash[] = St(".\\"); +#endif + +/* F F I N D F I L E S P E C */ +/* Search the paths specified in grpfpi (in order specified) looking + for stShort (may have wild cards iff nof & nofWildOK). If found + return true and full path to file in stFull. stFull is undefined + if failed. +*/ + +/* %%Function:FFindFileSpec %%Owner:peterj */ +FFindFileSpec (stShort, stFull, grpfpi, nfo) +CHAR *stShort, *stFull; +unsigned grpfpi; +int nfo; +{ + BOOL fHasPath; + unsigned fpi; + int shftFpi = 0; + struct FNS fns; + struct FINDFILE ffl; + CHAR st[ichMaxFile]; + CHAR rgchT[ichMaxFile]; + +#ifdef DFILEPATHS + CommSzSt(SzShared("FFindFileSpec: stShort = "), stShort); + CommSzLong(SzShared("grpfpi = "), (long)grpfpi); +#endif /* DFILEPATHS */ + + fHasPath = (PchInSt(stShort, '\\') != NULL || + PchInSt(stShort, '/') != NULL || + PchInSt(stShort, ':') != NULL); + + if (!FNormalizeStFile(stShort, st, nfo)) + return fFalse; + StFileToPfns(st, &fns); + + while (shftFpi <= 12 && (fpi = (grpfpi >> shftFpi) & 0xf) != fpiNil) + { + Assert(fpi != fpiOwn || !shftFpi); + shftFpi += 4; + + /* get path from fpi */ + if (fpi == fpiCurrent) + /* yes, .\ is necessary. this function needs to supply an + explicit path to FNormalizeStFile. */ + CopyCsSt(stDotSlash, fns.stPath); + else if (fpi == fpiOwn) + { + if (!fHasPath) + continue; /* file does not have its own! */ + } + else if (!FGetStFpi(fpi, fns.stPath)) + continue; + + /* see if valid & file exists */ + PfnsToStFile(&fns, st); + if (FNormalizeStFile(st, stFull, nfo)) /* name is legal */ + { + StToSz(stFull, rgchT); + AnsiToOem(rgchT, rgchT); +#ifdef DFILEPATHS + CommSzSz(SzShared("Trying: "), rgchT); +#endif /* DFILEPATHS */ + if (!FFirst(&ffl, rgchT, (nfo & nfoPathOK ? DA_SUBDIR : 0))) + { /* file exists */ + if (nfo & nfoWildOK) + { /* substitute actual name for wildcard */ + struct FNS fnsT; + + OemToAnsi( ffl.szFileName, rgchT ); + SzToStInPlace( rgchT ); + StFileToPfns( stFull, &fns ); + StFileToPfns( rgchT, &fnsT ); + CopySt(fnsT.stShortName, fns.stShortName); + CopySt(fnsT.stExtension, fns.stExtension); + PfnsToStFile( &fns, stFull ); + } +#ifdef DFILEPATHS + CommSzSt(SzShared("File found: "), stFull); +#endif /* DFILEPATHS */ + return fTrue; + } + } + } + + return fFalse; +} + + + +/* F G E T S T F P I */ +/* Return the stPath for fpi. False if no path available. st must have + at least ichMaxPath characters. +*/ + +/* %%Function:FGetStFpi %%Owner:peterj */ +FGetStFpi (fpi, st) +int fpi; +CHAR *st; +{ + struct EFPI * pefpi = &dnfpi[fpi]; + CHAR **hPath; + + Assert (fpi < fpiStoreMax); + + if (!pefpi->fInit) + InitFpi(fpi); + + if (pefpi->fNone) + return fFalse; + + hPath = HExpandHc(pefpi->hcPath); + CopySt(*hPath, st); + return fTrue; +} + + + +#ifdef OPUS_X64 +/* The longest counted profile key is UTIL-PATH: one length byte plus nine + * characters. These are the original English keys normally generated by + * the absent localization pass. */ +csconst CHAR mpfpistName[][10] = +{ + { 8, 'D', 'O', 'T', '-', 'P', 'A', 'T', 'H' }, + { 8, 'I', 'N', 'I', '-', 'P', 'A', 'T', 'H' }, + { 9, 'U', 'T', 'I', 'L', '-', 'P', 'A', 'T', 'H' } +}; +#else +csconst CHAR mpfpistName[][] = +{ + StKey("DOT-PATH",DOTPATH), + StKey("INI-PATH",INIPATH), + StKey("UTIL-PATH",UTILPATH) +}; +#endif + + +csconst int mpfpieid[] = +{ + eidBogusDotPath, + eidBogusIniPath, + eidBogusUtilPath, + eidNull +}; + + +/* I N I T F P I */ +/* Find the path for fpi and store it in dnfpi. +*/ + +/* %%Function:InitFpi %%Owner:peterj */ +InitFpi(fpi) +int fpi; +{ + struct EFPI *pefpi = &dnfpi[fpi]; + int cch; + CHAR ch, **hPath; + CHAR rgchName[50], rgchPath[ichMaxFile], rgchNormal[ichMaxFile]; + + Assert(fpi < fpiStoreMax); + + if (pefpi->fInit) + return; + + pefpi->fInit = fTrue; + +#ifdef DFILEPATHS + CommSzNum(SzShared("InitFpi: fpi = "), fpi); +#endif /* DFILEPATHS */ + + /* get a path */ + + if (fpi == fpiProgram) + /* location of opus.exe */ + CchGetProgramDir(rgchPath, ichMaxFile); + + else + /* get path from win.ini profile */ + { + bltbx((CHAR FAR *)mpfpistName[fpi], (CHAR FAR *)rgchName, + *mpfpistName[fpi]+1); + StToSzInPlace(rgchName); + GetProfileString((LPSTR)szApp, (LPSTR)rgchName, (LPSTR)szEmpty, + (LPSTR)rgchPath, ichMaxFile); + } + + if ((cch = CchSz(rgchPath)-1) != 0) + { + if ((ch = rgchPath[cch-1]) != ':' && ch != '\\' && ch != '/') + { + rgchPath[cch++] = '\\'; + rgchPath[cch] = 0; + } + +#ifdef DFILEPATHS + CommSzSz(SzShared("Trying: "), rgchPath); +#endif /* DFILEPATHS */ + + if (FNormalizeSzFile(rgchPath, rgchNormal, nfoPathOK|nfoPathCk) + && (cch = CchSz(rgchNormal)) < ichMaxPath + && (hPath = HAllocateCb(cch)) != hNil) + { + SzToSt(rgchNormal, *hPath); + pefpi->hcPath = HcCompactH(hPath); + Assert(hPath == HExpandHc(pefpi->hcPath)); + return; + } + + /* failure: string too long, bogus directory, no heap */ + Assert(fpi != fpiProgram || vmerr.fMemFail); + ErrorEid(mpfpieid[fpi], "FInitFpi"); + } + + pefpi->fNone = fTrue; +} + + + + +/* %%Function:CchGetProgramDir %%Owner:peterj */ +int CchGetProgramDir(sz, cchMax) +CHAR *sz; +int cchMax; +{ + CHAR *pch; + + extern HANDLE vhInstance; + + pch = sz + GetModuleFileName(vhInstance, (LPSTR) sz, cchMax); + while (*pch != '\\' && *pch != '/') + { + pch--; + } + *(++pch) = '\0'; + + return (pch - sz); +} + + + +#ifdef DEBUG +/* %%Function:DiskErrorProc %%Owner:peterj */ +DiskErrorProc(eid, fn, szFunc) +CHAR *szFunc; +#else +DiskErrorProc(eid, fn) +#endif +int eid; +int fn; +{ + char szDrive[3]; + szDrive[0] = ChUpper(PfcbFn(fn)->stFile[1]); + szDrive[1] = ':'; + szDrive[2] = 0; + +#ifdef BATCH + if (vfBatchMode) +#ifdef DEBUG + BatchModeError(SzShared("DiskError! "), szFunc, eid, 0); +#else + BatchModeError(SzShared("DiskError! "), NULL, eid, 0); +#endif /* DEBUG */ +#endif /* BATCH */ + +#ifdef DEBUG + ErrorEidWProc(eid, eid == eidDiskFull ? szDrive : PfcbFn(fn)->stFile, + szFunc); +#else + ErrorEidWProc(eid, eid == eidDiskFull ? szDrive : PfcbFn(fn)->stFile); +#endif /* DEBUG */ +} + + + +/* THE FOLLOWING CAME FROM FILE.C */ + +extern int vibpProtect; /* protected bp in Ext cache */ +struct BPS HUGE * vhpmpibpbps; /* comm. variable for SortSiftUpIbp */ + +/* F F L U S H F N */ +/* Write all dirty pages in file fn to the next level of storage - +to the external cache or to the disk. Return true iff successful. +*/ +/* %%Function:FFlushFn %%Owner:peterj */ +FFlushFn(fn) +int fn; +{ + int iibpMac, ibp, iibp; + int iibpT, ibpOld; + struct BPS HUGE *hpbps; + struct BPS HUGE *hpmpibpbps; + LPRGBPEXT lprgbpExt; + BOOL fRepeat; + int ec; + char HUGE *hp; + int ibpProtectCur; + int fReturn; +#define iibpMax 100 + int rgibp[iibpMax]; + char far *lpbpExt; + +#ifdef WIN +/* If we postponed creation of the scratch file, now is the time to do it */ + + if (fn == fnScratch) + { + if (vmerr.fPostponeScratch) + { + CHAR st [ichMaxFile]; + + st [0] = 0; /* default location */ + /* we tried, even if we failed */ + vmerr.fPostponeScratch = fFalse; + Assert(vfScratchFile); /* these are set when fPostpone is set */ + Assert(vmerr.fScratchFileInit); + if (!FCreateStFile( st )) + { + vmerr.fScratchFileInit = fFalse; /* there is no scratch file */ + vfScratchFile = fFalse; /* we cannot write to the scratch file */ + ErrorEid(eidCantCreateTempFile, "FFlushFn"); + return fFalse; + } + FreezeHp(); /* safe because space is pre-reserved */ + AssertDo(FNameFn( fn, st )); + MeltHp(); + } + else if (!vfScratchFile) + /* there is no scratch file to write to, fail now */ + return fFalse; + } +#endif /* WIN */ +#ifdef DEBUG + /* BLOCK: make sure the fDirty bit doesn't lie! */ + { + struct BPS HUGE * hpbpsT = vbptbExt.hpmpibpbps; + struct BPS HUGE * hpbpsMacT = hpbpsT + vbptbExt.ibpMac; + BOOL fDirtyT = fFalse; + for ( ;hpbpsT < hpbpsMacT; hpbpsT++) + if (hpbpsT->fn == fn) + fDirtyT |= hpbpsT->fDirty; + Assert(!fDirtyT == !PfcbFn(fn)->fDirty); + } +#endif /* DEBUG */ +/* if we're certain that there are no dirty pages for this file, we needn't + scan */ + if (!PfcbFn(fn)->fDirty) + return (fTrue); + +/* when we sort the dirty buffers, the current protected page contents may + moved to another buffer slot. ibpProtectCur will keep track of where the + protected contents are moved so we can move them back to vibpProtect + when we're finished. */ + ibpProtectCur = vibpProtect; +LRepeat: + /* set global for benefit of SortIbp */ +/* WARNING: proc calls outside this module will invalidate vhpmpibpbps */ + hpmpibpbps = vbptbExt.hpmpibpbps; + vhpmpibpbps = hpmpibpbps; + + fRepeat = fFalse; +/* look for dirty cached pages that deal with file fn */ +/* set up array of ibp's so that iibp's are sorted by pn */ + iibpMac = 0; + hpbps = HpbpsIbp(0); + {{ /* NATIVE - Short loop for creating rgibp in FFlushFn */ + for (ibp = 0; ibp < vbptbExt.ibpMac; ibp++, hpbps++) + if (hpbps->fn == fn && hpbps->fDirty) + { + rgibp[iibpMac++] = ibp; + if (iibpMac >= iibpMax) + { + fRepeat = fTrue; + break; + } + } + }} + SortIbp(rgibp, iibpMac); +/* sort data blocks so that writes can be consecutive */ + for (iibp = 0; iibp < iibpMac; iibp++) + { +/* exchange rgibp[iibp] with the ibp = iibp */ + ibpOld = rgibp[iibp]; + if (ibpOld != iibp) + { + ExchangeIbp(ibpOld, iibp); + if (iibp == ibpProtectCur) + ibpProtectCur = ibpOld; + else if (ibpOld == ibpProtectCur) + ibpProtectCur = iibp; +/* perform exchange in the rest of the rgibp array, too */ + for (iibpT = iibp + 1; iibpT < iibpMac; iibpT++) + if (rgibp[iibpT] == iibp) + { + rgibp[iibpT] = ibpOld; + break; + } + rgibp[iibp] = iibp; + } + } + +#ifdef DEBUG + /* BLOCK: after the sort, make sure what we are writing is valid */ + { + struct BPS HUGE * hpbpsT = vbptbExt.hpmpibpbps; + struct BPS HUGE * hpbpsMacT = hpbpsT + iibpMac; + PN pnPrev = pnNil; + for ( ; hpbpsT < hpbpsMacT; hpbpsT++) + { + Assert(hpbpsT->pn != pnNil); /* no nil pages */ + Assert(hpbpsT->pn > pnPrev||pnPrev == pnNil);/* correct order */ + Assert(hpbpsT->fn == fn); /* all refer to correct file */ + Assert(hpbpsT->fDirty); /* everything really is dirty */ + pnPrev = hpbpsT->pn; + } + } +#endif /* DEBUG */ + +/* write out to next level pages in rgibp */ + for (iibp = 0; iibp < iibpMac;) + { + int ibp; + int pn; + int cbp = 0; + int iibpT = iibp; + int ibpT; + int cbpT; + + ibp = rgibp[iibp]; + hpbps = HpbpsHpIbp(hpmpibpbps, ibp); + pn = hpbps->pn; +/* write out pages from external cache to the disk */ +/* detect consecutive pages for possible coalescing */ +#ifdef MAC + hp = vbptbExt.hprgbpExt; +#else + hp = (char HUGE *)HpOfBptbExt( ibp ); +#endif + do + { + ++iibpT; + ++cbp; + ++hpbps; + } + while (iibpT < iibpMac && + rgibp[iibpT] == rgibp[iibpT - 1] + 1 && + hpbps->pn == pn + cbp && + /* note limitation of write operation */ + cbp < 63 + +#ifdef WIN + /* WIN: entire write must be in same sb; EMM buffers may be noncontiguous */ + && SbOfHp(HpOfBptbExt(rgibp [iibpT])) + == SbOfHp(hp) +#endif /* WIN */ + + + ); + + Assert(ibp + cbp <= vbptbExt.ibpMac); + Assert(ibp >= 0); + +#ifdef MAC + lprgbpExt = LpLockHp(hp); + lpbpExt = (char far *)&lprgbpExt[ibp]; + ec = EcWriteFnPns(fn, pn, cbp, (char far *)lpbpExt); + UnlockHp(hp); +#else + ec = EcWriteFnPns(fn, pn, cbp, hp); +#endif + +/* if scratch file pages, leave them dirty otherwise reset dirty whether +the write is sucessful or not */ + if (ec == ecDiskFull && fn == fnScratch) + { + ReportSz("Incomplete write of fnScratch"); + Assert(vfScratchFile); +/* on a scratch file, write out one by one as many pages as you can */ + while (cbp-- != 0) + { +#ifdef MAC + hp = vbptbExt.hprgbpExt; + lprgbpExt = LpLockHp(hp); + lpbpExt = (char far *)&lprgbpExt[ibp]; + ec = EcWriteFnPns(fn, pn, 1, + (char far *)lpbpExt); + UnlockHp(hp); +#else + hp = (char HUGE *)HpOfBptbExt( ibp ); + ec = EcWriteFnPns(fn, pn, 1, hp); +#endif + + if (ec <= 0) break; + HpbpsHpIbp(hpmpibpbps, ibp)->fDirty = fFalse; + ibp++; + pn++; + } + vfScratchFile = fFalse; + fReturn = fFalse; + goto LRestoreProtect; + } + + hpbps = HpbpsHpIbp(hpmpibpbps, ibp); + cbpT = ibp + cbp; + for (ibpT = ibp; ibpT < cbpT; ibpT++, hpbps++) + hpbps->fDirty = fFalse; + + if (ec == ecDiskFull) + { + fReturn = fTrue; + goto LRestoreProtect; + } + iibp += cbp; + } + if (fRepeat) goto LRepeat; + PfcbFn(fn)->fDirty = fFalse; + fReturn = fTrue; + +#ifdef MAC + /* flush the physical file and volume (directory info) */ + FlushOsfn(fn); +#endif /* MAC */ + +LRestoreProtect: + if (vibpProtect != ibpProtectCur) + ExchangeIbp(vibpProtect, ibpProtectCur); + + return (fReturn); +} + + + +/* S O R T I B P */ +/* sorts the array rgw with respect to vhpmppibbps */ +/* %%Function:SortIbp %%Owner:peterj */ +SortIbp(rgw, iwMac) +int *rgw, iwMac; +{ + int iw; + if (iwMac < 2) return; + for (iw = iwMac>>1; iw >= 2; --iw) + SortSiftUpIbp(rgw, iw, iwMac); + for (iw = iwMac; iw >= 2; --iw) + { + int w; + SortSiftUpIbp(rgw, 1, iw); + w = rgw[0]; + rgw[0] = rgw[iw - 1]; + rgw[iw - 1] = w; + } +} + + +/* S O R T S I F T U P I B P */ +/* see Floyd, Robert W. Algorithm 245 TREESORT 3 [M1] CACM 7, December 1964. */ +/* %%Function:SortSiftUpIbp %%Owner:peterj */ +SortSiftUpIbp(rgw, iwI, iwN) +int *rgw, iwI, iwN; +{ + int iwJ; + int wCopy; + + wCopy = rgw[iwI - 1]; +Loop: + iwJ = 2 * iwI; + if (iwJ <= iwN) + { + if (iwJ < iwN) + { + /* to sort rgibp by increasing pn's in vhpmpibpbps */ + if (vhpmpibpbps[rgw[iwJ]].pn > vhpmpibpbps[rgw[iwJ - 1]].pn) + iwJ++; + } + if (vhpmpibpbps[rgw[iwJ - 1]].pn > vhpmpibpbps[wCopy].pn) + { + rgw[iwI - 1] = rgw[iwJ - 1]; + iwI = iwJ; + goto Loop; + } + } + rgw[iwI - 1] = wCopy; +} + + +#ifdef FUTURE +#ifdef MAC /* Opus is not prepared to do this yet (ever?) */ +/* F C H A N G E I B P M A C E X T */ +/* changes the number of external paging buffers to ibpMac. +Returns true iff change is successful (in doubt only if ibpMac increased.) +*/ +/* %%Function:FChangeIbpMacExt %%Owner:NOTUSED */ +FChangeIbpMacExt(ibpMacNew) +int ibpMacNew; +{ + int ibp; + BOOL fResult = fTrue; + + if (ibpMacNew >= vbptbExt.ibpMac) + ibpMacNew = min(ibpMacNew, vbptbExt.ibpMax); + else + { + int ibpClean; +/* reducing the number of buffers. clear buffer states. */ +/* first move all dirty buffers to below ibpMacNew */ + int ibpDirtyMac = vbptbExt.ibpMac; + for (ibpClean = 0; ibpClean < ibpMacNew; ibpClean++) + { + if (!HpbpsHpIbp(vbptbExt.hpmpibpbps, ibp)->fDirty) + { + while (ibpDirtyMac > ibpMacNew) + { + if (HpbpsHpIbp(vbptbExt.hpmpibpbps, --ibpDirtyMac)->fDirty) + { + ExchangeIbp(ibpClean, ibpDirtyMac); + goto LLoop; + } + } + goto LClear; + } +LLoop: + ; + } +/* no more clean pages. There may be dirty pages below ibpDirtyMac */ + ibpMacNew = ibpDirtyMac; + fResult = fFalse; +LClear: + for (ibp = ibpMacNew; ibp < vbptbExt.ibpMac; ibp++) + { + Assert(!HpbpsHpIbp(vbptbExt.hpmpibpbps, ibp)->fDirty); + DeleteIbpHashEntry(ibp); + } + } + if (EcChangeSizeQq(vbptbExt.hprgbpExt, (long)ibpMacNew << shftSector) + == 0) + { + vbptbExt.ibpMac = ibpMacNew; + return fResult; + } + return fFalse; +} + + +#endif /* MAC */ + +#endif /* FUTURE */ + + +/* E X C H A N G E I B P */ +/* %%Function:ExchangeIbp %%Owner:peterj */ +ExchangeIbp(ibp1, ibp2) +int ibp1, ibp2; +{ + int i; + struct BPS bps1, bps2, HUGE *hpmpibpbps = vbptbExt.hpmpibpbps; + struct BPS HUGE *hpbps1 = &hpmpibpbps[ibp1]; + struct BPS HUGE *hpbps2 = &hpmpibpbps[ibp2]; + char (HUGE *hprgbp)[cbSector]; + char HUGE *hpb1; + char HUGE *hpb2; + char rgb[cbSector / 4]; + +/* exchange bps's, and fix up hash links */ + bps1 = *hpbps1; + bps2 = *hpbps2; + DeleteIbpHashEntry(ibp1); + DeleteIbpHashEntry(ibp2); + *hpbps2 = bps1; + *hpbps1 = bps2; + if (hpbps1->fn != fnNil) + InsertIbpHashEntry(ibp1); + if (hpbps2->fn != fnNil) + InsertIbpHashEntry(ibp2); + +/* exchange data */ +#ifdef MAC + hprgbp = vbptbExt.hprgbpExt; + hpb1 = &hprgbp[ibp1]; + hpb2 = &hprgbp[ibp2]; +#else + hpb1 = HpOfBptbExt( ibp1 ); + hpb2 = HpOfBptbExt( ibp2 ); +#endif + for (i = 0; i < 4; i++) + { + bltbh(/*from*/hpb1, rgb, cbSector / 4); + bltbh(/*from*/hpb2, hpb1, cbSector / 4); + bltbh(/*from*/rgb, hpb2, cbSector / 4); + hpb1 += cbSector / 4; + hpb2 += cbSector / 4; + } +} + + +/* I N S E R T I B P H A S H E N T R Y */ +/* %%Function:InsertIbpHashEntry %%Owner:peterj */ +InsertIbpHashEntry(ibp) +int ibp; +{ + struct BPS HUGE *hpbps = HpbpsIbp(ibp); + int HUGE *hpibpHash; + int iibp = IibpHash(hpbps->fn, hpbps->pn, vbptbExt.iibpHashMax); + hpbps->ibpHashNext = *(hpibpHash = HpibpHash(iibp)); + *hpibpHash = ibp; +} + + + +/* N A M E F N */ +/* %%Function:FNameFn %%Owner:peterj */ +FNameFn(fn, st) +int fn; +char st[]; +{ + struct FCB **hfcb = mpfnhfcb [fn]; + + Assert( hfcb != NULL ); + Assert( cwFCB * sizeof (int) == sizeof (struct FCB) ); + + if (*st >= ichMaxFile-1/*safety*/) + /* guarantee we won't overflow things later */ + { + Assert(fFalse); + return fFalse; + } + + /* cwFCB includes stFile[2], so subtract 2 but add 1 for st[0] */ +/* this is a hack to prevent heap movement when the scratch file becomes real */ + if (st [0] > (*hfcb)->stFile [0] && + !FChngSizeHCw( hfcb, cwFCB + CwFromCch(st[0] - 1), fTrue )) + return fFalse; + bltbyte( st, (*hfcb)->stFile, st[0] + 1); + return fTrue; +} + + +#ifndef PMWORD +/* F E X T E R N A L F I L E */ +/* return TRUE if fn is on a network */ +/* %%Function:FExternalFile %%Owner:peterj */ +BOOL FExternalFile(fn) +int fn; +{ + CHAR szFile[cchMaxFile]; + StToSz(PfcbFn(fn)->stFile, szFile); + return FFileRemote(szFile); +} + + +#else /* PMWORD */ +/* F E X T E R N A L F I L E */ +/* return TRUE if fn is on a network */ +/* %%Function:FExternalFile %%Owner:ricks */ +BOOL FExternalFile(fn) +int fn; +{ + int osfn; + return FOsfnRemote(OsfnEnsureValid(fn)); +} + + +#endif /* PMWORD */ + + +#ifdef PROFILE +/* this is here so that appended native code does not appear in previous + function in pcode profiles. */ +File2_Last(){} +#endif /* PROFILE */ + +/* ADD NEW CODE *ABOVE* File2_Last() */ diff --git a/src/Opus/GRSPEC.C b/src/Opus/GRSPEC.C new file mode 100644 index 0000000..a1d510d --- /dev/null +++ b/src/Opus/GRSPEC.C @@ -0,0 +1,1750 @@ +/*------------------------------------------------------------------------ +* +* +* Microsoft Windows Word -- Graphics +* +* Special graphics file routines +* +*-----------------------------------------------------------------------*/ + +#ifdef PCJ +#define DREADPIC +#endif /* PCJ */ + +#include "word.h" +DEBUGASSERTSZ /* WIN - bogus macro for assert string */ +#include "file.h" +#include "ff.h" +#include "grstruct.h" +#include "grtiff.h" +#include "pic.h" +#include "heap.h" +#include "doslib.h" +#include "debug.h" +#include "screen.h" +#include "field.h" +#include "ch.h" +#include "props.h" +#include "format.h" +#include "disp.h" +#include "doc.h" +#include "print.h" +#include "rareflag.h" +#include "error.h" + + +#define WFromStm() (WFromVfcStm()) +#define cbitByte (8) + +extern PICT **hpcCur; +extern struct MERR vmerr; +extern struct PIC vpicFetch; +extern FC vfcFetchPic; /* fc of last fetched pe */ +extern STM stmGlobal; +extern struct SCI vsci; +extern struct FLI vfli; +extern int cbMemChunk; +extern int vfDeactByOtherApp; +extern struct FTI vfti; +extern struct FTI vftiDxt; +extern CHAR szEmpty[]; +extern struct RC vrcBand; +extern int vlm; +extern struct CHP vchpFetch; +extern BOOL vfGrInterrupt; +extern struct PRI vpri; +extern CHAR szNone[]; +extern HBITMAP vhbmPatVert; /* something to select when we dump our bm */ +extern int vfnPreload; +extern int fnFetch; + +#ifdef DEBUG +extern int cHpFreeze; +#endif + +extern LPCH LpchIncr(); + +struct PL **vhplgrib = -1; +HANDLE HReadStPict(); +HANDLE HReadPgribSt(); +HANDLE HOurLoadLibrary(); + + +#ifdef INFO_ONLY +typedef struct +{ + char fPcodeEnv; + char snEnv; + unsigned bpcEnv; + int cbEnv; + int *fEnv; +} ENV; +#endif /* INFO_ONLY */ + + +/* Globals */ + +ENV vEnvGraphics = { + 0,0,0,0,0}; + + +/* F C R C A L C F L T I M P O R T */ +/* This is the calculation function for IMPORT fields + format: + {IMPORT file-name} +*/ +/* %%Function: FcrCalcFltImport %%Owner: bobz */ + + +FcrCalcFltImport (doc, ifld, flt, cpInst, cpResult, pffb) +int doc, ifld, flt; +CP cpInst, cpResult; +struct FFB *pffb; + +{ + int fn; + int istErr; + CHAR stFile[ichMaxFile+1]; + CHAR stFileNorm[ichMaxFile]; + struct FLCD flcd; + struct RC rc; + struct CHP chp; + + InitFvbBufs(&pffb->fvb, &stFile[1], ichMaxFile, NULL, 0); + + /* skip the keyword */ + SkipArgument(pffb); + + /* fetch the file name */ + FFetchArgText(pffb, fTrue); + + /* make an st */ + stFile[0] = pffb->cch; + + if (!stFile[0]) + { + istErr = istErrNoFileName; +LError: + CchInsertFieldError(doc, cpResult, istErr); + return fcrError; + } + + istErr = istErrCannotOpenFile; + if (!FNormalizeStFile(stFile, stFileNorm, nfoNormal)) + goto LError; + if (vmerr.fFnFull) + KillExtraFns(); + if ((fn = FnOpenSt(stFileNorm, fOstReadOnly, ofcDoc, NULL)) == fnNil) + goto LError; + + if (PfcbFn(fn)->fcMacFile == fc0) + { + ReportSz("0 length picture file discarded"); + KillExtraFns(); + goto LError; + } + + GetResultChp (pffb, &chp); + + /* try reading other graphic format file first */ + if (vhplgrib == -1) + InitGrib(); + + if (vhplgrib != hNil) + { + HANDLE h1, h2; + struct CA ca; + + FCloseFn(fn);/* assure library can open it */ + + SetWords(&rc, 0, cwRC); + if ((h1 = HReadStPict(stFileNorm, &rc, &h2)) != NULL) + { + BOOL f = FReadPict(PcaPoint(&ca, doc, cpResult), + CF_METAFILEPICT, h1, 0, fFalse /* fEmptyPic */, + &chp, &rc /* prcWinMF */); + GlobalFree(h1); + Assert(h2 != NULL); + GlobalFree(h2); /* free the hMF too */ + if (f) + { + goto LHavePict; + } + } + } + + /* now try internal formats */ + /* note that we pass the UNNORMALIZED file name to be stored in + the pic structure for tiff files. We normalize at display time. + */ + if (!FImportFnChPic(fn, stFile, doc, cpResult, &chp)) + { + KillExtraFns(); + istErr = istErrCannotImportFile; + goto LError; + } + + /* NOTE: if we have loaded a TIFF image we leave the fn around (it will + be needed to display the picture). the number of TIFF files that can + reasonably be open at once is limited by fnMax). A converted image or + an unsuccessful read do not need the fn. (unless we have very few fns + left, then we delete it anyway) + + New Note: leaving the file open prevents other users from accessing it; + For dibs, this is entirely unneeded. For TIFF, the bitmap cache and + eventually the new tiff filter will reduce the need to leave it open, so + let's just close it now using KillExtraFns bz 10/26/90 + */ + + +LHavePict: + + KillExtraFns(); + GetIfldFlcd(doc, ifld, &flcd); + flcd.fPrivateResult = fTrue; + SetFlcdCh(doc, &flcd, chFieldEnd); + + return fcrNormal; +} + + +/* F I M P O R T F N C H P I C */ +/* Read the file fn (stFile) which should be an IMPORT file (TIFF, etc). + Place a chPic at doc, cp which, when displayed, will display the contents + of the file. + If the file format is not understood or for some other reason we cannot + succeed, return fFalse. +*/ +/* %%Function: FImportFnChPic %%Owner: bobz */ + +FImportFnChPic(fn, stFile, doc, cp, pchp) +int fn; +CHAR *stFile; +int doc; +CP cp; +struct CHP *pchp; +{ + + int ft; + unsigned rgco[16]; + PICT **hpc = hNil; /* pc_word style PICT structure */ + PICT *ppc; + + struct CA caPic; + BITMAP bm; + HANDLE hData = NULL; + LPCH lpch; + int fOk = fFalse; + + + if (SetJmp(&vEnvGraphics) != 0) + { + if (hpc != hNil) + EndPict(hpc); + InvalidateEnv(&vEnvGraphics); + return (fFalse); + } + + StmInit(fn); + ft = FtFromStm(); + + if (ft == ftDIB) + { +#define cbReadMax 256 + + char rgb[cbReadMax]; + char * pch = rgb; + long lcb; + int cb; + BITMAPFILEHEADER bf; + + PcaPoint(&caPic, doc, cp); + + /* Read remaining part of Bitmap File Header */ + RgbFromVfcStm((CHAR *)(((BYTE *)&bf) + 2), sizeof(BITMAPFILEHEADER)-2); + + /* Calculate size of remaining data in BYTES */ + lcb = stmGlobal.fcMac - sizeof(BITMAPFILEHEADER); + + /* allocate space for DIB, can be > 64K, use GlobalAlloc2 */ + if ( ((hData=GlobalAlloc2(GMEM_MOVEABLE, lcb ))==NULL) || + ((lpch=GlobalLock( hData ))==NULL)) + { +#ifdef DEBUG + if (vdbs.fDumpPicInfo) + CommSzLong(SzShared("Unable to allocate hData! lcb="), lcb); +#endif /* DEBUG */ + goto ErrRet; + } + else + { + while (lcb > 0L) /* RobD: Is there a way to read everything at once ? */ + /* bz. Not, not using current file systen with huge pointers */ + { + RgbFromVfcStm(pch, cb = ((lcb > cbReadMax) ? cbReadMax : (WORD) lcb)); + // since we are always moving 256 bytes or the remaining + // data which we have allocated room for, we will never cross + // a 64k boundary during a blt. + // assert there is room in current segment so we can use + // bltbx instead of bltbxHuge + // cbReadMax must be at least a power of 2 for this to work + Assert (cbReadMax == 256); + Assert ((unsigned)(-LOWORD(lpch)) >= (unsigned)cb + || (unsigned)(-LOWORD(lpch)) == 0); + + bltbx((LPCH)pch, lpch, cb); + + lpch = LpchIncr(lpch, (unsigned)cb); + lcb -= cb; + } + GlobalUnlock( hData ); + } + + /* load DIB into document */ + fOk = FReadPict(&caPic, CF_DIB, hData, 0, fFalse, pchp, NULL); + + GlobalFree(hData); + return fOk; + +#undef cbReadMax + } + + if (ft != ftTIFF) + return (fFalse); + + if ((hpc = HAllocateCb(sizeof(PICT))) == hNil) + return (fFalse); + + InitPict(hpc); + (*hpc)->ft = ftTIFF; + (*hpc)->fn = fn; + + GetInfoTIFF(hpc, rgco); /* may abort out to setjmp location */ + + PcaPoint(&caPic, doc, cp); + /* allocate space for bitmap structure floowed by stFile */ + if ( ((hData=OurGlobalAlloc(GMEM_MOVEABLE, + (long)(sizeof(BITMAP) + *stFile + 1) ))==NULL) || + ((lpch=GlobalLock( hData ))==NULL)) + { + goto ErrRet; + } + else + { + ppc = *hpc; + FreezeHp(); + bm.bmType = 0; /* logical bitmap */ + bm.bmWidth = ppc->vtExt.x; + bm.bmHeight = ppc->vtExt.y; + + /* widthbytes * 8 must be next multiple of 16 > bmWidth. + so calc # of words, then convert back to bytes + */ + bm.bmWidthBytes = ((bm.bmWidth + 15) >> 4) << 1; + + + /* Note. currently GetInfoTiff will only handle 1 + and does not store the value in the PICT struct. + If that changes, update this. Also, for now + there will be only 1 output plane (no color + bm support. Change also if needed in the future. + to pick up ppc->cplIn + */ + bm.bmBitsPixel = 1; + bm.bmPlanes = 1; + + bm.bmBits = NULL; + /* store bm struct AND file name */ + bltbx( (LPCH)&bm, lpch, sizeof(BITMAP) ); + bltbx( (LPCH)stFile, lpch + sizeof(BITMAP), *stFile + 1 ); + GlobalUnlock( hData ); + MeltHp(); + } + + + /* load tiff bitmap info into document */ + fOk = FReadPict (&caPic, CF_TIFF, + hData, 0 /* cbInitial */, + fFalse /* fEmptyPic */, + pchp, NULL /* prcWinMF */); + +ErrRet: + if (hData != NULL) + GlobalFree( hData ); + if (hpc != hNil) + FreeH (hpc); + + +#ifdef DEBUG + if (vdbs.fDumpPicInfo) + CommSzSt(SzShared("FImportFnChPic: stFile = "), stFile); +#endif + + return fOk; +} + + +/* %%Function: FtFromStm %%Owner: bobz */ + +int FtFromStm() + /* + * Determine the file format of the file of the current stream. + * + * Returns: a file format code, or ftNil if unrecognizeable. + Adapted/cut down (bz) from pc word 5 + */ +{ + unsigned w0, w1; + + StmSetTIFF((FC) 0); + w0 = WFromVfcStm(); + switch (w0) + { + case 0x4949: + if (WFromVfcStm() == 0x002a) + return(ftTIFF); /* TIFF */ + break; + case 0x4d4d: + if (WFromVfcStm() == 0x2a00) + return(ftTIFF); /* TIFF */ + break; + case BFT_BMAP: + return(ftDIB); /* DIB */ + default: + break; + } + + return(ftNil); +} + + +/* %%Function: WLoadBM %%Owner: bobz */ +/* loads bitmap bits into the hbm selected into hdc */ +/* return: true if ok, false if bad, GRINTERRUPT if interrupted */ +int WLoadBm(hdc, ppicrc, ww, peid, ft, fDcCache) +HDC hdc; +struct PICRC *ppicrc; +int ww; +int *peid; +int ft; +BOOL fDcCache; +{ + + int errRet; + PICT **hpc; /* pc_word style PICT structure */ + int fn; + int fnPreloadSav; + + fnPreloadSav = vfnPreload; + if ((errRet = SetJmp(&vEnvGraphics)) != 0) + { + KillExtraFns(); + if (hpc != hNil) + EndPict(hpc); /* note this frees partially built hmdc */ + /* reflag so it will redraw later */ + if (errRet == GRINTERRUPT) + { + /* this causes FEnhandePldr to return false, so we will redisplay */ + Assert (vfGrInterrupt); + if (!vfli.fPrint) + SetfEnhanceEdlWw(ww); /* this can only work on screen */ + } + InvalidateEnv(&vEnvGraphics); + vfnPreload = fnPreloadSav; + return (errRet == GRINTERRUPT ? GRINTERRUPT : fFalse); + } + + Assert (!cHpFreeze); + + /* Anything that could potentially do a DoJmp should follow the + call to HAllocateCb so hpc will be initialized. */ + if ((hpc = HAllocateCb(sizeof(PICT))) == hNil) + { + ReportSz("Warning - bitmap PICT struct alloc failed - pic not shown"); + goto LError; + } + InitPict(hpc); + + if (ft == ftClipboard) + fn = fnFetch; + else + { + long cfcPic; + CHAR rgch[256]; + CHAR stFileNorm[ichMaxFile]; + + cfcPic = (vpicFetch.lcb - vpicFetch.cbHeader); /* size of filename */ + Assert (cfcPic <= 256); /* it is an st */ + /* get file name */ + FetchPeData(vfcFetchPic, (char HUGE *)rgch, cfcPic); + /* note: this assumes the above read succeeds; it has no way + to signal failure + */ +#ifdef XBZ + CommSzSt(SzShared("FDrawTiff: stFile = "), rgch); +#endif /* XBZ */ + + if (!FNormalizeStFile(rgch, stFileNorm, nfoNormal) + || (fn = FnOpenSt(stFileNorm, 0, ofcDoc, NULL)) == fnNil) + { + +LErrorTiff: + *peid = eidPicNoOpenDataFile; + goto LError; + } + + StmInit(fn); + ft = FtFromStm(); + if (ft != ftTIFF) + goto LErrorTiff; + } + (*hpc)->fn = fn; + (*hpc)->ft = ft; + + if (ft == ftTIFF) /* only needed by tiff */ + if (((*hpc)->sbPat = SbAllocEmmCb(cbDitherPat)) == sbNil) + { + ReportSz("Warning - tiff emm alloc failed - pic not shown"); + goto LError; + } + + (*hpc)->pixExt.x = ppicrc->picScl.xpRight - ppicrc->picScl.xpLeft; + (*hpc)->pixExt.y = ppicrc->picScl.ypBottom - ppicrc->picScl.ypTop; + /* upper left hand corner of picture */ + (*hpc)->pixOrg.x = ppicrc->picScl.xpLeft; + (*hpc)->pixOrg.y = ppicrc->picScl.ypTop; + + PrecalcBitParms(hpc); +#ifdef XBZ + { + long l = (long)(*hpc)->cbRowIn * (long)(*hpc)->irwInMax; + CommSzLong(SzShared("Bytes in bitmap: "), l); + } +#endif /* XBZ */ + Assert (!cHpFreeze); + + + if (((*hpc)->hMDC = CreateCompatibleDC(hdc)) == NULL) + { + ReportSz("Warning - bitmap CreateCompatibleDC failed - pic not shown"); + goto LError; + } + LogGdiHandle((*hpc)->hMDC, 1045); + if (!FAllocBitmap(hpc)) + { + ReportSz("Warning - bitmap alloc failed - pic not shown"); +LError: + Assert (!cHpFreeze); + GraphicsError(hpc, IDPMTPictErr); + Assert(fFalse); /* GraphicsError does a DoJmp */ + } + FreezeHp(); + if (!vfli.fPrint) + GetClipBox (hdc, (LPRECT)&((*hpc)->rcClip)); + else + (*hpc)->rcClip = vrcBand; + if (fDcCache) + { + /* Disable limiting to clip rectangle if going into cache */ + (*hpc)->rcClip.ypTop = -32767; + (*hpc)->rcClip.ypBottom = 32767; + } + MeltHp(); + + Assert (!cHpFreeze); + vfnPreload = fn; + while (FPrepBitmap(hpc)) + { + ReadBitmap(hpc); /* pull in a swath */ + CheckGrAbortWin(hpc); + /* check clipping; if above clip we read but not translate */ + if ((*hpc)->pixOrg.v + (int)(*hpc)->irwOutMac >= (*hpc)->rcClip.ypTop) + { + TranslateBitmap(hpc); /* stretchblt and map colors */ + /* didn't want to check w/in translate... */ + CheckGrAbortWin(hpc); + if (!FSendBitmap(hpc, hdc, ppicrc, fDcCache)) + { + Assert (!cHpFreeze); + ReportSz("Warning - snd bitmap failed - pic not shown"); + GraphicsError(hpc, IDPMTPictErr); + /* break; not needed since we will dojmp */ + } + } + } + + KillExtraFns(); + EndPict(hpc); /* frees up hpc */ + vfnPreload = fnPreloadSav; + return (fTrue); +} + + + + + + + +/* %%Function: InitPict %%Owner: bobz */ + +InitPict(hpc) +PICT **hpc; + /* + * Initialize a PICT. + */ +{ + Assert (sbNil == 0); /* so blt will set up sb's correctly */ + + SetBytes(*hpc, 0, sizeof (PICT)); + vfGrInterrupt = fFalse; +} + + +/* %%Function: FAllocBitmap %%Owner: bobz */ + +FAllocBitmap(hpc) +PICT **hpc; +{ + unsigned csw; /* number of swaths worh of memory allocated */ + unsigned cbSwathMin; + PICT *ppc; + unsigned cbWant = 0; + SB sb = sbNil; + + /* if we can't get a whole segment worth, ask for half as much + until we get some. + */ + cbSwathMin = (*hpc)->cbSwathMin; + csw = UMultDiv((unsigned) (cbLmemHeap - (*hpc)->cbExtra), 1, cbSwathMin); + + while (csw >= 1) + { + cbWant = csw * cbSwathMin + (*hpc)->cbExtra; + if ((sb = SbAllocEmmCb(cbWant)) != sbNil) + break; + else + csw >>= 1; + } + + if (sb != sbNil) + { + ppc = *hpc; + ppc->cbBits = cbWant; + ppc->sbBits = sb; + ppc->ibIn = 0; + } + + return (sb != sbNil); +} + + +/* %%Function: ReadBitmap %%Owner: bobz */ + +ReadBitmap(hpc) +PICT **hpc; +{ + + +#ifdef XBZ + CommSzRgNum(SzShared("hpc in readbitmap to tiff: "), + (char *)*hpc, (sizeof(PICT) - sizeof (TIFF)) >> 1); + if ((*hpc)->ft == ftTIFF) + CommSzRgNum(SzShared("hpc in readbitmap tiff: "), + ((char *)*hpc) + (sizeof(PICT) - sizeof (TIFF)), sizeof(TIFF) >> 1); +#endif /* BZ */ + + + if ((*hpc)->ft == ftTIFF) + ReadTIFF(hpc); + else + ReadWIN(hpc); + +} + + +/* %%Function: ReadWIN %%Owner: bobz */ + +ReadWIN(hpc) +PICT **hpc; +{ + long cb; + PICT *ppc; + FC fcFetch; + + ppc = *hpc; + cb = ppc->cbRowIn * (ppc->irwInMac - ppc->irwInMic); + Assert (cb <= ppc->cbBits); + Assert (ppc->cbRowIn == vpicFetch.bm.bmWidthBytes); + Assert(vchpFetch.fSpec); + + /* we need to read starting at irwInMic, not read successively + because of rounding that can cause overflow. vfcFetchPic + is left after the pic struct where FetchPe put it. + */ + + fcFetch = vfcFetchPic + + (long)(ppc->cbRowIn * ppc->irwInMic); + + Assert ((LONG)((long)cb + fcFetch - vchpFetch.fcPic & 0x00FFFFFF) <= vpicFetch.lcb); + + FetchPeData(fcFetch, HpOfSbIb(ppc->sbBits, ppc->ibIn), cb); + + +} + + +/* %%Function: FSendBitmap %%Owner: bobz */ + +FSendBitmap(hpc, hdc, ppicrc, fDcCache) +PICT **hpc; +HDC hdc; +struct PICRC *ppicrc; +BOOL fDcCache; +{ + + LPCH lpch; + int dypPic, dxpPic; + BITMAP bm; + CHAR HUGE *hpBits; + + Assert ((*hpc)->hMDC != NULL); + + dxpPic = ppicrc->picScl.xpRight - ppicrc->picScl.xpLeft; + dypPic = (*hpc)->irwOutMac - (*hpc)->irwOutMic; + + /* create bitmap only if there is none or its height has changed */ + if ((*hpc)->hbm == NULL || (*hpc)->dypBm != dypPic) + { + if ((*hpc)->hbm != NULL) /* dump old one */ + { + SelectObject( (*hpc)->hMDC, vhbmPatVert); /* abritrary bm; so we can dispose selected bm */ + UnlogGdiHandle((*hpc)->hbm, -1); + DeleteObject((*hpc)->hbm); + } + /* the bitmap we are now creating has been stretchblted + to the desired output size, and so is no longer the same + as that in vpicFetch. In later calls, however, the width + will stay the same but the height may change, especially + if not only, on the last swath. + */ + bm.bmType = 0; /* logical bitmap */ + bm.bmWidth = dxpPic; + bm.bmHeight = dypPic; + bm.bmWidthBytes = (*hpc)->cbRowOut; + bm.bmBitsPixel = 1; + bm.bmPlanes = 1; + bm.bmBits = NULL; + if (((*hpc)->hbm = CreateBitmapIndirect((LPBITMAP)&bm)) == NULL) + return (fFalse); /* caller will handle freeing */ + LogGdiHandle((*hpc)->hbm, 1030); + (*hpc)->dypBm = dypPic; + } + + + hpBits = HpOfSbIb((*hpc)->sbBits, 0); + /* bm.bits just a handy holder for the lp */ + if ( ((bm.bmBits = LpLockHp(hpBits)) == NULL) || + (SetBitmapBits((*hpc)->hbm, (DWORD)((*hpc)->cbRowOut * dypPic), + (LPSTR)bm.bmBits) == 0L) || + (SelectObject( (*hpc)->hMDC, (*hpc)->hbm ) == NULL) ) + { + if (bm.bmBits != NULL) + UnlockHp(hpBits); + return (fFalse); /* caller will handle freeing */ + } + + UnlockHp(hpBits); + + Assert( (*hpc)->hbm != NULL && (*hpc)->hMDC != NULL ); + + BitBlt( hdc, fDcCache ? 0 : ppicrc->picScl.xpLeft, + (fDcCache ? 0 : ppicrc->picScl.ypTop) + (*hpc)->irwOutMic, + dxpPic, dypPic, + (*hpc)->hMDC, 0, 0, + vsci.fMonochrome ? + ropMonoBm : SRCCOPY ); + +#ifdef XBZ + CommSzNum(SzShared("FSendBitmap dxpPic: "), dxpPic); + CommSzNum(SzShared("FSendBitmap dypPic: "), dypPic); + CommSzNum(SzShared("FSendBitmap dxpIn: "), (*hpc)->vtExt.h); + CommSzNum(SzShared("FSendBitmap dypIn: "), (*hpc)->irwInMac - (*hpc)->irwInMic); +#endif + + return (fTrue); + +} + + +/* %%Function: EndPict %%Owner: bobz */ + +EndPict(hpc) +PICT **hpc; +{ + extern HBITMAP vhbmPatVert; + +#ifdef XBZ + CommSzNum(SzShared("EndPic sbBits: "), (*hpc)->sbBits); + CommSzNum(SzShared("EndPic sbPat: "), (*hpc)->sbPat); +#endif + + if ((*hpc)->sbBits != sbNil) + FreeEmmSb((*hpc)->sbBits); + + if ((*hpc)->sbPat != sbNil) + FreeEmmSb((*hpc)->sbPat); + + + if ((*hpc)->hMDC != NULL) + { + FSetDcAttribs( (*hpc)->hMDC, dccmUnlockBrushPen ); + SelectObject( (*hpc)->hMDC, vhbmPatVert); /* abritrary bm; so we can dispose selected bm */ + UnlogGdiHandle((*hpc)->hMDC, 1045); + AssertDo(DeleteDC( (*hpc)->hMDC )); + } + if ((*hpc)->hbm != NULL) + { + UnlogGdiHandle((*hpc)->hbm, -1); + DeleteObject( (*hpc)->hbm ); + } + + FreeH(hpc); + +} + + +/* ************* Misc routines from PC Word needed by Opus **************** */ + + +/* %%Function: HprgbFromVfcStm %%Owner: bobz */ + + +HprgbFromVfcStm(hprgb, cb) +char HUGE *hprgb; +int cb; +{ + SetFnPos(stmGlobal.fn, stmGlobal.fc); + ReadHprgchFromFn(stmGlobal.fn, hprgb, cb); + stmGlobal.fc += cb; +} + + +/* %%Function: WSwappedFromStm %%Owner: bobz */ + +WSwappedFromStm() +{ + int w; + w = WFromStm(); + SwitchBytes(&w, 1); + return (w); +} + + +/* %%Function: StmInit %%Owner: bobz */ + +StmInit(fn) +{ + stmGlobal.fn = fn; + stmGlobal.fc = (FC)0; + stmGlobal.fcMac = (FC)PfcbFn(fn)->cbMac; + +#ifdef XBZ + CommSzNum(SzShared("StmInit stmglobal.fn: "), stmGlobal.fn); + CommSzLong(SzShared("StmInit stmglobal.fcMac: "), stmGlobal.fcMac); +#endif +} + + +/* %%Function: StmSetTIFF %%Owner: bobz */ +/* TIFF variant of SetStmPos that aborts via SetJmp if fc out of range. + vENVGraphics MUST be set before this is called. Only call this out + of the routines called by FImportFnChPic or FDrawBitmap, which set + the env. +*/ + +StmSetTIFF(fc) +FC fc; +{ + if (fc > stmGlobal.fcMac || fc < (FC)0) + { +#ifdef BZ + CommSzLong(SzShared("StmSetTIFF inval fc: "), fc); +#endif + Assert (vEnvGraphics.fPcodeEnv); /* assure ENV set up */ + EndGraphics(GRERROR); /* does a dojmp */ + } + else + SetStmPos(stmGlobal.fn, fc); +} + + + + +/* Sign-extend character to integer */ +/* %%Function: sxt %%Owner: bobz */ + +int sxt (ch) +int ch; +{ + return(ch - ((ch & 0x80) << 1)); +} + + +/* %%Function: EndGraphics %%Owner: bobz */ + +EndGraphics(valRet) +{ + /* EndPict(hpc) now done at Jmp location */ + DoJmp (&vEnvGraphics, valRet); +} + + +/* %%Function: FEof %%Owner: bobz */ + +FEof() +{ + return (stmGlobal.fc > stmGlobal.fcMac); +} + + +/* %%Function: CheckGrAbortWin %%Owner: bobz */ + +CheckGrAbortWin(hpc) +{ + extern HWND vhwndPgPrvw; /* Page preview window handle */ + MSG msg; + + Assert (!cHpFreeze); + /* only abort on galley and pageview. Except for print we also will + abort so we can yield to spooler. Not in print preview which + has messages flying around that abort us right off or for interrupt + or even for print, which could cause formatlines. In these cases + peek to yield but do not interrupt */ + + /* bz for fPrint we used to call FQueryAbortCheck but that could + cause updateww which would call formatline and we + are within displayfli. So only abort at the line + level (let print code handle it). Peek to yield. + */ + if (vfli.fPrint || vlm == lmPreview || vfDeactByOtherApp) + PeekMessage((MSG far *)&msg, NULL, 0, 0, PM_NOREMOVE); + else if (FMsgPresent (mtyLongDisp)) /* won't blink & cause formatline call */ + { +#ifdef BZ + CommSz(SzShared("CheckGrAbortWin bitmap interrupted\n")); +#endif /* BZ */ + vfGrInterrupt = fTrue; + EndGraphics(GRINTERRUPT); + } +} + + +/* dummies for sake of shared code */ +/* %%Function: GetInfoPCX %%Owner: bobz */ + +GetInfoPCX(hpc, rgco) +PICT **hpc; +unsigned rgco[]; +{ + Assert (fFalse); +} + + +/* %%Function: GetInfoWin %%Owner: bobz */ + +GetInfoWin(hpc, rgco) +PICT **hpc; +unsigned rgco[]; +{ + PICT *ppc; + + ppc = *hpc; + + ppc->vtExt.x = vpicFetch.bm.bmWidth; + ppc->vtExt.y = vpicFetch.bm.bmHeight; + ppc->cplIn = 1; + /* note order different than in tiff files because windows bitmaps + are already in the desired bit order and we don't have + to flip 0 and 1 bz + */ + rgco[0] = coBlack; + rgco[1] = coWhiteGR; + +} + + +/* color mapping to dither pattern routines */ +/* %%Function: DistFromCoCo %%Owner: bobz */ + +DistFromCoCo (co1, co2) +CO co1, +co2; +{ + int coT; + int dRed, dGreen, dBlue; + +#ifdef PCWORD + SB sbSav = sbCur; + + ResetSbCur(); +#endif /* PCWORD */ + + + dRed = co1.red - co2.red; + dGreen = co1.green - co2.green; + dBlue = co1.blue - co2.blue; + coT = dRed*dRed + dGreen*dGreen + dBlue*dBlue; + + +#ifdef PCWORD + SetSbCur(sbSav); +#endif /* PCWORD */ + + return (coT); +} + + +/* %%Function: IcoFromCoCcoRgco %%Owner: bobz */ + + + +IcoFromCoCcoRgco (co, cco, rgco) +CO co; +int cco; +int rgco[]; + /* + * Return the index into rgco of the color nearest to co. + * +* PCWORD only - Warning: sbCur == SbOfHp(hpvdvCur) during this procedure. + */ +{ + int icoCur, + icoMac, + icoNear, + wdistNear, + icoMaxM1, + wdistCur; + int *pco; + + +#ifdef PCWORD + PresetSbCur(); /* sbCur != sbApp */ +#endif /* PCWORD */ + + + /* get number of colors */ + icoMac = cco; + icoMaxM1 = icoMac-1; + + Assert(icoMac > 0); + + /* check first for white (a very common color) */ + #ifdef OPUS_X64 + if (rgco[icoMaxM1] == (int) OpusCoValue(co)) return icoMaxM1; + #else + if (rgco[icoMaxM1] == (int) co) return icoMaxM1; + #endif + /* for all colors in pallette, ... */ + for (pco = rgco,icoCur = 0; icoCur < icoMaxM1; ++icoCur,++pco) + { + #ifdef OPUS_X64 + if ((int)(*pco) == (int) OpusCoValue(co)) return (icoCur); + #else + if ((int)(*pco) == (int) co) return (icoCur); + #endif + } + + /* initialize nearest color to first color */ + wdistNear = DistFromCoCo(co, *rgco); + icoNear = 0; + + for (pco=&rgco[icoMaxM1],icoCur=icoMaxM1; icoCur > 0; --icoCur,--pco) + { + /* find nearest color */ + if (wdistNear > (wdistCur = DistFromCoCo(co, *pco))) + { + wdistNear = wdistCur; + icoNear = icoCur; + } + } + + return (icoNear); +} + + + +/* Convert from pixels to twips for the current device */ +/* %%Function: ScaleToTwp %%Owner: bobz */ + +ScaleToTwp(pPoint) +TWP *pPoint; +{ + pPoint->v = NMultDiv (pPoint->v, czaInch, vfti.dypInch); + pPoint->h = NMultDiv (pPoint->h, czaInch, vfti.dxpInch); +} + + +/* %%Function: IntAssertProc %%Owner: bobz */ + +int IntAssertProc(unsval) +int unsval; +{ + Assert(unsval >= 0); + return unsval; +} + + +/* get picture size from tiff file */ + +/* %%Function: GetGrSize %%Owner: bobz */ + +GetGrSize(ft, pdya, pdxa) +int ft; /* user-supplied type */ +int *pdya, /* fill in with size or aspect ratio of picture */ +*pdxa; + /* + * Purpose: Determine the picture size of a graphic file. + */ +{ + switch (ft) + { + default: + Assert(FALSE); + *pdxa = *pdya = 0; + break; + case ftTIFF: + { + + /* this assumes stm has been set up before this call */ + FC fc; + int ide, cde; + long lx0 = -1L; + long lx1 = -1L; + long ly0 = -1L; + long ly1 = -1L; + + BOOL fSwitchBytes; + VPOINT vtImageSize; + DEN den; + int ctwp = czaInch; + + vtImageSize.y = -1; + vtImageSize.x = -1; + + StmSetTIFF((FC)0); + fSwitchBytes = (WFromStm() == 0x4d4d); + + GetPifdTIFF(&fc, fSwitchBytes); + StmSetTIFF(fc); + cde = WFromTIFF(fSwitchBytes); + + for (ide = 0; ide < cde; ide++) + { + DenFromTIFF(&den, fSwitchBytes); + if (den.wTag > YResolution) + break; + switch (den.wTag) + { + default: + break; + case ImageLength: + vtImageSize.y = den.w1Value; + break; + case ImageWidth: + vtImageSize.x = den.w1Value; + break; + case ResolutionUnit: + /* use czaInch unless none or centimeter is specified */ + if (den.wTag == 1) + ctwp = 1; + else if (den.wTag == 3) + ctwp = czaCm; + else + ctwp = czaInch; + break; + case XResolution: + case YResolution: + fc = StmGlobalFc(); + StmSetTIFF(den.lpValue); + + if (den.wTag == XResolution) + { + LFromTIFF(&lx0,fSwitchBytes); + LFromTIFF(&lx1,fSwitchBytes); + } + else + { + LFromTIFF(&ly0,fSwitchBytes); + LFromTIFF(&ly1,fSwitchBytes); + } + StmSetTIFF(fc); + break; + } + } + + if (lx0 == -1L || lx1 == -1L || ly0 == -1L || ly1 == -1L) + { + /* if any or all of these are undefined, use screen + resolution to convert pixels to twips + */ + lx0 = (long) vfti.dxpInch; /* default to pixels on current device */ + lx1 = 1L; + ly0 = (long)vfti.dypInch; /* default to pixels on current device */ + ly1 = 1L; + ctwp = czaInch; + } + /* catch missing or invalid required fields */ + /* longs must be > 0 && < 65535; no high bits set */ + + if ((lx0 & 0xffff0000) || (lx1 & 0xffff0000) || + (ly0 & 0xffff0000) || (ly1 & 0xffff0000) || + /* mults can't overflow long result due to above tests */ + ((unsigned long)(lx1 * ctwp) & 0xffff0000)|| + ((unsigned long)(ly1 * ctwp) & 0xffff0000) || + vtImageSize.y <= 0 || vtImageSize.x <= 0) + { + *pdxa = *pdya = 0; + break; /* will fall into safety net below */ + } + + /* validity of casts assured by test above. Jodi claims real + world tiff files will always be in this range. + */ + *pdxa = UMultDiv(vtImageSize.x,(unsigned)(lx1*ctwp),(unsigned)lx0); + *pdya = UMultDiv(vtImageSize.y,(unsigned)(ly1*ctwp),(unsigned)ly0); + + if (ctwp == 1) /* no units. Use values as aspect ratio only */ + if (*pdxa > *pdya) + { + *pdxa = 3 * czaInch; + *pdya = NMultDiv (3 * czaInch, *pdya, *pdxa); + } + else + { + *pdya = 3 * czaInch; + *pdxa = NMultDiv (3 * czaInch, *pdxa, *pdya); + } + + break; + } + } + /* safety net */ + if (*pdxa > czaMax || *pdxa <= 0) + *pdxa = 3 * czaInch; + if (*pdya > czaMax || *pdya <= 0) + *pdya = 3 * czaInch; + +} + + +/* ************* End Misc routines from PC Word needed by Opus ************ */ + + + +/* ************************************************************************* */ +/* Interface to graphic converter libraries--based on PowerPoint's readers.c */ +/* ************************************************************************* */ + +/* win.ini file format: + [WWFilters] + =, ,