Configuration

This chapter will explain the various configuration options for Prolint


file exclude.lst

# this file specifies which particular warnings should be excluded. The rules will
# still be executed, but warnings are intercepted if they match this file.
# You can also consider using {&_proparse_ prolint-nowarn(ruleid,ruleid)} directives
# 
# format:
#    sourcefile|rules
#
# sourcefile : spell exactly as it appears in "Prolint result window",
#              wildcards are accepted. CAN-DO rules apply
# rule       : comma separated list of identifiers of the rules that gives the warning, 
#              wildcards are accepted. CAN-DO rules apply
#
# empty lines or lines matching #* are ignored

# exclude everything from directories adm and adm2:
adm/*.i|*
adm2/*.i|*

# from file ifindent.i, allow rules ifindent1 and ifindent2 but exclude all other rules:
prolint/regrtest/ifindent.i|!ifindent*,*

file nowarn.lst

# this file specifies which particular warnings should be suppressed. The rules will
# still be executed, but warnings are intercepted if they match this file.
# You can also consider using {&_proparse_ prolint-nowarn(ruleid,ruleid)} directives
# 
# format:
#    sourcefile|rule|linenumbers
#    sourcefile|_file-size|size
#
# sourcefile : spell exactly as it appears in "Prolint result window"
# rule       : identifier of the rule that gives the warning
# linenumbers: comma separated list of linenumbers where the warning would occur when not suppressed
#
# size : the filesize of the sourcefile, in bytes
# if _file-size is not specified, or if size doesn't match the actual size of the sourcefile,
# all lines for sourcefile will be invalid. So after you edit a sourcefile no warnings will be suppressed.
#
# empty lines or lines matching #* are ignored
# unfortunately when you lint prolint itself you will get a lot of warnings from proparse.i
proparse/api/proparse.i|_file-size|3179
proparse/api/proparse.i|varusage|8,10,12,14,16,18,28,30,34,36,38,40,42,44,48,50,62,64,67,70,72,74,76,78,80,84
proparse/api/proparse.i|nocomment|8
proparse/api/proparse.i|nocomment|10
proparse/api/proparse.i|nocomment|12
proparse/api/proparse.i|nocomment|14
proparse/api/proparse.i|nocomment|16
proparse/api/proparse.i|nocomment|18
proparse/api/proparse.i|nocomment|20
proparse/api/proparse.i|nocomment|22
proparse/api/proparse.i|nocomment|24
proparse/api/proparse.i|nocomment|26
proparse/api/proparse.i|nocomment|28
proparse/api/proparse.i|nocomment|30
proparse/api/proparse.i|nocomment|32
proparse/api/proparse.i|nocomment|34
proparse/api/proparse.i|nocomment|36
proparse/api/proparse.i|nocomment|38
proparse/api/proparse.i|nocomment|40
proparse/api/proparse.i|nocomment|42
proparse/api/proparse.i|nocomment|44
proparse/api/proparse.i|nocomment|46
proparse/api/proparse.i|nocomment|48
proparse/api/proparse.i|nocomment|50
proparse/api/proparse.i|nocomment|52
proparse/api/proparse.i|nocomment|54
proparse/api/proparse.i|nocomment|56
proparse/api/proparse.i|nocomment|58
proparse/api/proparse.i|nocomment|60
proparse/api/proparse.i|nocomment|62
proparse/api/proparse.i|nocomment|64
proparse/api/proparse.i|nocomment|66
proparse/api/proparse.i|nocomment|68
proparse/api/proparse.i|nocomment|69
proparse/api/proparse.i|nocomment|70
proparse/api/proparse.i|nocomment|72
proparse/api/proparse.i|nocomment|74
proparse/api/proparse.i|nocomment|76
proparse/api/proparse.i|nocomment|78
proparse/api/proparse.i|nocomment|80
proparse/api/proparse.i|nocomment|82
proparse/api/proparse.i|nocomment|84

optional: the prolint database

Prolintdb consists of an outputhandler to write warnings to a database, and a couple of programs to help you query the database.

the user story:

Suppose you have a pretty large software project and want to inspect it with Prolint. It will take a long while for Prolint to finish the job,
so you would like to run Prolint unattended and look at the warnings later. Since it is a large software project Prolint will probably find
thousands of warnings, so you need tools to help you generate an overview.

Setup / configuration

  1. Create a Progress database. Do not create the database in the Prolint directory or in one of its subdirectories, because
    that might cause trouble with future updates of Prolint. I would suggest to create separate databases for each software project.

  2. Make sure the logical database name is "prolintdb".
  3. Load the dictionary from file "prolint/prolintdb/prolintdb.df".
  4. modify your startup script or shortcut, so this database will be connected in the session where you run Prolint.

Using Prolintdb

Make sure the prolintdb database is connected with logical database name "prolintdb".

Run Prolint as usual, but select a profile that uses outputhandler "prolintdb.p". This outputhandler is responsible for writing warnings to the database.
When you do not want to write anything to the database, then just don't use outputhandler "prolintdb.p".

To query warnings that are stored in the prolint database, you can use the windows "Statistics by rule" and "Statistics by subdirectory".
These windows can be launched from the Prolint Desktop window.

These windows don't actually query the warnings that are generated by the outputhandler, but they query statistics.
These statistics are also stored in the database but need to be calculated manually: just press
button "Recalculate" in one of the statistics windows. Statistics are not automatically refreshed after you run Prolint, you just need to press the Recalculate-button.

From the two statistics windows, you can use button "Show Results" to see the actual Prolint warnings that were saved by the outputhandler.
This button launches the usual "Prolint Results Window" and publishes the selected warnings to that window.

Once the selected warnings are visible in the Results window, you can use all the features of that window including: open the sourcefiles at the specified line number, re-lint the selected compilation unit, etc.

Please notice that the "Prolint Results window" assumes that you have been using a profile named "prolintdb".

When you want to re-lint a selected compilation unit, the Results window will try to do that with profile "prolintdb".
So it is required to actually have such a profile, and to make sure that this profile uses outputhandler "prolintdb.p".


Profiles

You don't always want to run every rule. A "profile" contains a specification of the rules you want to skip and which outputhandlers you want to use. You can create as many profiles as you want.

For example, you may want to create a profile named "indexes" that only uses rules "nowhere", "sortaccess" and "wholeindex" and writes its output to HTML and to a tab-delimited file. Or you may want to ue profile "Ed4Win" that writes its output to the build-window in ED for Windows.

Each subdirectory in "prolint/settings" is a profile. Each of those subdirectories contains a couple of ascii-files to define the characteristics of the profile.

Local profiles vs Shared profiles

Profiles in "prolint/settings" are considered to be "shared" profiles.

In addition to "prolint/settings" you can also create a directory "local-prolint/settings" anywhere in your propath. Each subdirectory in "local-prolint/settings" is also a profile, and these are considered to be "local" profiles.


you can achieve two different goals with local profiles:

  1. Specific profiles for different projects.

    Assuming you have different Progress products, each with their own working-dir or Propath, you can create a subdirectory "local-prolint/settings" in that Propath to override the default profiles in "prolint/settings".

  2. Personal profiles for each user.

    If Prolint is used in a larger development team, each individual programmer can create local profiles simply by creating a directory "local-prolint/settings" in their working-directories and avoid conflicts over shared profiles.

The list of profiles, available in a prolint-session, is merged from profiles in both "prolint/settings" and "local-prolint/settings".

A local profile overrides the shared profile, unless the shared profile contains a file named "no-local-settings.lk". The contents of this file is not important, but the existence of such a file notifies prolint that only the shared profile should be used and the local profile will be ignored.

for a GUI-window to modify the settings described here:

   run prolint/core/lintcfg.w("")                               

See page "lintcfg" for features of this window.

files you may find in a profile subdirectory:

file severity.d

specifies which rules to run and allows to customize severities.

inherits prolint/rules/rules.d

each line has two or three fields:

  1. required YES/NO

    if NO, the rule specified in field 2 will not be used by this profile.
  2. rule id
  3. custom severity

    this replaces the default severity.

    if this field is missing, prolint will just use the default severity

file handlers.d

specifies a list of outputhandlers to start for this profile.
these are programnames found in directory prolint/outputhandlers.

Prolint 'knows' for each outputhandler if it requires a specific Progress version or GUI/ChUI mode. It will not run the
outputhandlers that don't match the current Progress session. This means you can safely select "logwin" even if you
are running a ChUI session, because in that case Prolint will simply skip "logwin".

If file handlers.d is missing, or if the file is empty, or if it only contains outputhandlers that are not supported
in the current Progress session, then Prolint will terminate with an error message.

file nowarn.lst

Same purpose as putting {&_proparse_ prolint-nowarn(ruleid)} in source, but may be more convenient if the source is
maintained by someone else (like sources in adm2/src)

See example nowarn.lst for details.


Settings and Profiles

for a GUI-window to modify the settings described here:

   run prolint/core/lintcfg.w("")                               

Directory prolint/settings shows an example of how custom profiles can be used.

Each profile represents a subdirectory in prolint/settings.

Such a subdirectory may contain configuration files describing the behavior of Prolint.

The name of the custom profile is passed to Prolint as an input parameter. For example:

  RUN prolint/core/prolint.p (sourcefile, ttemptablehandle, "relaxed", true).

tells prolint to look for configuration files in directory prolint/settings/relaxed.

The configuration files in this directory may tell prolint to skip all rules with severity<6, for example.

If the parameter is blank or points to a non-existing directory, prolint will
use directory prolint/settings instead because this contains the default settings.

Profiles can be attractive when prolint is called from other ADE-tools to specify the
context where prolint is called from.

For example, Roundtable might run prolint.p(.., .., "rtb check-in",..)
during its pre-validation on check-in.

The Application compiler might run prolint.p(.., .., "application compiler",..)
which might tell prolint to write results to a logfile instead of using the results window.

Note: directories are searched in PROPATH.

files in prolint/settings:

file exteditor.cfg

file exteditor.cfg specifies how a source file can be opened in an external editor, like for example Ed4Win or UltraEdit etc.


exteditor.cfg contains just two lines:

  1. commandline
  2. parameters

These two lines are passed to the operating system. Each of these lines may contain &1 and &2, which are substituted by
filename and linenumber respectively, using the Progress SUBSTITUTE function.

example (for UltraEdit-32) :

"C:\Program Files\UltraEdit\UEDIT32.EXE"
"&1/&2"

(in this example the double quotes are used for supporting long filenames.)

file dbaliases.d

If your program requires database aliases to exist before it will compile, then you must use this file to tell Prolint about your database aliases before that program can be parsed.
The file may contain several lines, each line contains two fields: aliasname and databasename. Example:

"demo" "sports2000"
"archive" "sports2001"

In this example, "demo" is an alias for database "sports2000" and "archive" is an alias for database "sports2001".

files you may find in a profile subdirectory:

See profiles


Suppress warnings

Sometimes Prolint may raise a warning you don't agree with.
For example, rule "noundo" might warn that a specific temp-table is defined without NO-UNDO while you are certain that not using no-undo
is intentional.


In such cases you may want to suppress the Prolint warning.


There are two separate ways to suppress warnings:

  1. mark the statement with a _proparse_ directive
  2. use filters

Finally, if you really completely disagree with a rule, you can put it in the "skiprules" list. In that case Prolint will pretend the rule does not exist at all. The "skiprules" list is file "prolint/custom/rules/skiprules.lst". Its format is simple: each line contains one rule-id.

_proparse_ directives

Let's begin with an example:

{&_proparse_ prolint-nowarn(noundo)}
DEFINE TEMP-TABLE tt_mytable 
   FIELD code AS CHAR
   FIELD desc AS CHAR INIT "<description>"
   INDEX idx_code AS PRIMARY UNIQUE code.

When Prolint executes rule "noundo" it will simply skip the statement, the statement is invisible to the rule.

Prolint will still give a warning for rule "abbrevkwd" because INIT is an abbreviation for INITIAL, and a warning for
rule "strattrib" because "<description>" does not have any string attributes.


If you are sure you want to suppress these warnings too, you can extend the _proparse_ directive to:

{&_proparse_ prolint-nowarn(noundo,abbrevkwd,strattrib)}
DEFINE TEMP-TABLE tt_mytable 
   FIELD code AS CHAR
   FIELD desc AS CHAR INIT "<description>"
   INDEX idx_code AS PRIMARY UNIQUE code.

Note:

There is no way to suppress all warnings.
There is also no way to suppress warnings for a larger scope than just one single statement.
This is intentional: adding _proparse_ directives is meant to be more work than fixing the cause of the warning.

Another note:
Please don't use the _proparse_ directive immediately after the ELSE keyword.

/* this does not work and confuses the parser: */
IF False THEN 
   RUN first.p.
