Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Update multiple prg files at the same time? 1

Status
Not open for further replies.

DB Boxers

Programmer
Jan 3, 2022
3
US
Hi, pardon the newbie question. Would like to update multiple prg files in a folder at the same time, without having to open each file. Goal is to change the directory location from \\origserver\Reports\ to \\newserver\Reports\ across all the files. Is that possible?

Thank you.
 
Hi DB Boxer,

I'm putting a longer answer in because you wrote you are a newbie. So I apologise in advance if what everything here is old hat to you! Also this post does not replace what others have written about using an editor to change multiple files -- I'm only writing about what the new code should look like.

As Chris Miller indicates the general solution is not to hardcode paths. Ideally you would change the 100 programs so that they do not all have to be changed in the future when the path changes again :) I'm guessing this is not a new system and it is likely that the existing vfp application already has one or more strategies for dealing with the issue -- it's just that the programmer didn't think to use one of those solutions for this particular path. Ideally (again) you would use one of the approaches already in place.

Most likely the application already has one or more of the following features


1) global application settings management
e.g. a global memory object goApp (or whatever) that has a bunch of application settings. Here you would add the report path to the object.
goapp.cReportPath = "\\newserver\Reports\" && global object with system settings​

Depending upon the complexity of the application you might find a raft of go[Something] where the naming convention "g" stands for global, "o" object etc.

Depending upon the age of the application this might simply be a long list of global memory variables. e.g. you would add

public gcReportPath​
gcReportPath = "\\newserver\Reports\"​

to the application startup program.


2) constants -- many larger VFP applications have one or more constants files.
See commands
#INCLUDE​
#DEFINE​
for how this works.

If these programs already have an #include you could add your constant with the path to the include file.

3) use relative paths
Unlike PHP for example, in VFP it is typical for the application to run from a specific directory, and all paths are relative to that running directory. If this is the way your application is setup then the change is might be as simple as changing

\\newserver\Reports​
to
Reports​

This would work if the default (starting) directory is \\newserver\, which is unlikely given the name. More likely the different like "\\applicationserver\vfp\myapplication\"

Chris Miller's suggestion is to use SET DEFAULT to change the starting directory so that relative paths work. This is theortically possible but unlikely to work properly for a legacy application. If you wish to know more about this approach simply ask, and someone will answer!


4) a more VFP specific approach is to use the SET PATH command. This would be useful if you need the path to call a some source code. e.g. if the orginal code is

REPORT FORM \\origserver\Reports\MyReport001​

Then put this line in your

SET PATH TO ("\\newserver\Reports\") ADDITIVE && code in your startup program​

the code could simply be changed to

REPORT FORM MyReport001​

This will not work if instead the \\newserver\ directory is the location where a report result should be stored (e.g. pdf or excel), only if it is the location for the source code.

If you want to know more about this approach, ask and someone will answer!

5) Create an alias so that "\\origserver" is mapped by the network administrator as "\\newserver" -- this is again Chris Miller's suggestion. I'm including it for completeness, but I think it will only work without weirdness if the "origserver" machine has been retired and replaced with a new machine that simply happens to have a different name. If both servers are still in use on the computer running VFP you will have to expect consequences.

Conclusion
-------------
Most likely the path should be saved to a system variable (1) or constant (2), but depending upon the exact nature of your problem one of the others might be cleaner.

 
Jamie,

Welcome to the forum. Your post contains a lot of good advice.

Most of your suggestions still include a hard-coded path, but in each case that hard-coding is localised in one small part of the application, which makes it easy to change. However, such a change would still require a new build of the application, which must then be distributed to users, with all that that implies.

My preferred approach is to store the path in an external file or other medium - one that can be edited by an administrator but which would not normally be accessible to an ordinary user. I often use an INI file for that purpose, but there are of course other possibilities.

Typically, this would specify the path to the database, and perhaps to error logs, archived data, and one or two other items. It would not include anything that would be regarded as part of the application itself, such as any free-standing reports, as these would all be in the application's own directory or sub-directories.

That's how I would do it, but of course other developers will have different approaches.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Chris,

You said:

you'll surely miss the VFP document view to easily jump to certain points in the code, which I personally find working better than collapsing and expanding
.

Yes, I do too. In fact, Notepad++ does have the equivalent of the document view. It's called the function list, and it is accessible from the View menu. I use it with Javascript, and it works well. But unfortunately, it doesn't work with the VFP definition that Greg posted (but neither does the collapsing and expanding, as far as I can see).

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
I think 'it depends' is probably the phrase that best covers this.

