Functions that should be static

Francois Gouget fgouget at free.fr
Thu Dec 18 03:09:02 CST 2008


I have attached a script that identifies functions that should be made 
static (among other things). There are approximately 450 of them, there 
should be pretty efw false positives, and I will look into them 
eventually. But if someone beats me to it I sure won't complain <g>.

So if you do try to tackle them you are likely to find that they fall 
into one of the following categories:

 1) Unused debug functions.
    For instance for dumping the contents of a structure to stderr. 
    Although these are unused we probably want to keep them. Let me know 
    about these and I will put them in an exception list.

 2) Functions that should be exported by a spec file
    It happens. Sometimes the developer implementing a function just 
    forgets to add it to the spec file!

 3) Generated functions
    This typically happens with widl: it generates a bunch of functions 
    for the client / server and proxy cases, but these functions may be 
    unused. I have special code to not warn about these, but there may 
    be other cases. For instance in the list below you will find a 
    number of yy*() functions generated by lex. Either we can tell lex 
    to make them static or to not generate them, or I should make 
    another special case. If you find some of these, let me know.

 4) Assembly functions
    I believe there should not be any of these in the list below.
    So if you find one let me know.

 5) Functions declared in a private header file but implemented and used 
    from a single C file.
    I'm in favor of removing these functions from the private header and 
    making them static.

 6) All the others should be pretty clear-cut.