ELSE
   {&_proparse_ prolint-nowarn(runname)}
   RUN Second.p.
/* this is better: */
IF False THEN 
   RUN first.p.
ELSE DO:
   {&_proparse_ prolint-nowarn(runname)}
   RUN Second.p.
END.   
    
/* or this is also fine: */
{&_proparse_ prolint-nowarn(runname)}
IF False THEN 
   RUN first.p.
ELSE
   RUN Second.p.

filters

Filters intercept warnings after they are created by a rule, but before they are published to outputhandlers. Filters can modify or hide warnings.

You can create new filters, or configure existing filters. See topic "filter plug-ins" for more information.


Turbolint

Note: This is history. Turbolint is removed from Prolint release 74, because Turbolint was not compatible with Proparse.NET

Turbolint is a Dynamic Link Library that contains 3GL versions for some of the rules. The purpose of Turbolint is to improve the overall performance of Prolint, by running the 3GL rules instead of the 4GL rules.


The rules contained in Turbolint are supposed to be identical to the 4GL rules, only faster.

Turbolint.dll does not contain 3GL versions of every existing 4GL rule.

By default, if a 3GL rule exists in Turbolint.dll, then Prolint will use this 3GL version instead of the 4GL version.

Obviously if a rule does not exists in Turbolint.dll then Prolint will use the 4GL version.

