About the "mess":
Well, you know and see you can't get the data show up in any codepage, you only have some of it right in codepage 866 (Cyrillic DOS) and other data right in codepage 1251 (Cyrillic Windows).
CPZERO can only switch to one, not both, but cpzero does not change any data bytes. So the mess about mixed data was already there before and didn't get worse through usage of cpzero. You can get into bigger trouble with string conversion, if its not reversible. And most string encoding conversions from a bigger set of characters to a smaller set of characters are not reversable, fully. Even the two cyrillic codepages don't have a mapping of all thier characters to each other, they are not just the same 256 characters in different order, so converting between 1251 to 866 and back or vice versa you can have a loss and characters turn into '?'.
I think your goal can only be to have all data in the Windows codepage 1251. So the task now is to find out what strings are codepage 866 and to convert them to 1251.
You ideally would know which codepage each field is, but that's not stored with the string. You only have byte values, in the end.
In VFP you have STRCONV() - I mentioned that, but also and better for that conversion, CPCONVERT(). So to convert DOS string to Windows that's windowsstring = CPCONVERT(866,1251,dosstring). But you can't tell whether field is the DOS codepage 866. This would have been the simple way if all data was codepage 866, so at the time changing from DOS to Windows, this would have worked for all data. Now it's too late to have a simple conversion like that.
If you do CPCONVERT(866,1251,field) on a field that's already in the Windows codepage 1251, that'll not stop it from making changes, the bytes are interpreted as being from codepage 866 and so a string readable in Windows is becoming unreadable. Even unreadable in codepage 866.
Let me give an example, looking into the Wikipedia pages
Cyrillic Windows Codepage 1251:
Cyrillic DOS codepage 866:
Code 0xE6 is ц in DOS and ж in Windows. So in both codepages it is a readable character. You can't decide from that byte being in the field, which codepage it is.
If you have a codepage 866 string with ц in it, CPVONVERT(866,1251,string) will convert this to Windows encoding and it will be seen as 'ц' again in Windows, with the byte code 0xF6. That's fine.
But a string already in codepage 1251 would not stay as it already is, it would be interpreted as codepage 866 and so a valid 'ц' in a Windows string would convert to 'Ў' or a 'ж' of a Windows string would be interpreted as a DOS 'ц' and become a Windows 'ц'. That's your dilemma. In both cases you would also only detecct a problem by reading the text, technically all interpretations are alphabetical.
What is CPCURRENT() for you? Is it 1251? If so then I think VFP will interpret characters of a string as if they are in codepage 1251 and categorize them with ISALPHA(), ISDIGIT() on that assumption. If you then find just a few characters in data that's not in these categories or a punctuation character, you could assume its DOS, but you never can be sure about that. You could analyze data that should mostly be cyrillic text this way:
Code:
Lparameters tcString
tcString = Alltrim(tcString)
Local lnI, lcChar, llDOSString
For lnI=1 To Len(tcSString)
lcChar = substr(tcString,lnI,1)
Do Case
Case Isalpha(lcChar)
Case IsDigit(lcChar)
Case lcChar $ [.,!;() ']+chr(9)+chr(13)+chr(10)
Otherwise
llDOSString = .T.
EXIT
EndCase
EndFor
Return llDOSString
This will judge any string that's not only consisting of letters, digits and some allowed punctuation characters or whitespace (tab, CR, LF, space) as a DOS string. It's likely that, as text won't need other characters. Even if memo contains Foxpro code written in the DOS codepage you could need to covert it, but then you'll also need to allow many further characters besides whitespace and punctuation.
Chriss