Generally, if a user is expected to select a database (or folder) from a short list which is unique to them
I prefer to use a local table (perhaps a database, perhaps not, depends on [see - there it goes again]...)
This table might be a list of individual complete paths, or relative ones to an overriding source. Often for
this I might see a number of projects (customers not mine) under one path on a specific drive. This has an
advantage whereby should the list be lost somehow it can be rebuilt by searching all the sub folders
of the specific drive and path - looking for .dbc files of a specific name (the app name typically).

Where there are many users, who all need access from time to time to any of the projects, it makes sense
to store that local table on a shared drive - so if user A adds a new project, all the others can see it.
This approach also lends itself to having smaller groups of users who are focussed on 'non-public' projects...
such as new aquisitions or semi-confidential projects - studies, proposals, remedial works things like that.

Where a user needs access to just one data folder (for example) I would use some variant of an ini file.
Probably not an 'standard' ini file though, one that is cryptic, if not actually encrypted - because I'm
not keen of letting customers IT people mess with my setups, and if an ini is in plain english they probably
will! I am generally paid to support the system and the users, not so much recover the damage done by
an 'interested' IT person - probably trying to pop a dodgy copy of something on a new machine...



Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.
 
Mike,

you're right in that a path should be configuration data. It might also just be an idea of DB Boxers that changing any occurrence of a path in any PRG to the new path solves the problem without even looking at any of the code. It could turn out the code doesn't have the path at all, nothing is replaced in code and the necessary change is still not done, as it is in some config file, ini, registry key or whatever else.

But when all sources exist, it should not be hard to find the place such a configuration is read and then change that. The idea to not read into the code and simply smash it with a general search and replace can also fire back at you.

As far as we pointed out solutions for globale search & replace, it's only covering code, not data. If you go through this with a *.* file skeleton and notepad++, it can find paths in data, too, in FPT files (as memo content) and then you can get into trouble if the new path is longer than the old or also shorter: The binary structure of the FPT then will be broken. So all such search & replace strategies still need to limit changes to pure text files, not anything that just includes the searched path in some file position, that's not working generally.

This again is something that makes a VFP tool preferrable. Not sure you can use code references to search and replace a text in any relevant Char, Memo, Varchar field in all tables of the project.

And once more I point out another reason to use a server alias to solve the problem without any change to code or config data. Or in a simpler case the new server share mapping to the previous mapped drive letter with the same share name, if it was mapped as a drive letter. There are several solutions in that direction that are thought of to be used when you only control the server environment and not the code.

Chriss
 
Just to demonstrate what happens if you blindly replace file parts in an FPT:

Code:
CD GETENV("TEMP")
lcDir = Sys(2015)
MD &lcDir
CD &lcDir
SET SAFETY OFF

SET BLOCKSIZE TO 1
CREATE TABLE config (path M)
INSERT INTO config VALUES ('\\AlphaBeta')
USE

FOR i= 1 TO ADIR(laFiles,'*.*')
     TRY
        lcOldContent = FILETOSTR(laFiles[i,1])
        lcNewContent = STRTRAN(lcOldContent,'\\AlphaBeta','\\DeltaOmega')
        STRTOFILE(lcNewContent,laFiles[i,1],0)
     CATCH
        *
     ENDTRY 
ENDFOR i

USE config
? config.path