Turbolint.dll currently contains the following rules:

abbrevkwd,blocklabel,ifindent,ifindent1,ifindent2,noundo,nowhere,recid,runargs,sepdbui,substitute,varusage


The ultimate goal is not to have every rule in Turbolint, only the really slow ones.

What to do if you prefer 4GL?

Sometimes you may want to prefer the 4GL version of a rule, even if Turbolint contains a 3GL version. For example when you are modifying or debugging the rule.
There are different ways to force Prolint to use the 4GL rule:

custom rules always take precendence over standard rules. Just copy the rule from directory "prolint/rules" to "prolint/custom/rules". Because if Prolint can find a rule in "prolint/custom/rules" then it's a custom rule, and will be run instead rules with the same name in "prolint/rules" or turbolint.

If you don't want to make a custom rule, but still want to run a 4GL rule instead of a 3GL rule, then you can specify so in file
"prolint/custom/prolint.properties.p" :

For example:

     RUN SetProlintProperty ("Turbolint.RulesToIgnore", "noundo,varusage").

will force Turbolint to NOT run its built-in versions of rule "noundo"
and "varusage", and Prolint will run the 4GL versions instead. See
file prolint/prolint.properties.p for more details.

Finally, you can simply remove or rename file "prolint/turbolint.dll" so Prolint cannot find it. Prolint will then simply fall back to its 4GL rules.