dlls/advapi32/advapi32.dll.so: CRYPT_DESkey8to7
dlls/browseui/tests/browseui_test.exe.so: strdup_AtoW
dlls/browseui/tests/browseui_test.exe.so: TestACL_ACList_AddRef
dlls/browseui/tests/browseui_test.exe.so: TestACL_ACList_QueryInterface
dlls/browseui/tests/browseui_test.exe.so: TestACL_ACList_Release
dlls/browseui/tests/browseui_test.exe.so: TestACL_AddRef
dlls/browseui/tests/browseui_test.exe.so: TestACL_Clone
dlls/browseui/tests/browseui_test.exe.so: TestACL_Expand
dlls/browseui/tests/browseui_test.exe.so: TestACL_Next
dlls/browseui/tests/browseui_test.exe.so: TestACL_QueryInterface
dlls/browseui/tests/browseui_test.exe.so: TestACL_Release
dlls/browseui/tests/browseui_test.exe.so: TestACL_Reset
dlls/browseui/tests/browseui_test.exe.so: TestACL_Skip
dlls/cabinet/cabinet.dll.so: checksum
dlls/cabinet/cabinet.dll.so: make_decode_table
dlls/cabinet/cabinet.dll.so: QTMupdatemodel
dlls/comctl32/tests/comctl32_test.exe.so: flush_sequence
dlls/comdlg32/comdlg32.dll.so: CC_WMCommand
dlls/crypt32/crypt32.dll.so: ContextList_Empty
dlls/dbghelp/dbghelp.dll.so: hash_table_find
dlls/dbghelp/dbghelp.dll.so: hash_table_hash
dlls/dbghelp/dbghelp.dll.so: module_find_by_name
dlls/dbghelp/dbghelp.dll.so: module_get_container
dlls/dinput/dinput.dll.so: DIEnumDevicesCallbackAtoW
dlls/dmime/dmime.dll.so: DMUSIC_CreateDirectMusicobjImpl
dlls/dmime/dmime.dll.so: DMUSIC_CreateDirectMusicPatternTrackImpl
dlls/dmusic/dmusic.dll.so: DMUSIC_CreateDirectMusicBufferImpl
dlls/dmusic/dmusic.dll.so: DMUSIC_CreateDirectMusicDownloadedInstrumentImpl
dlls/dmusic/dmusic.dll.so: DMUSIC_CreateDirectMusicDownloadImpl
dlls/dnsapi/dnsapi.dll.so: dns_ns_name_pton
dlls/dplayx/dplayx.dll.so: cbDeleteGroupsElem
dlls/dplayx/dplayx.dll.so: cbDeletePlayerElem
dlls/dplayx/dplayx.dll.so: DPLAYX_DestroyLobbyApplication
dlls/dplayx/dplayx.dll.so: DPLAYX_SetLocalSession
dlls/dplayx/dplayx.dll.so: NS_GetOtherMagic
dlls/dplayx/dplayx.dll.so: NS_SetRemoteComputerAsNameServer
dlls/dsound/dsound.dll.so: DirectSoundCaptureDevice_AddRef
dlls/fusion/fusion.dll.so: assembly_get_architecture
dlls/fusion/fusion.dll.so: CompareAssemblyIdentity
dlls/fusion/fusion.dll.so: GetAssemblyIdentityFromFile
dlls/inetcomm/inetcomm.dll.so: InternetTransport_Read
dlls/iphlpapi/iphlpapi.dll.so: getInterfaceEntryByIndex
dlls/iphlpapi/iphlpapi.dll.so: getInterfacePhysicalByName
dlls/itss/itss.dll.so: chm_enumerate
dlls/jscript/jscript.dll.so: jsdisp_call
dlls/jscript/jscript.dll.so: parser_parse
dlls/mountmgr.sys/mountmgr.sys.so: DriverEntry
dlls/msacm32/msacm32.dll.so: MSACM_UnregisterLocalDriver
dlls/mshtml/mshtml.dll.so: HTMLElementCollection_Create
dlls/msi/msi.dll.so: cond_parse
dlls/msi/msi.dll.so: ControlEvent_UnSubscribeToEvent
dlls/msi/msi.dll.so: db_get_raw_stream
dlls/msi/msi.dll.so: encode_streamname
dlls/msi/msi.dll.so: find_published_source
dlls/msi/msi.dll.so: MSI_DatabaseExport
dlls/msi/msi.dll.so: MSI_DatabaseImport
dlls/msi/msi.dll.so: msi_dialog_register_class
dlls/msi/msi.dll.so: MSI_EnableUIPreview
dlls/msi/msi.dll.so: msi_id2stringA
dlls/msi/msi.dll.so: msi_id2stringW
dlls/msi/msi.dll.so: msi_load_media_info
dlls/msi/msi.dll.so: MSI_PreviewDialogW
dlls/msi/msi.dll.so: MSI_RecordDataSize
dlls/msi/msi.dll.so: MSI_RecordSetStream
dlls/msi/msi.dll.so: MSI_RecordSetStringA
dlls/msi/msi.dll.so: MSIREG_OpenInstallerFeaturesKey
dlls/msi/msi.dll.so: msi_strcmp
dlls/msi/msi.dll.so: msi_string2idA
dlls/msi/msi.dll.so: msi_ui_error
dlls/msi/msi.dll.so: msi_version_dword_to_str
dlls/msi/msi.dll.so: reduce_to_shortfilename
dlls/msi/msi.dll.so: sql_parse
dlls/msxml3/msxml3.dll.so: httprequest_Release
dlls/msxml3/msxml3.dll.so: XMLElementCollection_create
dlls/netapi32/netapi32.dll.so: NBNameCacheUpdateNBName
dlls/ole32/ole32.dll.so: IMalloc16_Constructor
dlls/qcap/qcap.dll.so: FreeMediaType
dlls/qcap/qcap.dll.so: IPinImpl_QueryInternalConnections
dlls/quartz/quartz.dll.so: MemInputPin_AddRef
dlls/quartz/quartz.dll.so: MemInputPin_GetAllocator
dlls/quartz/quartz.dll.so: MemInputPin_GetAllocatorRequirements
dlls/quartz/quartz.dll.so: MemInputPin_NotifyAllocator
dlls/quartz/quartz.dll.so: MemInputPin_QueryInterface
dlls/quartz/quartz.dll.so: MemInputPin_Receive
dlls/quartz/quartz.dll.so: MemInputPin_ReceiveCanBlock
dlls/quartz/quartz.dll.so: MemInputPin_ReceiveMultiple
dlls/quartz/quartz.dll.so: MemInputPin_Release
dlls/quartz/quartz.dll.so: OutputPin_DeliverNewSegment
dlls/riched20/riched20.dll.so: ME_ConcatString
dlls/riched20/riched20.dll.so: ME_CopyToCF2W
dlls/riched20/riched20.dll.so: ME_DestroyEditor
dlls/riched20/riched20.dll.so: ME_DITypesEqual
dlls/riched20/riched20.dll.so: ME_DrawParagraph
dlls/riched20/riched20.dll.so: ME_FindItemFwdOrHere
dlls/riched20/riched20.dll.so: ME_FindNextURLCandidate
dlls/riched20/riched20.dll.so: ME_FindRowStart
dlls/riched20/riched20.dll.so: ME_GetOptimalBuffer
dlls/riched20/riched20.dll.so: ME_GetParaFormat
dlls/riched20/riched20.dll.so: ME_GetYScrollVisible
dlls/riched20/riched20.dll.so: ME_InvalidateFromOfs
dlls/riched20/riched20.dll.so: ME_IsCandidateAnURL
dlls/riched20/riched20.dll.so: ME_LinkNotify
dlls/riched20/riched20.dll.so: ME_MakeEditor
dlls/riched20/riched20.dll.so: ME_MakeStringB
dlls/riched20/riched20.dll.so: ME_MarkForWrapping
dlls/riched20/riched20.dll.so: ME_QueueInvalidateFromCursor
dlls/riched20/riched20.dll.so: ME_Scroll
dlls/riched20/riched20.dll.so: ME_SelectByType
dlls/riched20/riched20.dll.so: ME_SetParaFormat
dlls/riched20/riched20.dll.so: ME_ToCFAny
dlls/riched20/riched20.dll.so: ME_UpdateLinkAttribute
dlls/riched20/riched20.dll.so: ME_UpdateSelection
dlls/riched20/riched20.dll.so: ME_UpdateSelectionLinkAttribute
dlls/riched20/riched20.dll.so: REComboWndProc
dlls/riched20/riched20.dll.so: REListWndProc
dlls/riched20/riched20.dll.so: RTFExpandStyle
dlls/riched20/riched20.dll.so: RTFGetClassCallback
dlls/riched20/riched20.dll.so: RTFGetDestinationCallback
dlls/riched20/riched20.dll.so: RTFGetInputName
dlls/riched20/riched20.dll.so: RTFGetOutputName
dlls/riched20/riched20.dll.so: RTFGetReadHook
dlls/riched20/riched20.dll.so: RTFGetStyle
dlls/riched20/riched20.dll.so: RTFHexToChar
dlls/riched20/riched20.dll.so: RTFPeekToken
dlls/riched20/riched20.dll.so: RTFSetClassCallback
dlls/riched20/riched20.dll.so: RTFSetInputName
dlls/riched20/riched20.dll.so: RTFSetOutputName
dlls/riched20/riched20.dll.so: RTFSetToken
dlls/riched20/riched20.dll.so: RTFUngetToken
dlls/rpcrt4/rpcrt4.dll.so: NCA2RPC_STATUS
dlls/rpcrt4/rpcrt4.dll.so: NdrByteCountPointerMemorySize
dlls/rpcrt4/rpcrt4.dll.so: NdrRangeBufferSize
dlls/rpcrt4/rpcrt4.dll.so: NdrRangeFree
dlls/rpcrt4/rpcrt4.dll.so: NdrRangeMarshall
dlls/rpcrt4/rpcrt4.dll.so: NdrRangeMemorySize
dlls/rpcrt4/rpcrt4.dll.so: RPCRT4_receive_fragment
dlls/rpcrt4/rpcrt4.dll.so: RPCRT4_SpawnConnection
dlls/rpcrt4/rpcrt4.dll.so: RPCRT4_ValidateCommonHeader
dlls/rsaenh/rsaenh.dll.so: alloc_handle_table
dlls/rsaenh/rsaenh.dll.so: mp_2expt
dlls/rsaenh/rsaenh.dll.so: mp_abs
dlls/rsaenh/rsaenh.dll.so: mp_add_d
dlls/rsaenh/rsaenh.dll.so: mp_clamp
dlls/rsaenh/rsaenh.dll.so: mp_clear
dlls/rsaenh/rsaenh.dll.so: mp_cmp_mag
dlls/rsaenh/rsaenh.dll.so: mp_cnt_lsb
dlls/rsaenh/rsaenh.dll.so: mp_div
dlls/rsaenh/rsaenh.dll.so: mp_div_2
dlls/rsaenh/rsaenh.dll.so: mp_div_2d
dlls/rsaenh/rsaenh.dll.so: mp_div_d
dlls/rsaenh/rsaenh.dll.so: mp_dr_reduce
dlls/rsaenh/rsaenh.dll.so: mp_dr_setup
dlls/rsaenh/rsaenh.dll.so: mp_exch
dlls/rsaenh/rsaenh.dll.so: mp_grow
dlls/rsaenh/rsaenh.dll.so: mp_init
dlls/rsaenh/rsaenh.dll.so: mp_init_size
dlls/rsaenh/rsaenh.dll.so: mp_lshd
dlls/rsaenh/rsaenh.dll.so: mp_mod_2d
dlls/rsaenh/rsaenh.dll.so: mp_mod_d
dlls/rsaenh/rsaenh.dll.so: mp_montgomery_calc_normalization
dlls/rsaenh/rsaenh.dll.so: mp_montgomery_reduce
dlls/rsaenh/rsaenh.dll.so: mp_montgomery_setup
dlls/rsaenh/rsaenh.dll.so: mp_mul_2
dlls/rsaenh/rsaenh.dll.so: mp_mul_2d
dlls/rsaenh/rsaenh.dll.so: mp_mul_d
dlls/rsaenh/rsaenh.dll.so: mp_prime_is_divisible
dlls/rsaenh/rsaenh.dll.so: mp_prime_is_prime
dlls/rsaenh/rsaenh.dll.so: mp_prime_miller_rabin
dlls/rsaenh/rsaenh.dll.so: mp_reduce
dlls/rsaenh/rsaenh.dll.so: mp_reduce_2k
dlls/rsaenh/rsaenh.dll.so: mp_reduce_2k_setup
dlls/rsaenh/rsaenh.dll.so: mp_reduce_setup
dlls/rsaenh/rsaenh.dll.so: mp_rshd
dlls/rsaenh/rsaenh.dll.so: mp_set
dlls/rsaenh/rsaenh.dll.so: mp_signed_bin_size
dlls/rsaenh/rsaenh.dll.so: mp_sqr
dlls/rsaenh/rsaenh.dll.so: mp_sqrmod
dlls/rsaenh/rsaenh.dll.so: mp_zero
dlls/rsaenh/rsaenh.dll.so: release_handle_table
dlls/sane.ds/sane.ds.so: SANE_AutomaticCaptureDirectory
dlls/sane.ds/sane.ds.so: SANE_FileSystemCopy
dlls/sane.ds/sane.ds.so: SANE_PendingXfersStopFeeder
dlls/sane.ds/sane.ds.so: SANE_SetupFileXfer2Get
dlls/sane.ds/sane.ds.so: SANE_SetupFileXfer2GetDefault
dlls/sane.ds/sane.ds.so: SANE_SetupFileXfer2Reset
dlls/sane.ds/sane.ds.so: SANE_SetupFileXfer2Set
dlls/secur32/secur32.dll.so: SECUR32_initNegotiateSP
dlls/secur32/secur32.dll.so: SECUR32_strdupW
dlls/setupapi/setupapi.dll.so: PARSER_string_substW
dlls/setupapi/setupapi.dll.so: VcpEnumFiles
dlls/setupapi/setupapi.dll.so: VcpFlush16
dlls/setupapi/setupapi.dll.so: vsmStringCompare16
dlls/setupapi/setupapi.dll.so: vsmStringFind16
dlls/shell32/shell32.dll.so: HCR_GetDefaultIconFromGUIDW
dlls/shell32/shell32.dll.so: ILGetDisplayNameExA
dlls/shell32/shell32.dll.so: _ILGetSTextPointer
dlls/shell32/shell32.dll.so: _ILGetTextPointerW
dlls/shell32/shell32.dll.so: RenderFILECONTENTS
dlls/shell32/shell32.dll.so: RenderFILEDESCRIPTOR
dlls/shell32/shell32.dll.so: RenderPREFEREDDROPEFFECT
dlls/shell32/shell32.dll.so: RenderSHELLIDLISTOFFSET
dlls/shell32/shell32.dll.so: SHILCreateFromPathA
dlls/shell32/shell32.dll.so: TRASH_DisposeElement
dlls/shell32/shell32.dll.so: XDG_GetPath
dlls/user32/user32.dll.so: EditWndProcW
dlls/user32/user32.dll.so: LookupIconIdFromDirectory16
dlls/uxtheme/uxtheme.dll.so: UXINI_ResetINI
dlls/w32skrnl/w32skrnl.dll.so: _GetThunkBuff
dlls/winealsa.drv/winealsa.drv.so: ALSA_PeekRingMessage
dlls/winealsa.drv/winealsa.drv.so: wodSetVolume
dlls/winedos/winedos.dll.so: DOSDEV_Console
dlls/winedos/winedos.dll.so: DOSDEV_FindCharDevice
dlls/winedos/winedos.dll.so: DOSDEV_IoctlRead
dlls/winedos/winedos.dll.so: DOSDEV_IoctlWrite
dlls/winedos/winedos.dll.so: DOSDEV_Peek
dlls/winedos/winedos.dll.so: DOSDEV_Read
dlls/winedos/winedos.dll.so: DOSDEV_Write
dlls/winedos/winedos.dll.so: DOSVM_AllocCodeUMB
dlls/winedos/winedos.dll.so: DOSVM_AllocUMB
dlls/winedos/winedos.dll.so: DPMI_FreeInternalRMCB
dlls/winedos/winedos.dll.so: VGA_SetQuadPalette
dlls/winedos/winedos.dll.so: VGA_SetTextAttribute
dlls/wineps.drv/wineps.drv.so: PSDRV_CmpColor
dlls/wineps.drv/wineps.drv.so: PSDRV_WriteArrayGet
dlls/wineps.drv/wineps.drv.so: PSDRV_WriteInitClip
dlls/wineps.drv/wineps.drv.so: PSDRV_WriteRRectangle
dlls/winex11.drv/winex11.drv.so: X11DRV_get_client_window
dlls/winex11.drv/winex11.drv.so: X11DRV_SetupGCForPen
dlls/winex11.drv/winex11.drv.so: X11DRV_window_to_X_rect
dlls/winex11.drv/winex11.drv.so: X11DRV_XF86VM_SetExclusiveMode
dlls/winex11.drv/winex11.drv.so: X11DRV_XRandR_Cleanup
dlls/winhttp/winhttp.dll.so: netconn_set_timeout
dlls/wininet/wininet.dll.so: HTTP_FinishedReading
dlls/wininet/wininet.dll.so: HTTP_GetHeader
dlls/wininet/wininet.dll.so: HTTP_HttpOpenRequestW
dlls/wininet/wininet.dll.so: HTTP_HttpSendRequestW
dlls/winmm/winmm.dll.so: MCI_DefYieldProc
dlls/winmm/winmm.dll.so: MCI_GetDriverFromString
dlls/winmm/winmm.dll.so: MCI_SendCommandFrom16
dlls/winmm/winmm.dll.so: MCI_SendCommandFrom32
dlls/winmm/winmm.dll.so: MCI_WriteString
dlls/wintrust/wintrust.dll.so: CRYPT_AsnEncodeInt
dlls/wintrust/wintrust.dll.so: WINTRUST_ReAlloc
dlls/wnaspi32/wnaspi32.dll.so: ASPI_SendASPICommand
dlls/wnaspi32/wnaspi32.dll.so: SCSI_GetDeviceName
dlls/wuapi/wuapi.dll.so: AutomaticUpdates_create
programs/cmd/cmd.exe.so: handleExpansion
programs/cmd/cmd.exe.so: WCMD_addCommand
programs/cmd/cmd.exe.so: WCMD_ask_confirm
programs/cmd/cmd.exe.so: WCMD_dir_sort
programs/cmd/cmd.exe.so: WCMD_filesize64
programs/cmd/cmd.exe.so: WCMD_opt_s_strip_quotes
programs/cmd/cmd.exe.so: WCMD_parse
programs/cmd/cmd.exe.so: WCMD_show_prompt
programs/cmd/cmd.exe.so: WCMD_strrev
programs/cmd/cmd.exe.so: WCMD_strtrim_trailing_spaces
programs/oleview/oleview.exe.so: AddToStrW
programs/oleview/oleview.exe.so: AddToTLDataStrW
programs/oleview/oleview.exe.so: AddToTLDataStrWithTabsW
programs/oleview/oleview.exe.so: CreateInstOnProc
programs/oleview/oleview.exe.so: DetailsProc
programs/oleview/oleview.exe.so: InterfaceViewerProc
programs/oleview/oleview.exe.so: PaneProc
programs/oleview/oleview.exe.so: SysConfProc
programs/oleview/oleview.exe.so: TreeProc
programs/oleview/oleview.exe.so: TypeLibProc
programs/oleview/oleview.exe.so: WndProc
programs/progman/progman.exe.so: DIALOG_Symbol
programs/regedit/regedit.exe.so: GetMultiByteStringN
programs/regedit/regedit.exe.so: GetRootKeyName
programs/regedit/regedit.exe.so: GetWideStringN
programs/regedit/regedit.exe.so: HexEdit_Unregister
programs/regedit/regedit.exe.so: processRegLinesA
programs/regedit/regedit.exe.so: processRegLinesW
programs/taskmgr/taskmgr.exe.so: Draw3dRect
programs/taskmgr/taskmgr.exe.so: Draw3dRect2
programs/taskmgr/taskmgr.exe.so: FillSolidRect2
programs/taskmgr/taskmgr.exe.so: GraphCtrl_DrawPoint
programs/taskmgr/taskmgr.exe.so: GraphCtrl_InvalidateCtrl
programs/taskmgr/taskmgr.exe.so: GraphCtrl_Paint
programs/taskmgr/taskmgr.exe.so: GraphCtrl_Resize
programs/taskmgr/taskmgr.exe.so: TrayIcon_GetProcessorUsageIcon
programs/taskmgr/taskmgr.exe.so: UpdateApplicationListControlViewSetting
programs/view/view.exe.so: FileIsPlaceable
programs/view/view.exe.so: GetPlaceableMetaFile
programs/winecfg/winecfg.exe.so: enumerate_valuesW
programs/wineconsole/wineconsole.exe.so: WCUSER_AreFontsEqual
programs/wineconsole/wineconsole.exe.so: WINECON_FetchCells
programs/wineconsole/wineconsole.exe.so: WINECON_GetHistoryMode
programs/wineconsole/wineconsole.exe.so: WINECON_SetHistoryMode
programs/wineconsole/wineconsole.exe.so: WINECON_SetHistorySize
programs/winedbg/winedbg.exe.so: be_cpu_build_addr
programs/winedbg/winedbg.exe.so: be_cpu_linearize
programs/winedbg/winedbg.exe.so: dbg_alloc
programs/winedbg/winedbg.exe.so: dbg__create_buffer
programs/winedbg/winedbg.exe.so: dbg__delete_buffer
programs/winedbg/winedbg.exe.so: dbg__flush_buffer
programs/winedbg/winedbg.exe.so: dbg_free
programs/winedbg/winedbg.exe.so: dbg_get_debug
programs/winedbg/winedbg.exe.so: dbg_get_in
programs/winedbg/winedbg.exe.so: dbg_get_leng
programs/winedbg/winedbg.exe.so: dbg_get_lineno
programs/winedbg/winedbg.exe.so: dbg_get_out
programs/winedbg/winedbg.exe.so: dbg_get_text
programs/winedbg/winedbg.exe.so: dbg_lex_destroy
programs/winedbg/winedbg.exe.so: dbg_outputA
programs/winedbg/winedbg.exe.so: dbg_parse
programs/winedbg/winedbg.exe.so: dbg_pop_buffer_state
programs/winedbg/winedbg.exe.so: dbg_push_buffer_state
programs/winedbg/winedbg.exe.so: dbg_realloc
programs/winedbg/winedbg.exe.so: dbg_restart
programs/winedbg/winedbg.exe.so: dbg__scan_buffer
programs/winedbg/winedbg.exe.so: dbg__scan_bytes
programs/winedbg/winedbg.exe.so: dbg__scan_string
programs/winedbg/winedbg.exe.so: dbg_set_debug
programs/winedbg/winedbg.exe.so: dbg_set_in
programs/winedbg/winedbg.exe.so: dbg_set_lineno
programs/winedbg/winedbg.exe.so: dbg_set_out
programs/winedbg/winedbg.exe.so: dbg__switch_to_buffer
programs/winedbg/winedbg.exe.so: dbg_wrap
programs/winedbg/winedbg.exe.so: expr_alloc_uconstant
programs/winedbg/winedbg.exe.so: lexeme_alloc
programs/winedbg/winedbg.exe.so: parser
programs/winedbg/winedbg.exe.so: validate_file
programs/winemine/winemine.exe.so: AboutDlgProc
programs/winemine/winemine.exe.so: AddFlag
programs/winemine/winemine.exe.so: CompleteBox
programs/winemine/winemine.exe.so: CompleteBoxes
programs/winemine/winemine.exe.so: CreateBoard
programs/winemine/winemine.exe.so: DestroyBoard
programs/winemine/winemine.exe.so: DrawBoard
programs/winemine/winemine.exe.so: DrawFace
programs/winemine/winemine.exe.so: DrawLeds
programs/winemine/winemine.exe.so: DrawMine
programs/winemine/winemine.exe.so: DrawMines
programs/winemine/winemine.exe.so: InitBoard
programs/winemine/winemine.exe.so: LoadBoard
programs/winemine/winemine.exe.so: MainProc
programs/winemine/winemine.exe.so: PlaceMines
programs/winemine/winemine.exe.so: PressBox
programs/winemine/winemine.exe.so: PressBoxes
programs/winemine/winemine.exe.so: SaveBoard
programs/winemine/winemine.exe.so: SetDifficulty
programs/winemine/winemine.exe.so: TestBoard
programs/winemine/winemine.exe.so: TestFace
programs/winemine/winemine.exe.so: TestMines
programs/winemine/winemine.exe.so: UnpressBox
programs/winemine/winemine.exe.so: UnpressBoxes
programs/winhlp32/winhlp32.exe.so: HLPFILE_BPTreeSearch
programs/winhlp32/winhlp32.exe.so: HLPFILE_Contents
programs/winhlp32/winhlp32.exe.so: HLPFILE_HalfPointsToTwips
programs/winhlp32/winhlp32.exe.so: MACRO_AddAccelerator
programs/winhlp32/winhlp32.exe.so: MACRO_ALink
programs/winhlp32/winhlp32.exe.so: MACRO_AppendItem
programs/winhlp32/winhlp32.exe.so: MACRO_Back
programs/winhlp32/winhlp32.exe.so: MACRO_BackFlush
programs/winhlp32/winhlp32.exe.so: MACRO_BookmarkMore
programs/winhlp32/winhlp32.exe.so: MACRO_BrowseButtons
programs/winhlp32/winhlp32.exe.so: MACRO_ChangeButtonBinding
programs/winhlp32/winhlp32.exe.so: MACRO_ChangeEnable
programs/winhlp32/winhlp32.exe.so: MACRO_ChangeItemBinding
programs/winhlp32/winhlp32.exe.so: MACRO_CheckItem
programs/winhlp32/winhlp32.exe.so: MACRO_CloseSecondarys
programs/winhlp32/winhlp32.exe.so: MACRO_CloseWindow
programs/winhlp32/winhlp32.exe.so: MACRO_Compare
programs/winhlp32/winhlp32.exe.so: MACRO_Contents
programs/winhlp32/winhlp32.exe.so: MACRO_ControlPanel
programs/winhlp32/winhlp32.exe.so: MACRO_CopyTopic
programs/winhlp32/winhlp32.exe.so: MACRO_DeleteItem
programs/winhlp32/winhlp32.exe.so: MACRO_DeleteMark
programs/winhlp32/winhlp32.exe.so: MACRO_DestroyButton
programs/winhlp32/winhlp32.exe.so: MACRO_DisableItem
programs/winhlp32/winhlp32.exe.so: MACRO_EnableButton
programs/winhlp32/winhlp32.exe.so: MACRO_EnableItem
programs/winhlp32/winhlp32.exe.so: MACRO_EndMPrint
programs/winhlp32/winhlp32.exe.so: MACRO_ExecFile
programs/winhlp32/winhlp32.exe.so: MACRO_ExecProgram
programs/winhlp32/winhlp32.exe.so: MACRO_ExtAbleItem
programs/winhlp32/winhlp32.exe.so: MACRO_ExtInsertItem
programs/winhlp32/winhlp32.exe.so: MACRO_ExtInsertMenu
programs/winhlp32/winhlp32.exe.so: MACRO_FileExist
programs/winhlp32/winhlp32.exe.so: MACRO_Find
programs/winhlp32/winhlp32.exe.so: MACRO_Finder
programs/winhlp32/winhlp32.exe.so: MACRO_FloatingMenu
programs/winhlp32/winhlp32.exe.so: MACRO_Flush
programs/winhlp32/winhlp32.exe.so: MACRO_FocusWindow
programs/winhlp32/winhlp32.exe.so: MACRO_Generate
programs/winhlp32/winhlp32.exe.so: MACRO_GotoMark
programs/winhlp32/winhlp32.exe.so: MACRO_IfThen
programs/winhlp32/winhlp32.exe.so: MACRO_IfThenElse
programs/winhlp32/winhlp32.exe.so: MACRO_InitMPrint
programs/winhlp32/winhlp32.exe.so: MACRO_InsertItem
programs/winhlp32/winhlp32.exe.so: MACRO_InsertMenu
programs/winhlp32/winhlp32.exe.so: MACRO_IsBook
programs/winhlp32/winhlp32.exe.so: MACRO_IsMark
programs/winhlp32/winhlp32.exe.so: MACRO_IsNotMark
programs/winhlp32/winhlp32.exe.so: MACRO_JumpHelpOn
programs/winhlp32/winhlp32.exe.so: MACRO_JumpID
programs/winhlp32/winhlp32.exe.so: MACRO_JumpKeyword
programs/winhlp32/winhlp32.exe.so: MACRO_KLink
programs/winhlp32/winhlp32.exe.so: MACRO_Menu
programs/winhlp32/winhlp32.exe.so: MACRO_MPrintHash
programs/winhlp32/winhlp32.exe.so: MACRO_MPrintID
programs/winhlp32/winhlp32.exe.so: MACRO_Next
programs/winhlp32/winhlp32.exe.so: MACRO_NoShow
programs/winhlp32/winhlp32.exe.so: MACRO_PopupHash
programs/winhlp32/winhlp32.exe.so: MACRO_PopupId
programs/winhlp32/winhlp32.exe.so: MACRO_PositionWindow
programs/winhlp32/winhlp32.exe.so: MACRO_Prev
programs/winhlp32/winhlp32.exe.so: MACRO_RegisterRoutine
programs/winhlp32/winhlp32.exe.so: MACRO_RemoveAccelerator
programs/winhlp32/winhlp32.exe.so: MACRO_ResetMenu
programs/winhlp32/winhlp32.exe.so: MACRO_SaveMark
programs/winhlp32/winhlp32.exe.so: MACRO_Search
programs/winhlp32/winhlp32.exe.so: MACRO_SetHelpOnFile
programs/winhlp32/winhlp32.exe.so: MACRO_SetPopupColor
programs/winhlp32/winhlp32.exe.so: MACRO_ShellExecute
programs/winhlp32/winhlp32.exe.so: MACRO_ShortCut
programs/winhlp32/winhlp32.exe.so: MACRO_TCard
programs/winhlp32/winhlp32.exe.so: MACRO_Test
programs/winhlp32/winhlp32.exe.so: MACRO_TestALink
programs/winhlp32/winhlp32.exe.so: MACRO_TestKLink
programs/winhlp32/winhlp32.exe.so: MACRO_UncheckItem
programs/winhlp32/winhlp32.exe.so: MACRO_UpdateWindow
programs/winhlp32/winhlp32.exe.so: WINHELP_IndexDlgProc
programs/winhlp32/winhlp32.exe.so: WINHELP_MessageBoxIDS_s
programs/winhlp32/winhlp32.exe.so: WINHELP_SearchDlgProc
programs/winhlp32/winhlp32.exe.so: yyalloc
programs/winhlp32/winhlp32.exe.so: yy_create_buffer
programs/winhlp32/winhlp32.exe.so: yy_delete_buffer
programs/winhlp32/winhlp32.exe.so: yy_flush_buffer
programs/winhlp32/winhlp32.exe.so: yyfree
programs/winhlp32/winhlp32.exe.so: yyget_debug
programs/winhlp32/winhlp32.exe.so: yyget_in
programs/winhlp32/winhlp32.exe.so: yyget_leng
programs/winhlp32/winhlp32.exe.so: yyget_lineno
programs/winhlp32/winhlp32.exe.so: yyget_out
programs/winhlp32/winhlp32.exe.so: yyget_text
programs/winhlp32/winhlp32.exe.so: yylex
programs/winhlp32/winhlp32.exe.so: yylex_destroy
programs/winhlp32/winhlp32.exe.so: yypop_buffer_state
programs/winhlp32/winhlp32.exe.so: yypush_buffer_state
programs/winhlp32/winhlp32.exe.so: yyrealloc
programs/winhlp32/winhlp32.exe.so: yyrestart
programs/winhlp32/winhlp32.exe.so: yy_scan_buffer
programs/winhlp32/winhlp32.exe.so: yy_scan_bytes
programs/winhlp32/winhlp32.exe.so: yy_scan_string
programs/winhlp32/winhlp32.exe.so: yyset_debug
programs/winhlp32/winhlp32.exe.so: yyset_in
programs/winhlp32/winhlp32.exe.so: yyset_lineno
programs/winhlp32/winhlp32.exe.so: yyset_out
programs/winhlp32/winhlp32.exe.so: yy_switch_to_buffer
programs/winhlp32/winhlp32.exe.so: yywrap
    