In this case the file structure has a bit (or to be exact 1 byte) of freedom to change without being broken, but as the memo field is stored with the offset and length of the initial name \\AlphaBeta and \\DeltaOmega is 1 letter longer, the a is cut off from reading the memo. So, look closely, the final output is \\DelatOmeg, not \\DeltaOmeg[highlight #FCE94F]a[/highlight]. If you open the FPT file in notepad++ you'll see it contains \\DeltaOmega, the a is stored and shifts the end of the file, which only has some trailing NULs which count don't matter much. In a much more general case you can really mess the memo up. With any value change the struct that points to start and length of a memo value has to change, too.

And that's just a very general rule of text embedded within any binary file that is composed of chunks of data with headers that have meanings. Yes you can read any bytes, you can find and replace text, it still doesn't mean the new text is really fully in the right position and context.

Chriss
 
I know, I know, the original post and thread title explicitly says PRG files...

Chriss
 
I know, the original post and thread title explicitly says PRG files..

Exactly. I don't know how this discussion of search and replace in FPTs arose - or of any other binary date.

Not sure you can use code references to search and replace a text in any relevant Char, Memo, Varchar field in all tables of the project.

Well, if you try to search and replace inside a DBF or DBC using code references, I think it only looks in the meta data, that is, the table and field names, table and field properties, stored procedures, SQL statements in local and remote views, and so on. If you wanted to change actual data, you could probably do that by renaming the table to, say, TXT. But I can't imagine actually doing that.

On the other hand, code refs will happily search and replace inside DOC or XLS files. I know people who have done that. Not surprisingly, the files in question were nicely corrupted. But the point is that code refs didn't prevent them doing it.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
The NotePad++ file that I uploaded I got several years ago (do not remember where). I have made adjustments to it as time as past. Yes, it would be nice if intellisense was available - NotePad++ would have to have extensive knowledge of VFP PEMs, so it is not possible. I use NotePad++ to view a PRG file from the Windows File Explorer and not from VFP at all.

However, I wrote replacement editors for forms (scx), visual classes (vcx), programs (prg), menus (mnx), and tables (dbf). There are also other tools for comparing SCX, PRG and VCX files; a table browser; a project manager supplement (integrated with the editors); and a global search tool. I have mentioned them before on this forum. I am doing again because someone above lamented on better editors. I have uploaded the full source code and supporting active-x components to GitHub -- see If anyone is interested in installing the editors, I had sent a number of emails to a couple of other users that I can forward. Please let me know.

Greg
 
Mike--

You mentioned that the NotePad++ VFP definition file did not support code collapse -- it does. See screen shots below:

2022-01-06_20-16-30_etntjg.jpg


Now showing collapse:

2022-01-06_20-19-20_w3erww.jpg
 
Hi Mike,

You are completely correct, a configuration file is most likely the best solution for an absolute path (or url), if only to support a test environment. I think it is likely that DB Boxers application already has an ini or constant file setup, and that he/she could burrow through the system to find it. My note was to help identify the approach that is already used in the application. e.g. look for #include in the prg, look for a global settings object, look for groups of global variables in the application startup. Find other examples of paths in the application. If such a mechanism already exists it is better not to write a new mechanism. The tricky part is that quite possibly the existing app has all of the elements I mention: constants, a global setting object (read from an ini of course), and hard coded paths, and even the foxpro config file. Then the best solution depends upon exactly how this absolute path is being used.

kind regards,

Jamie









 
Greg said:
You mentioned that the NotePad++ VFP definition file did not support code collapse

No, I don't think I said that. I saw that your language file does support code collapse in Notepad++. Also it supports Intellisense, but this is Notepad++-style Intellisense, not the VFP variety. So, when you start typing a string, it offers to auto-complete it, not with a pre-defined keyword, but with a word that already appears in the file.

Now that you mentioned it, Greg, I remember that you mentioned your replacement editor in a thread some time ago. I never got round to trying it out at the time, but will look again now.

I use NotePad++ to view a PRG file from the Windows File Explorer and not from VFP at all.

That seems like a good use for it - especially as you can add "Open with Notepad++" as a shortcut to the context menu.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Some things to mention about Notepad++:

Notepads UDL (user defined language) XML files define a file extension for the language. And the syntax coloring and further features only kick in, if you save (or load) a file with that extension. So starting a new file you have no file extension and no intellisense unless you first save with the file extension for the language.

Notepad++ does offer intellisense for parameters, for example, if you save something with .php extension you can type in a PHP function and get parameter intelisense. It differs a bit from VFPs, but it's about the same functionality. Overall a bit more and less here and there. But to get there, the definition would need to be extended a lot. A source of necessary data would be in foxcode.dbf.

And then still several things would be missing, like PEMs of classes/objects. Of variables known to be that object, including OLE objects.

I guess looking int a PRG without needing to open VFP for it can be handy, though the VFP IDE does start fast, too, especially when turning off task pane start. You could also easily get the collapse feature when using a treeview that nests code lines by their indentation, but then syntax coloring is gone, so that's a thing notepad++ can do with the language definition.

Notepad does not detect a single * as comment, most likely you can't configure that, as it's interpreted as the multiplication operator and you can't define that * only works at line start, otherwise also the native editor would not allow multiplication or show everything after and including the second factor as a comment. && always felt like a patch fix for that and choosing something else than // and /*...*/ is a bad choice anyway.

Chriss
 
Some good points there, Chris.

I guess looking int a PRG without needing to open VFP for it can be handy, though the VFP IDE does start fast, too, especially when turning off task pane start.

An advantage of using Notepad++ for that is that, if you open multiple PRGs in that way, VFP opens each in a separate instance, whereas Notepad++ opens them in the same instance, in separate tabs, which is probably more convenient.

Notepad does not detect a single * as comment,

That's right. And furthermore, if any of the text inside the comment happens to match VFP keywords, Notepad++ applies syntax colouring to those words, which is probably not what you want. For example:

Code:
* [COLOR=#204A87]This[/color] can be[COLOR=#204A87] used for general[/color]-purpose utility routines that 
can be called [COLOR=#204A87]from[/color] anywhere [COLOR=#204A87]in[/color] the application.

Interestingly, Notepad++ does recognise the word NOTE as starting a comment. Also, you can use Block Comment to create a block of comments beginning with *!*, just as you can in VFP (and Block Uncomment to reverse that).

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top