-- 
Francois Gouget <fgouget at free.fr>              http://fgouget.free.fr/
        War doesn't determine who's right.  War determines who's left.
-------------- next part --------------
#!/usr/bin/perl -w
use strict;

my $name0=$0;
$name0 =~ s%^.*/%%;


my $IDENTIFIER="[a-zA-Z_][a-zA-Z0-9_]*";
my $MANGLEDIDENT="[a-zA-Z0-9_?@\$]+";
my $SPECIDENT="$IDENTIFIER(?:\.$MANGLEDIDENT)*";
my $SPECOPT="-[a-zA-Z0-9_=,]+\\s+";


### List of linefeed issues to ignore
my %lf_blacklist=(
    "dlls/comctl32/rebar.c" => {"\"band # \%u: xHeader=\%u\"" => 1},
    "dlls/d3d8/device.c" => {"\"Searching for declaration for fvf \%08x... \"" => 1},
    "dlls/d3d9/device.c" => {"\"Searching for declaration for fvf \%08x... \"" => 1},
    "dlls/ddraw/ddraw.c" => {"\"Searching for declaration for fvf \%08x... \"" => 1},
    "dlls/ddraw/utils.c" => {"\"\%s \"" => 1,
                             "\" R \"" => 1,
                             "\" - \"" => 1},
    "dlls/dinput/effect_linuxinput.c" => {"\"\%[ds] \"" => 1},
    "dlls/dinput/mouse.c" => {"\"\\(X: \%d Y: \%d Z: \%d\"" => 1},
    "dlls/dsound/dsound.c" => {"\"\%s \",flags\\[i\\]\\.name" => 1},
    "dlls/gdi32/freetype.c" => {"\"\\\\t\%s\\\\t\%08x\"" => 1},
    "dlls/ntdll/loader.c" => {"\"No implementation for \%s\\.%[ds]\"" => 1},
    "dlls/ntdll/rtl.c" => {"\"\%s\%x: \%s\"" => 1},
    "dlls/ntdll/time.c" => {"\"starting date isdst \%d, \%s\"" => 1,
                            "\"year_start: \%s\"" => 1,
                            "\"std: \%s\"" => 1,
                            "\"dlt gmtime: \%s\"" => 1,
                            "\"std gmtime: \%s\"" => 1},
    "dlls/ntdll/virtual.c" => {"\"View: \%p - \%p\"" => 1},
    "dlls/odbc32/proxyodbc.c" => {"\"returns: \%d \\\\t\"" => 1},
    "dlls/ole32/marshal.c" => {"\" MSHLFLAGS_TABLESTRONG\"" => 1},
    "dlls/oleaut32/tmarshal.c" => {"\"*\"" => 1},
    "dlls/oleaut32/typelib.c" => {"\"\%p->\\{\%s\%s\"" => 1},
    "dlls/oleaut32/varformat.c" => {"\"\%s0x%02x\"" => 1},
    "dlls/quartz/dsoundrender.c" => {"\"%02x \"" => 1},
    "dlls/quartz/videorenderer.c" => {"\"%02x \"" => 1},
    "dlls/rpcrt4/ndr_marshall.c" => {"\" RPC_FC_P_ALLOCALLNODES\"" => 1},
    "dlls/rpcrt4/ndr_stubless.c" => {"\" MustSize\"" => 1,
                                    "\" ServerMustSize\"" => 1},
    "dlls/rpcrt4/rpc_binding.c" => {"\"SecurityQos { Version=\%ld, Capabilties=0x\%lx, IdentityTracking=\%ld, ImpersonationLevel=\%ld\"" => 1},
    "dlls/secur32/dispatcher.c" => {"\"\%s \"" => 1},
    "dlls/secur32/schannel.c" => {"\"<\%d> \%s\"" => 1},
    "dlls/setupapi/parser.c" => {"\"\%p/\%p/\%d/\%d index \%d returning\"" => 1},
    "dlls/snmpapi/main.c" => {"\"\%u\"" => 1,
                              "\"String \"" => 1,
                              "\"IpAddress \"" => 1,
                              "\"Bits \"" => 1,
                              "\"Opaque \"" => 1,
                              "\"ObjectID \"" => 1},
    "dlls/user32/listbox.c" => {"\\[\%p\\]: settabstops \"" => 1},
    "dlls/user32/menu.c" => {"\"\%s\%s\"" => 1,
                             "\"\%s \"" => 1},
    "dlls/user32/painting.c" => {"\"\%p region \%p box \%s \"" => 1},
    "dlls/user32/scroll.c" => {"\"hwnd=\%p bar=\%d\"" => 1},
    "dlls/user32/tests/msg.c" => {"\"\%p after \%p, x \%d, y \%d, cx \%d, cy \%d flags \%08x \"" => 1},
    "dlls/usp10/usp10.c" => {"\"New_Script=\%d, eScript=\%d \"" => 1,
                             "\"Item \%d, Glyphs \%d \"" => 1},
    "dlls/version/info.c" => {"\"filetype=APP\"" => 1},
    "dlls/winecoreaudio.drv/midi.c" => {"\"\%02X \"" => 1},
    "dlls/wined3d/baseshader.c" => {"\"GL HW \\(\%u, \%u\\) : \%s\"" => 1,
                                    "\"dcl\"" => 1,
                                    "\"-\"" => 1,
                                    "\"_d8\"" => 1,
                                    "\"def c\%u = \%f, \%f, \%f, \%f\"" => 1,
                                    "\"%s\"" => 1},
    "dlls/wined3d/vertexbuffer.c" => {"\"[[]\%d[]]\"" => 1},
    "dlls/winex11.drv/dib.c" => {"\"%04x/%04lx \"" => 1},
    "dlls/winex11.drv/opengl.c" => {"\"\\('\%s'\\):\%\\*s\"" => 1,
                                    "\"\\*\"" => 1},
    "dlls/wininet/internet.c" => {"\" %s\"" => 1},
);


### List of stdcall equivalents
my @stdcall_seeds=qw(__stdcall);
my (%macros, $stdcall_re);


### List of 'static stdcall' functions to ignore
my %static_ignore=(
    "dlls/winedos/interrupts.c" => {DOSVM_Int20Handler => 1,
                                    DOSVM_Int5cHandler => 1},
    "dlls/winmm/message16.c" => {MMDRV_Aux_Callback => 1,
                                 MMDRV_Mixer_Callback => 1,
                                 MMDRV_MidiIn_Callback => 1,
                                 MMDRV_MidiOut_Callback => 1,
                                 MMDRV_WaveIn_Callback => 1,
                                 MMDRV_WaveOut_Callback => 1},
    "programs/cmdlgtst/cmdlgtst.c" => {dummyfnHook => 1},
);


### List of pointers for the NULL cast checker
my (%typedefs, %pointers);


### List of macros that are equal to 0
my %zeroes=(NULL => 1);


### List of undef-ed macros
my %undefs;


### List of exported functions to ignore
my %export_ignore=(
    "dlls/dpnet" => {debugstr_SP => 1},
    "dlls/kernel32" => {NE_DumpModule => 1,
                        NE_WalkModules => 1,
                        debug_handles => 1},
    "dlls/ntdll" => {__wine_process_init => 1,
                     __wine_spec_unimplemented_stub => 1},
    "dlls/ole32" => {STORAGE_dump_pps_entry => 1},
    "dlls/riched20" => {ME_DumpParaStyleToBuf => 1,
                        ME_DumpStyle => 1},
    "dlls/wined3d" => {debug_fixup_channel_source => 1,
                       debug_yuv_fixup => 1},
    "dlls/wineoss.drv" => {seqbuf_dump => 1},
);


### List of functions implemented or referenced from assembly code,
### sorted by directory
my %asm_functions;

### List of standard sublanguages
my %standard_sublangs=(
    SUBLANG_NEUTRAL => 1,
    SUBLANG_DEFAULT => 1,
    SUBLANG_SYS_DEFAULT => 1,
    SUBLANG_CUSTOM_DEFAULT => 1,
    SUBLANG_CUSTOM_UNSPECIFIED => 1,
    SUBLANG_UI_CUSTOM_DEFAULT => 1
);

### Lists of the languages default sublang and of those that have many sub
### languages
my (%lang_default, %lang_manysubs);

### List of languages known to have translations for non-default sub languages
my %lang_anysub=(
    LANG_ENGLISH => 1,
    LANG_PORTUGUESE => 1
);


my $verbose;
sub verbose(@)
{
    return print STDERR @_ if ($verbose);
}

my $debug;
sub debug(@)
{
    return print STDERR @_ if ($debug);
}

sub err(@)
{
    print STDERR "$name0:error: ", @_;
}

sub dirname($)
{
    my ($path)=@_;
    return "" if ($path !~ s!/[^/]+$!!);
    return $path;
}


my @file;
my $l;
my @chars;
my $len;
my $c;

sub skip_bracket();
sub skip_parent();
sub skip_string();

sub setup_line($)
{
    return 0 if ($l >= @file);

    $c=$_[0];
    $len=length($file[$l]);
    @chars=split //, $file[$l];
    debug("$l,$c: $file[$l]");
    return 1;
}

sub set_position($$)
{
    return 0 if ($l >= @file);

    $c=$_[0];
    $l=$_[1];
    $len=length($file[$l]);
    @chars=split //, $file[$l];
    debug("$l,$c: $file[$l]");
    return 1;
}

sub skip_bracket()
{
    while (1)
    {
        while ($c < $len)
        {
            debug("skip_bracket: $c -> '$chars[$c]'\n");
            if ($chars[$c] eq "]")
            {
                debug("skip_bracket returns 1\n");
                return 1;
            }
            elsif ($chars[$c] eq "\"")
            {
                $c++;
                skip_string();
            }
            elsif ($chars[$c] eq "(")
            {
                $c++;
                skip_parent();
            }
            elsif ($chars[$c] eq "[")
            {
                $c++;
                skip_bracket();
            }
            $c++;
        }
        $l++;
        return 0 if (!setup_line(0));
    }
    return 0;
}

sub skip_parent()
{
    while (1)
    {
        while ($c < $len)
        {
            debug("skip_parent: $c -> '$chars[$c]'\n");
            if ($chars[$c] eq ")")
            {
                debug("skip_parent returns 1\n");
                return 1;
            }
            elsif ($chars[$c] eq "\"")
            {
                $c++;
                skip_string();
            }
            elsif ($chars[$c] eq "(")
            {
                $c++;
                skip_parent();
            }
            elsif ($chars[$c] eq "[")
            {
                $c++;
                skip_bracket();
            }
            $c++;
        }
        $l++;
        return 0 if (!setup_line(0));
    }
    return 0;
}

sub skip_string()
{
    my $backslash;
    while (1)
    {
        while ($c < $len)
        {
            debug("skip_string: $c -> '$chars[$c]'\n");
            if ($chars[$c] eq "\"")
            {
                if (!$backslash)
                {
                    debug("skip_string returns 1\n");
                    return 1;
                }
                $backslash=undef;
            }
            elsif ($chars[$c] eq "\\")
            {
                $backslash=($backslash?undef:1);
            }
            else
            {
                $backslash=undef;
            }
            $c++;
        }
        $l++;
        return 0 if (!setup_line(0));
    }
    return 0;
}

sub skip_comment()
{
    my $star;
    while (1)
    {
        while ($c < $len)
        {
            debug("skip_comment: $c -> '$chars[$c]'\n");
            if ($chars[$c] eq "*")
            {
                $star=1;
            }
            elsif ($chars[$c] eq "/")
            {
                return 1 if ($star);
            }
            else
            {
                $star=0;
            }
            $c++;
        }
        $l++;
        return 0 if (!setup_line(0));
    }
    return 0;
}

sub skip_arg()
{
    while (1)
    {
        while ($c < $len)
        {
            debug("skip_arg: $c -> '$chars[$c]'\n");
            if ($chars[$c] eq ",")
            {
                debug("skip_arg returns 1\n");
                return 1;
            }
            elsif ($chars[$c] eq "\"")
            {
                $c++;
                skip_string();
            }
            elsif ($chars[$c] eq "(")
            {
                $c++;
                skip_parent();
            }
            elsif ($chars[$c] eq "[")
            {
                $c++;
                skip_bracket();
            }
            $c++;
        }
        $l++;
        return 0 if (!setup_line(0));
    }
    return 0;
}

sub get_quote()
{
    while (1)
    {
        while ($c < $len)
        {
            debug("get_quote: $c -> '$chars[$c]'\n");
            if ($chars[$c] eq "\"")
            {
                debug("get_quote returns 1\n");
                return 1;
            }
            elsif ($chars[$c] eq "\\")
            {
                return 0 if ($c+1==$len or $chars[$c+1] ne "\n");
            }
            elsif ($chars[$c] eq "/" and $c+1 < $len and $chars[$c+1] eq "*")
            {
                return 0 if (!skip_comment());
            }
            elsif ($chars[$c] !~ /(\s|\n)/)
            {
                return 0;
            }
            $c++;
        }
        $l++;
        return 0 if (!setup_line(0));
    }
    return 0;
}

sub get_comma()
{
    while (1)
    {
        while ($c < $len)
        {
            debug("get_comma: $c -> '$chars[$c]'\n");
            if ($chars[$c] eq ",")
            {
                debug("get_comma returns 1\n");
                return 1;
            }
            elsif ($chars[$c] eq "\\")
            {
                return 0 if ($c+1==$len or $chars[$c+1] ne "\n");
            }
            elsif ($chars[$c] !~ /(\s|\n|[a-zA-Z0-9\#])/)
            {
                return 0;
            }
            $c++;
        }
        $l++;
        return 0 if (!setup_line(0));
    }
    return 0;
}

my $lf_set_ignore;
sub fix_lf($$$$)
{
    my ($needs_lf, $heuristics, $arg, $pos)=@_;
    setup_line($pos);
    verbose("processing:",$l+1," ",substr($file[$l], $pos));

    # Locate the format string
    for (my $i=1; $i < $arg; $i++)
    {
        return undef if (!skip_arg());
        $c++;
    }
    return undef if (!get_quote());

    # See if this is a string of the form "xxx" #var "yyy"
    my ($quote_c, $quote_l);
    while ($c < $len)
    {
        last if ($chars[$c] ne "\"");
        $c++;
        return "" if (!skip_string());
        $quote_c=$c;
        $quote_l=$l;
        $c++;
        last if (get_comma());
    }
    set_position($quote_c, $quote_l);

    # Check and modify
    if ($needs_lf)
    {
        if ($c >= 2 and ($chars[$c-2] ne "\\" or $chars[$c-1] ne "n"))
        {
            my $start=substr($file[$l], 0, $c);
            verbose("  start=[$start]\n");
            if ($start =~ /\\r$/ or $start =~ /\"\s*$/)
            {
                return $file[$l];
            }
            elsif ($heuristics and
                   ($start =~ /(?:->|[=:,|{([])\s*$/ or
                    # For the dm* dlls
                    $start =~ /\": \%s chunk \(size = (?:0x%04x|0x%08X|\%d)\)$/ or
                    $start =~ /\": (?:LIST|RIFF) chunk of type \%s$/
                   ))
            {
                verbose("  matched=[$&]\n");
                $lf_set_ignore=1;
                return $file[$l];
            }
            else
            {
                $start=~s/\s*$/\\n/;
                return $start . substr($file[$l], $c);
            }
        }
        elsif ($c >= 3 and $chars[$c-3] eq " " and
               $chars[$c-2] eq "\\" and $chars[$c-1] eq "n")
        {
            my $space=$c-3;
            while ($space > 0 and $chars[$space] eq " ")
            {
                $space--;
            }
            return substr($file[$l], 0, $space+1) . substr($file[$l], $c-2);
        }
    }
    else
    {
        my $cut=$c;
        if ($cut >= 2 and $chars[$cut-2] eq "\\" and $chars[$cut-1] eq "n")
        {
            $cut-=2;
        }
        while ($cut > 0)
        {
            $cut--;
            last if ($chars[$cut] ne " ");
        }
        return substr($file[$l], 0, $cut+1) . substr($file[$l], $c);
    }
    return $file[$l];
}

sub collect($$)
{
    my ($rootdir, $filename) = @_;

    debug("***** Processing $filename\n");
    if (open(my $fh, "<", "$rootdir$filename"))
    {
        my $dir=dirname($filename);
        while (my $line=<$fh>)
        {
            if ($line =~ /^\s*#\s*define\s+($IDENTIFIER)\s+(0(?:x0+)?L?|\(\s*0(?:x0+)?L?\s*\))\s*(\/\*.*)?$/)
            {
                debug("zero $1\n");
                $macros{$1}=$2;
                $zeroes{$1}=1;
            }
            elsif ($line =~ /^\s*#\s*define\s+($IDENTIFIER)\s+([0-9]+L?|0x[0-9a-fA-F]+L?|\(\s*(?:[0-9]+L?|0x[0-9a-fA-F]+L?)\s*\))\s*(\/\*.*)?$/)
            {
                debug("macro $1=$2\n");
                $macros{$1}=$2;
            }
            elsif ($line =~ /^\s*#\s*define\s+($IDENTIFIER)\s+($IDENTIFIER)\s*(\/\*.*)?$/)
            {
                debug("macro $1=$2\n");
                $macros{$1}=$2;
            }
            elsif ($line =~ /^\s*typedef\s+($IDENTIFIER)\s+($IDENTIFIER)\s*[;,]/)
            {
                debug("typedef $1 $2\n");
                $typedefs{$2}=$1;
            }
            elsif ($line =~ /^\s*typedef\s+[^;,]*\*\s*($IDENTIFIER)\s*[;,]/)
            {
                debug("pointer $1: $line");
                $pointers{$1}=1;
            }
            elsif ($line =~ /^\s*DECLARE_HANDLE\(($IDENTIFIER)\)\s*;/)
            {
                debug("handle $1\n");
                $pointers{$1}=1;
            }
            elsif ($line =~ /^\s*#\s*undef\s+($IDENTIFIER)\s*(\/\*.*)?$/ and
                   $1 ne "YYERROR_VERBOSE")
            {
                debug("undef $1\n");
                $undefs{$1}=1;
            }
            elsif ($line =~ /^\s*__ASM_GLOBAL_FUNC\s*\(\s*($IDENTIFIER)\s*,/)
            {
                my $function=$1;
                $asm_functions{$dir}->{$function}=1;
            }
            elsif ($line =~ /^\s*DEFINE_REGS_ENTRYPOINT\s*\(\s*($IDENTIFIER)\s*,/)
            {
                my $function=$1;
                $asm_functions{$dir}->{$function}=1;
                $asm_functions{$dir}->{"__regs_$function"}=1;
            }
            elsif ($line =~ /^\s*DEFINE_(?:FASTCALL[12]|SETJMP)_ENTRYPOINT\s*\(\s*($IDENTIFIER)\s*\)/)
            {
                my $function="__regs_$1";
                $asm_functions{$dir}->{$function}=1;
            }
            elsif ($line =~ /^\s*DEFINE_THISCALL_WRAPPER\s*\(\s*($IDENTIFIER)\s*\)/)
            {
                my $function=$1;
                $asm_functions{$dir}->{$function}=1;
                $asm_functions{$dir}->{"__thiscall_$function"}=1;
            }
            elsif ($line =~ /__ASM_NAME\(\s*\"($IDENTIFIER)\"\s*\)/)
            {
                my $function=$1;
                $asm_functions{$dir}->{$function}=1;
            }
        }
        close($fh);
    }
    else
    {
        err("unable to open '$filename' for reading: $!\n");
        exit 1;
    }
}

sub fix_c_file($$)
{
    my ($rootdir, $filename) = @_;

    debug("***** Processing $filename\n");
    if (open(my $fh, "<", "$rootdir$filename"))
    {
        @file = <$fh>;
        close($fh);
    }
    else
    {
        err("unable to open '$filename' for reading: $!\n");
        exit 1;
    }

    # Initialize the linefeed checker
    my $lf_blacklist_extra;
    if ($lf_blacklist{$filename})
    {
        $lf_blacklist_extra=join("|", keys %{$lf_blacklist{$filename}});
    }
    my $lf_ignore=0;

    # Initialize the static stdcall checker
    my (%st_statics, %st_refs);
    my $st_prefix="";

    my $modified;
    $l=0;
    while ($l < @file)
    {
        # Ifdef checker
        if ($file[$l] =~ /^\s*#\s*if\s+($IDENTIFIER)\s*(\/\*.*)?$/ and
            $undefs{$1})
        {
            print "$filename:",$l+1,": $1 might be undefined\n";
        }

        # Zero-flag checker
        if ($file[$l] =~ /[^&]&[^&]/)
        {
            my $line=$file[$l];
            debug("zflags: $line");
            my %warned;
            while ($line =~ s/([^&,({= ]\s*[&]\s*)($IDENTIFIER)\b/$1 1/)
            {
                debug("zflags1: $2 -> $line");
                if ($zeroes{$2} and !$warned{$2})
                {
                    print "$filename:",$l+1,": '&' with zero-flag $2\n";
                    $warned{$1}=1;
                }
            }
            while ($line =~ s/\b($IDENTIFIER)(\s*&[^&])/1 $2/)
            {
                debug("zflags2: $1 -> $line");
                if ($zeroes{$1} and !$warned{$1})
                {
                    print "$filename:",$l+1,": '&' with zero-flag $1\n";
                    $warned{$1}=1;
                }
            }
            if (%warned)
            {
                $line=$file[$l];
                $line =~ s/^\s*//;
                print "    $line";
            }
        }

        # Static stdcall checker
        if ($file[$l] =~ /^\s*static(?:\s+$IDENTIFIER\s*\**)+\s+(?:$stdcall_re)\s+($IDENTIFIER)\s*(?:\(|$)/)
        {
            debug("$filename: static $1\n");
            push @{$st_statics{$1}}, $l;
            $st_prefix="";
        }
        elsif ("$st_prefix $file[$l]" =~ /^\s*static(?:\s+$IDENTIFIER+\s*\**)+\s+(?:$stdcall_re)\s+($IDENTIFIER)\s*(?:\(|$)/)
        {
            debug("$filename: static $1\n");
            push @{$st_statics{$1}}, $l;
            $st_prefix="";
        }
        elsif ($file[$l] =~ /^\s*static(?:\s+$IDENTIFIER\s*\**)*\s*$/)
        {
            $st_prefix=$file[$l];
            chomp $st_prefix;
        }
        else
        {
            my $s=$file[$l];
            while ($s =~ s/(^|[\{\(\)&=?:,])\s*($IDENTIFIER)\s*(?![\(a-zA-Z0-9_])/$1/)
            {
                #debug("$filename: & $2\n");
                $st_refs{$2}=1;
            }
            $st_prefix="";
        }

        # NULL cast checker
        # Ignore the '#define foo(xxx) NULL' lines
        if ($file[$l] !~ /^\s*#/)
        {
            my $cast=$file[$l];
            $cast =~ s/\(\s*$IDENTIFIER(?:\s+$IDENTIFIER|\s*\*)*\s*\*\s*\)\s*(?:NULL|0L?)(?!\w|[0-9])/NULL/g;
            if ($cast =~ /\(\s*($IDENTIFIER)\s*\)\s*(?:NULL|0L?)(?!\w|[0-9])/)
            {
                # There may be others but if that happens
                # they will be removed manually
                $cast =~ s/\(\s*$1\s*\)\s*(?:NULL|0L?)(?!\w|[0-9]|\s*\)\s*->)/NULL/g if ($pointers{$1});
            }
            if ($cast ne $file[$l])
            {
                $file[$l]=$cast;
                $modified=1;
            }
        }

        # Linefeed processing
        # This may read more lines so this should be done last
        $lf_set_ignore=0;
        my $fixed;
        if ($file[$l] =~ /^(.*?\bok\s*\()/)
        {
            $fixed=fix_lf(1, 0, 2, length($1));
        }
        elsif ($file[$l] =~ /^(.*?\btrace\s*\()/)
        {
            $fixed=fix_lf(1, 1, 1, length($1));
        }
        elsif ($file[$l] =~ /^(.*?\b(?:WINE_)?(?:ERR|FIXME|TRACE|WARN)(?:_\s*\(\w+\))?\s*\()/)
        {
            $fixed=fix_lf(1, 1, 1, length($1));
        }
        elsif ($file[$l] =~ /^(.*?\b(?:WINE_)?(?:ERR|FIXME|TRACE|WARN)_\s*\(\s*[a-z]+\s*\)\s*\()/)
        {
            $fixed=fix_lf(1, 1, 1, length($1));
        }
        elsif ($file[$l] =~ /^(.*?\bshader_addline\s*\()/)
        {
            # This is a wined3d trace function
            $fixed=fix_lf(1, 1, 2, length($1));
        }
        elsif ($file[$l] =~ /^(.*?\b(?:mcy_|parser_|xyy)?(?:chat|warning)\s*\()/)
        {
            # Error and warning reporting functions used in tools/
            $fixed=fix_lf(1, 0, 1, length($1));
        }
        elsif ($file[$l] =~ /^(.*?\berror\s*\()/)
        {
            # Error reporting functions used in tools/
            $fixed=fix_lf(1, 0, 1, length($1));
        }
        elsif ($file[$l] =~ /^(.*?\bparser_error\s*\()/)
        {
            # Error reporting function used in tools/ that must not have
            # a trailing '\n'
            $fixed=fix_lf(0, 0, 1, length($1));
        }
        elsif ($file[$l] =~ /^(.*?\berror_loc\s*\()/)
        {
            # Error reporting function used in tools/widl/
            $fixed=fix_lf(1, 0, 1, length($1));
        }
        elsif ($file[$l] =~ /^(.*?\b(?:error|warning)_loc_info\s*\()/)
        {
            # Error and warning reporting functions used in tools/widl/
            $fixed=fix_lf(1, 0, 2, length($1));
        }
        elsif ($file[$l] =~ /^(.*?\binternal_error\s*\()/)
        {
            # Error reporting function used in tools/wrc/
            $fixed=fix_lf(1, 0, 3, length($1));
        }
        elsif ($lf_ignore and $file[$l] =~ /^[{}]/)
        {
            verbose("$filename:",$l+1,": resuming checks\n");
            $lf_ignore=0;
        }

        if (defined $fixed)
        {
            # fix_lf() successfully checked this line
            if (!$lf_ignore and !$lf_set_ignore and
                $fixed ne $file[$l] and
                $lf_blacklist_extra and $file[$l] =~ m!$lf_blacklist_extra!)
            {
                # Mark this blacklist entry as used
                foreach my $re (keys %{$lf_blacklist{$filename}})
                {
                    if ($file[$l] =~ /$re/)
                    {
                        delete $lf_blacklist{$filename}->{$re};
                        verbose("$filename:",$l+1,": matched $re\n");
                        last;
                    }
                }
                $lf_set_ignore=1;
            }

            if ($lf_ignore)
            {
                if (!$lf_set_ignore and $fixed eq $file[$l])
                {
                    # We found a trace that looks ok so resume the checks
                    my $line=$file[$l];
                    $line =~ s/^\s*//;
                    verbose("$filename:",$l+1,": resuming checks due to: $line");
                    $lf_ignore=0;
                }
            }
            else
            {
                if ($lf_set_ignore)
                {
                    my $line=$file[$l];
                    $line =~ s/^\s*//;
                    verbose("$filename:",$l+1,": ignoring further errors due to: $line");
                    $lf_ignore=1;
                }
                elsif ($fixed ne $file[$l])
                {
                    $file[$l]=$fixed;
                    $modified=1;
                    $fixed =~ s/^\s*//;
                    verbose("$filename:",$l+1,": fixed $fixed");
                }
            }
        }

        $l++;
    }
    if ($modified)
    {
        if (open(my $fh, ">", "$rootdir$filename"))
        {
            print $fh @file;
            close($fh);
        }
        else
        {
            err("unable to open '$filename' for writing: $!\n");
        }
    }

    # Check for unused linefeed blacklist entries
    if ($lf_blacklist{$filename})
    {
        foreach my $re (keys %{$lf_blacklist{$filename}})
        {
            print STDERR "$filename: unused linefeed blacklist: $re\n";
        }
    }
    delete $lf_blacklist{$filename};

    # Static stdcall checker
    foreach my $func (sort { $st_statics{$a}->[0] <=> $st_statics{$b}->[0] } keys %st_statics)
    {
        if (!$st_refs{$func})
        {
            if ($static_ignore{$filename}->{$func})
            {
                verbose("$filename: ignored static stdcall $func\n");
                delete $static_ignore{$filename}->{$func};
            }
            else
            {
                print "***** $filename ", join(" ", @{$st_statics{$func}}), "\n";
                $st_prefix="";
                foreach my $line (@file)
                {
                    if ($line =~ /\b$func\b/)
                    {
                        print "  $st_prefix $line";
                        $st_prefix="";
                    }
                    elsif ($line =~ /^\s*static(?:\s+$IDENTIFIER\s*\**)*\s*$/)
                    {
                        $st_prefix=$line;
                        chomp $st_prefix;
                    }
                    else
                    {
                        $st_prefix="";
                    }
                }
                print "\n";
            }
        }
    }
    foreach my $func (keys %{$static_ignore{$filename}})
    {
        print "$filename:$func not used\n";
    }
    delete $static_ignore{$filename};
}

sub fix_rc_file($$)
{
    my ($rootdir, $filename) = @_;

    debug("***** Processing $filename\n");
    if (open(my $fh, "<", "$rootdir$filename"))
    {
        @file = <$fh>;
        close($fh);
    }
    else
    {
        err("unable to open '$filename' for reading: $!\n");
        exit 1;
    }

    my $modified;
    $l=0;
    while ($l < @file)
    {
        my $line=$file[$l];
        # Fix extraneous spaces in '...'
        $line =~ s/\.(?: ?\.){2-5}/.../g;
        if ($filename =~ m!Si\.rc$!)
        {
            # Slovenian requires a space before '...'
            $line =~ s/([^ [])\.{3}/$1 .../g;
        }
        else
        {
            # Other languages say there should be no space before '...'
            # Except English where it's a bit ambiguous but where there
            # usually is no space in computer programs
            $line =~ s/([^,*]) *\.{3}/$1.../g;
        }

        # Remove spaces before '\n'
        $line =~ s/ +\\n/\\n/g;

        # Fix SUBLANGs
        if ($line !~ /^\s*#/ and
            $line =~ /\b(LANG_[A-Z]+)\s*,\s*(SUBLANG_[A-Z]+)\b/)
        {
            my ($lang, $sublang)=($1, $2);
            if ($lang eq "LANG_NEUTRAL")
            {
                if ($sublang ne "SUBLANG_NEUTRAL")
                {
                    print "$filename:",$l+1,": expected LANG_NEUTRAL, SUBLANG_NEUTRAL for language-independent resource\n";
                }
            }
            elsif (!$standard_sublangs{$sublang} and
                $sublang =~ /^SUB(LANG_[A-Z]+)(?:_|$)/ and $1 ne $lang)
            {
                print "$filename:",$l+1,": $sublang does not match $lang\n";
            }
            elsif (!exists $lang_default{$lang})
            {
                print "$filename:",$l+1,": unknown language $lang\n";
            }
            elsif ($lang eq "LANG_RUSSIAN")
            {
                # FIXME: Say nothing for now until the SUBLANG_RUSSIAN_MOLDAVIA
                # situation is resolved
            }
            elsif ($lang eq "LANG_GERMAN" and $sublang eq "SUBLANG_DEFAULT" and
                   $filename =~ m!kernel32/tests/resource\.rc$!)
            {
                # This is a test resource, presumably the SUBLANG_DEFAULT
                # is important
                # FIXME: Though maybe not
            }
            elsif (!$lang_manysubs{$lang})
            {
                # There is only one sublanguage
                if ($lang_default{$lang} eq $sublang and $sublang ne "SUBLANG_DEFAULT")
                {
                    # So it should be specified with SUBLANG_DEFAULT
                    $line =~ s/\b$lang\s*,\s*$sublang\b/$lang, SUBLANG_DEFAULT/;
                }
            }
            elsif ($lang_anysub{$lang})
            {
                # This language has many sublanguages, and sublanguage-specific
                # translations
                if ($lang eq "LANG_ENGLISH")
                {
                    # FIXME: Leave LANGUAGE_ENGLISH, SUBLANG_DEFAULT alone
                    # for now
                }
                elsif ($sublang eq "SUBLANG_DEFAULT")
                {
                    # It's better to use the explicit name for the default
                    # sublanguage: it's clearer for the next translator.
                    $line =~ s/\b$lang\s*,\s*SUBLANG_DEFAULT\b/$lang, $lang_default{$lang}/;
                }
            }
            else
            {
                # Although this language has many sublanguages, we believe
                # that all the current translations are neutral.
                if ($sublang eq "SUBLANG_DEFAULT")
                {
                    $line =~ s/\b$lang\s*,\s*SUBLANG_DEFAULT\b/$lang, SUBLANG_NEUTRAL/;
                }
                elsif ($sublang eq $lang_default{$lang})
                {
                    $line =~ s/\b$lang\s*,\s*$lang_default{$lang}\b/$lang, SUBLANG_NEUTRAL/;
                }
                elsif ($sublang ne "SUBLANG_NEUTRAL")
                {
                    # Warn for non-neutral, non-default translations.
                    # Maybe we finally have per-sublanguage translations?
                    print "$filename:",$l+1,": $lang has an unexpected non neutral translation: $sublang\n";
                }
            }


        }
        if ($line ne $file[$l])
        {
            verbose("$filename:",$l+1,": fixed $line");
            $file[$l]=$line;
            $modified=1;
        }

        $l++;
    }

    if ($modified)
    {
        if (open(my $fh, ">", "$rootdir$filename"))
        {
            print $fh @file;
            close($fh);
        }
        else
        {
            err("unable to open '$filename' for writing: $!\n");
        }
    }
}

sub fix_so($$$$)
{
    my ($rootdir, $so_file, $spec_files, $obj_files)=@_;
    return if (!defined $so_file or !@$obj_files);

    my ($is_exe, $is_test);
    $is_exe=1 if ($so_file =~ /\.exe\.so$/);
    $is_test=1 if ($so_file =~ /_test\.exe\.so$/);
    if (!@$spec_files and !$is_exe)
    {
        # This is not a Wine dll or exe so we have no idea
        # what should or should not be exported
        return;
    }

    my %spec_apis;
    foreach my $spec_file (@$spec_files)
    {
        if (open(my $fh, "<", "$rootdir$spec_file"))
        {
            while (my $line = <$fh>)
            {
                next if ($line =~ /^\s*(?:#|$)/);
                chomp $line;
                if ($line =~ /^\s*(?:\d+|@)\s+\w+\s+(?:$SPECOPT)*\$?$MANGLEDIDENT\s*\([^)]*\)\s+($SPECIDENT)\s*(?:#.*)?$/)
                {
                    my $identifier=$1;
                    $spec_apis{$identifier}=1 if ($identifier !~ /\./);
                }
                elsif ($line =~ /^\s*(?:\d+|@)\s+\w+\s+(?:$SPECOPT)*($SPECIDENT)\s*\([^)]*\)\s*(?:#.*)?$/)
                {
                    my $identifier=$1;
                    $spec_apis{$identifier}=1 if ($identifier !~ /\./);
                }
                elsif ($line =~ /^\s*(?:\d+|@)\s+stub\s+(?:$SPECOPT)*($SPECIDENT)(?:@\d+)?\s*(?:#.*)?$/)
                {
                    my $identifier=$1;
                    $spec_apis{$identifier}=1 if ($identifier !~ /\./);
                }
                elsif ($line =~ /^\s*(?:\d+|@)\s+stub\s+(?:$SPECOPT)*$MANGLEDIDENT\s*(?:#.*)?$/)
                {
                    # Stub with only a mangled name -> no use to us
                }
                elsif ($line =~ /^\s*\d+\s+stub\s+@\s*(?:#.*)?$/)
                {
                    # Unnamed stub -> no use to us
                }
                elsif ($line =~ /^\s*(?:\d+|@)\s+extern\s+(?:$SPECOPT)*\$?$MANGLEDIDENT\s+($SPECIDENT)\s*(?:#.*)?$/)
                {
                    my $identifier=$1;
                    $spec_apis{$identifier}=1 if ($identifier !~ /\./);
                }
                elsif ($line =~ /^\s*(?:\d+|@)\s+extern\s+(?:$SPECOPT)*($SPECIDENT)\s*(?:#.*)?$/)
                {
                    my $identifier=$1;
                    $spec_apis{$identifier}=1 if ($identifier !~ /\./);
                }
                elsif ($line =~ /^\s*\d+\s+equate\s/)
                {
                    # No use to us
                }
                else
                {
                    err("$spec_file: unknown line format\n  $line\n");
                }
            }
            close($fh);
        }
        else
        {
            err("unable to open '$spec_file' for reading: $!\n");
            exit 1;
        }
    }

    my (%idl_ignore, %obj_exports, %obj_references);
    foreach my $obj_file (@$obj_files)
    {
        my ($idl_cs, $idl_proxy);
        my $idl_file=$obj_file;
        if ($idl_file =~ s/_[csp]\.o$/.idl/ and -f "$rootdir$idl_file")
        {
            $idl_cs=1 if ($obj_file =~ /_[cs]\.o$/);
            $idl_proxy=1 if ($obj_file =~ /_p\.o$/);
        }

        if (open(my $fh, "objdump -t \"$rootdir$obj_file\" |"))
        {
            while (my $line = <$fh>)
            {
                if ($line =~ /^.*\s\.text\s+[0-9a-f]+\s+(?:\.hidden\s+)?([A-Za-z_][A-Za-z0-9_]*)$/)
                {
                    my $symbol=$1;
                    if ($idl_cs)
                    {
                        $idl_ignore{$symbol}=1;
                    }
                    elsif ($idl_proxy and $symbol =~ /_(?:Proxy|Stub)$/)
                    {
                        $idl_ignore{$symbol}=1;
                    }
                    else
                    {
                        $obj_exports{$symbol}=1;
                        $obj_references{$symbol}++;
                    }
                }
                elsif ($line =~ /^.*\s\*UND\*\s+[0-9a-f]+\s+(?:\.hidden\s+)?([A-Za-z_][A-Za-z0-9_]*)$/)
                {
                    $obj_references{$1}++;
                }
            }
            close($fh);
        }
        else
        {
            err("unable to analyze '$obj_file': $!\n");
            exit 1;
        }
    }

    my $dir=dirname($so_file);
    if (open(my $fh, "nm -D \"$rootdir$so_file\" |"))
    {
        while (my $line = <$fh>)
        {
            if ($line =~ /^[0-9a-f]+\sT\s(\w+)$/)
            {
                my $function=$1;
                if (!$obj_exports{$function})
                {
                    # We're importing this function, not exporting it!
                }
                elsif (($obj_references{$function} || 0) > 1)
                {
                    # This function is used in more than one object file
                    # so it cannot be made static.
                }
                elsif ($idl_ignore{$function})
                {
                    # These are widl-generated functions. They are meant to
                    # be used from other object files, but widl cannot know
                    # whether that will actually be the case or not.
                    # So these functions cannot be made static.
                }
                elsif ($asm_functions{$dir}->{$function})
                {
                    # Functions implemented in assembly, or referenced from
                    # assembly code, cannot be made static due to gcc
                    # limitations.
                }
                elsif ($spec_apis{$function})
                {
                    # These are meant to be exported
                }
                elsif ($is_exe and $function =~ /^w?(?:main|WinMain)$/)
                {
                    # Executables are supposed to export these.
                }
                elsif ($is_test and $function =~ /^(?:broken$|wine_dbgstr_[aw]n?$|winetest_)/)
                {
                    # Tests export these because of wine/test.h
                }
                elsif ($export_ignore{$dir}->{$function})
                {
                    delete $export_ignore{$dir}->{$function};
                }
                else
                {
                    print "$so_file: $function should be made static\n";
                }
            }
        }
        close($fh);
    }
    else
    {
        err("unable to analyze '$so_file': $!\n");
        exit 1;
    }
    foreach my $func (keys %{$export_ignore{$dir}})
    {
        print "$dir:$func not used\n";
    }
    delete $export_ignore{$dir};
}

sub fix_tree($$$$$$)
{
    my ($rootdir, $filter, $collect, $fix_c, $fix_rc, $fix_so)=@_;

    my @dirs=("");
    while (@dirs)
    {
        my $dir=pop @dirs;
        if (opendir(my $dh, "$rootdir$dir"))
        {
            my ($so_file, @spec_files, @obj_files);
            foreach my $dentry (readdir($dh))
            {
                next if ($dentry eq "." or $dentry eq "..");
                $dentry="$dir$dentry";
                if (-d "$rootdir$dentry")
                {
                    if (-l "$rootdir$dentry")
                    {
                        verbose("skipping '$dentry' directory symbolic link\n");
                        next;
                    }
                    push @dirs, "$dentry/";
                    next;
                }
                next if ($filter and $dentry !~ /^$filter/);

                if ($collect and $dentry =~ /\.[chly]$/)
                {
                    collect($rootdir, $dentry);
                }
                elsif ($collect and $dentry eq "include/config.h.in")
                {
                    collect($rootdir, $dentry);
                }
                elsif ($fix_c and $dentry =~ /\.[cly]$/)
                {
                    fix_c_file($rootdir, $dentry);
                }
                elsif ($fix_rc and $dentry =~ /\.rc$/)
                {
                    fix_rc_file($rootdir, $dentry);
                }
                elsif ($fix_so and $dentry =~ /\.so$/)
                {
                    $so_file=$dentry;
                }
                elsif ($fix_so and $dentry =~ /\.spec$/)
                {
                    push @spec_files, $dentry;
                }
                elsif ($fix_so and $dentry =~ /\.o$/ and $dentry !~ /\.cross\.o$/)
                {
                    push @obj_files, $dentry;
                }
            }
            closedir($dh);
            fix_so($rootdir, $so_file, \@spec_files, \@obj_files) if ($fix_so);
        }
        else
        {
            err("unable to open the '$dir' directory: $!\n");
        }
    }
}


#####
#
# Main
#
#####

my ($opt_c, $opt_rc, $opt_so, $opt_help, $opt_dir, $opt_filter);
use Getopt::Long;
my $rc=GetOptions("c"       => \$opt_c,
                  "rc"      => \$opt_rc,
                  "so"      => \$opt_so,
                  "debug"   => \$debug,
                  "verbose" => \$verbose,
                  "help"    => \$opt_help
                 );
if ($rc)
{
    $opt_dir=shift @ARGV if (@ARGV);
    $opt_filter=shift @ARGV if (@ARGV);
    if (@ARGV)
    {
        err("only one directory can be specified\n");
        $rc=0;
    }
    $opt_dir||=".";
    $opt_dir.="/" if ($opt_dir !~ m!/$!);
}
if (!$rc)
{
    err("try running $name0 --help\n");
    exit 2;
}
if (!defined $opt_c and !defined $opt_rc and !defined $opt_so)
{
    $opt_c=$opt_rc=$opt_so=1;
}
$verbose=1 if ($debug);
if ($opt_help)
{
    print "Usage: $name0 [--c|--rc|--so] [--verbose] [--debug] [--help] [dir [filter]]\n";

    print "\n";
    print "Checks for various types of errors in the Wine source.\n";

    print "\n";
    print "Options:\n";
    print "  dir               The directory containing the Wine sources\n";
    print "  filter            Only handle that specific subdirectory\n";
    print "  --c               Fix the C files\n";
    print "  --rc              Fix the resource files\n";
    print "  --so              Check the API exported by .so files\n";
    print "  --verbose         Print some details and progress information\n";
    print "  --debug           Print lots of debug information\n";
    print "  --help            Prints this help message\n";
    exit 0;
}


### First pass: Collect information for the second pass
verbose("First pass...\n");
fix_tree($opt_dir, $opt_filter, 1, 0, 0, 0);

sub set_closure($@)
{
    my $set=shift @_;
    my $count=0;
    while (1)
    {
        my $c=keys %$set;
        last if ($count == $c);
        $count=$c;
        foreach my $map (@_)
        {
            while (my ($name, $value)=each %$map)
            {
                $set->{$name}=1 if ($set->{$value});
            }
        }
    }
}

# Find all the macros that expand to __stdcall
my %stdcalls;
map { $stdcalls{$_}=1 } @stdcall_seeds;
set_closure(\%stdcalls, \%macros);
verbose("stdcall = ", join(" ", sort keys %stdcalls), "\n");
$stdcall_re=join("|", keys %stdcalls);

# Round up the macros that expand to 0
set_closure(\%zeroes, \%macros);
verbose("zeroes = ", join(" ", sort keys %zeroes), "\n");

# Round up the pointer types
set_closure(\%pointers, \%typedefs, \%macros);
verbose("pointers = ", join(" ", sort keys %pointers), "\n");

# Find all languages with more than one sublanguage
foreach my $name (keys %macros)
{
    next if ($standard_sublangs{$name});
    if ($name =~ /^SUB(LANG_[A-Z]+)(?:_[A-Z][A-Z_]+)?$/)
    {
        my $lang=$1;
        if ($name !~ /^SUBLANG_(?:LOWER|UPPER)_SORBIAN_GERMANY$/ and
            !exists $macros{$lang})
        {
            err("$name has no matching language definition\n");
        }

        my $val=$macros{$name};
        my $indirect;
        if ($val =~ /^SUBLANG_/)
        {
            $val=$macros{$val};
            $indirect=1;
        }
        $val =~ s/^.*\(\s*((?:0x)?[0-9a-fA-F]+)\s*\).*$/$1/;
        $val =~ s/^0x0*(?=0$|[1-9a-fA-F])//;
        if ($val !~ /^[0-9a-fA-F]+$/)
        {
            err("unknown sublanguage type for $name: $macros{$name}\n");
            exit 1;
        }
        elsif ($val ne "1")
        {
            $lang_manysubs{$lang}=1;
        }
        elsif (!$indirect or ($lang_default{$lang} || "SUBLANG_DEFAULT") eq "SUBLANG_DEFAULT")
        {
            $lang_default{$lang}=$name;
        }
    }
    elsif ($name =~ /^(LANG_[A-Z]+)$/ and !$lang_default{$name})
    {
        $lang_default{$name}="SUBLANG_DEFAULT";
    }
}


### Second pass: Actually fix files and report issues
verbose("Second pass...\n");
fix_tree($opt_dir, $opt_filter, 0, $opt_c, $opt_rc, $opt_so);


### Check for unused blacklist entries
if (-f "$opt_dir/configure.ac" and !$opt_filter)
{
    if ($opt_c)
    {
        map { print "linefeed: $_ not found\n"; } sort keys %lf_blacklist;
        map { print "static: $_ not found\n"; } sort keys %static_ignore;
    }
    if ($opt_rc)
    {
        map { print "$_ should not be in \%lang_anysub\n" if (!$lang_manysubs{$_}) } sort keys %lang_anysub;
    }
    if ($opt_so)
    {
        map { print "export: $_ not found\n"; } sort keys %export_ignore;
    }
}


More information about the wine-devel mailing list