mirror of
				https://github.com/ElvishArtisan/rivendell.git
				synced 2025-11-03 23:53:59 +01:00 
			
		
		
		
	* Changed the recommended base branch for PRs from 'master' to 'v4' in the 'CONTRIBUTING CHANGES' section of 'CODINGSTYLE'. Signed-off-by: Fred Gleason <fredg@paravelsystems.com>
		
			
				
	
	
		
			433 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			433 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
This is the CODINGSTYLE file for the Rivendell package.
 | 
						|
 | 
						|
OVERVIEW:
 | 
						|
This file, CODINGSTYLE, describes the coding style guidelines for writing
 | 
						|
new code, how to submit patches to be incorporated into the official
 | 
						|
Rivendell Git repository, and other code related information. General info
 | 
						|
on the Rivendell project can be found at the http://www.rivendellaudio.org/
 | 
						|
web page and also in the 'README' and 'INSTALL' files.  
 | 
						|
 | 
						|
The code style used for Rivendell is a somewhat idiosyncratic mixture of
 | 
						|
the style generally used for Qt C++ programs combined with the classic UNIX
 | 
						|
C style. Some of the specifics include:
 | 
						|
 | 
						|
 | 
						|
LINE LENGTH:
 | 
						|
Should not be longer than 78 characters unless doing so would severely
 | 
						|
compromise the readability of the code. Where it is necessary to break a
 | 
						|
line, it should be done at a point that preserves maximum clarity and ease
 | 
						|
of reading.
 | 
						|
 | 
						|
Good:
 | 
						|
  *report+=QString(" ")+
 | 
						|
    logLine(i)->startTime(RDLogLine::Logged).toString("hh:mm:ss")+
 | 
						|
    QString::asprintf(" - cart %06d [",logLine(i)->cartNumber())+
 | 
						|
    q->value(1).toString()+"] "+QObject::tr("is not playable")+"\n";
 | 
						|
 | 
						|
Bad:
 | 
						|
  *report+=QString(" ")+logLine(i)->startTime(RDLogLine::Logged).toString("hh:mm:ss")+QString::asprintf(" - cart %06d [",logLine(i)->cartNumber())+q->value(1).toString()+"] "+QObject::tr("is not playable")+"\n";
 | 
						|
 | 
						|
 | 
						|
INDENTATION:
 | 
						|
Should be two spaces per level. This helps to keep the line length down.
 | 
						|
 | 
						|
Good:
 | 
						|
  if(to_line<0) {
 | 
						|
    to_line=size();
 | 
						|
    for(int i=from_line;i<size();i++) {
 | 
						|
      if(logLine(i)->timeType()==RDLogLine::Hard) {
 | 
						|
	to_line=i;
 | 
						|
	i=size();
 | 
						|
	if(sched_time!=NULL) {
 | 
						|
	  *sched_time=logLine(i)->startTime(RDLogLine::Logged);
 | 
						|
	}
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
Bad:
 | 
						|
  if(to_line<0) {
 | 
						|
          to_line=size();
 | 
						|
	  for(int i=from_line;i<size();i++) {
 | 
						|
                  if(logLine(i)->timeType()==RDLogLine::Hard) {
 | 
						|
	                  to_line=i;
 | 
						|
	                  i=size();
 | 
						|
	                  if(sched_time!=NULL) {
 | 
						|
	                          *sched_time=logLine(i)->startTime(RDLogLine::Logged);
 | 
						|
	                  }
 | 
						|
                   }
 | 
						|
           }
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
CURLY BRACES:
 | 
						|
Conditional statements (such as 'if' and 'for') should *always* use curly
 | 
						|
braces, even where the affected block is but one line long. The opening
 | 
						|
brace should be on the same line as the conditional and the closing one on
 | 
						|
a line by itself. This style greatly facilitates debugging, allowing a
 | 
						|
single line to be provisionally commented out or additional lines to be
 | 
						|
provisionally added without making the enclosing conditional syntactically
 | 
						|
invalid.
 | 
						|
 | 
						|
Good:
 | 
						|
  if(i==12) {
 | 
						|
    printf("i is equal to twelve!\n");
 | 
						|
  }
 | 
						|
 | 
						|
Bad:
 | 
						|
  if(i==12)
 | 
						|
    printf("i is equal to twelve!\n");
 | 
						|
 | 
						|
 | 
						|
PADDING WHITESPACE:
 | 
						|
Wherever possible, there should be no whitespace between constants/variables
 | 
						|
and operators. This helps to keep the line length down.
 | 
						|
 | 
						|
Good:
 | 
						|
  for(int i=from_line;i<size();i++) {
 | 
						|
    if(logLine(i)->timeType()==RDLogLine::Hard) {
 | 
						|
      to_line=i;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
Bad:
 | 
						|
  for(int i = from_line; i < size(); i++) {
 | 
						|
    if(logLine(i)->timeType() == RDLogLine::Hard) {
 | 
						|
      to_line = i;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
CLASS NAMES:
 | 
						|
Should have the initial letter of each word capitalized, e.g. 'ThisIsMyClass'.
 | 
						|
If the class is part of the librd convenience library (in 'lib/'), the name
 | 
						|
should be prefaced with the uppercase letters 'RD', e.g. 'RDThisIsMyClass'.
 | 
						|
 | 
						|
 | 
						|
METHOD NAMES:
 | 
						|
Public method names as well as signal and slot method names should follow
 | 
						|
the general style used by Qt. A special convention for Rivendell is to
 | 
						|
reserve names beginning with an uppercase letter for private methods only.
 | 
						|
 | 
						|
Good:
 | 
						|
class RDLogPlay
 | 
						|
{
 | 
						|
 Q_OBJECT
 | 
						|
 public:
 | 
						|
  RDLogPlay(int id,RDEventPlayer *player,QObject *parent=0);
 | 
						|
  QString serviceName() const;
 | 
						|
  void setServiceName(const QString &svcname);
 | 
						|
 | 
						|
 private slots:
 | 
						|
  void transTimerData();
 | 
						|
  void graceTimerData();
 | 
						|
 | 
						|
 signals:
 | 
						|
  void renamed();
 | 
						|
  void reloaded();
 | 
						|
  void transportChanged();
 | 
						|
 | 
						|
 private:
 | 
						|
  bool StartEvent(int line,RDLogLine::TransType trans_type,int trans_length,
 | 
						|
		  RDLogLine::StartSource src,int mport=-1,int duck_length=0);
 | 
						|
  bool StartAudioEvent(int line);
 | 
						|
};
 | 
						|
 | 
						|
Bad:
 | 
						|
class RDLogPlay
 | 
						|
{
 | 
						|
 Q_OBJECT
 | 
						|
 public:
 | 
						|
  RDLogPlay(int id,RDEventPlayer *player,QObject *parent=0);
 | 
						|
  QString servicename() const;
 | 
						|
  void set_service_name(const QString &svcname);
 | 
						|
 | 
						|
 private slots:
 | 
						|
  void TransTimerData();
 | 
						|
  void grace_timer_data();
 | 
						|
 | 
						|
 signals:
 | 
						|
  void RENAMED();
 | 
						|
  void Reloaded();
 | 
						|
  void transport_changed();
 | 
						|
 | 
						|
 private:
 | 
						|
  bool startEvent(int line,RDLogLine::TransType trans_type,int trans_length,
 | 
						|
		  RDLogLine::StartSource src,int mport=-1,int duck_length=0);
 | 
						|
  bool startAudioEvent(int line);
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
VARIABLE NAMES:
 | 
						|
*All* variables should be lowercase only, with uppercase being reserved for
 | 
						|
class and method names. Words should be separated by underscores.
 | 
						|
 | 
						|
Good:
 | 
						|
  int log_position_number=1;
 | 
						|
 | 
						|
Bad:
 | 
						|
  int logPositionNumnber=1;
 | 
						|
 | 
						|
Class variables should be prefaced with a short base name that is common to
 | 
						|
all, followed by an underscore. For example, the class 'MyClass' might use
 | 
						|
'myclass_', as in 'myclass_foo1', 'myclass_foo2', etc. Local variables
 | 
						|
(including function parameter names) should be kept short, preferably a
 | 
						|
single word.
 | 
						|
 | 
						|
 | 
						|
SQL STATEMENTS:
 | 
						|
When embedding SQL statements in code, the following guidelines should be
 | 
						|
followed:
 | 
						|
 | 
						|
1) All identifier fields should be enclosed in backticks (ASCII 0x2C)
 | 
						|
characters (NOT to be confused with apostrophes, see below).
 | 
						|
 | 
						|
Good:
 | 
						|
  sql="select `FIELD1`,`FIELD2` from `MY_TABLE` where `ID`=2";
 | 
						|
 | 
						|
Bad:
 | 
						|
Good:
 | 
						|
  sql="select FIELD1,FIELD2 from MY_TABLE where ID=2";
 | 
						|
 | 
						|
 | 
						|
2) All string literals should be delimited with the apostrophe character,
 | 
						|
*not* quotes. The previous use of quotes is a MySQL-ism that is now strongly
 | 
						|
discouraged.
 | 
						|
 | 
						|
Good:
 | 
						|
  sql="select `FIELD1` from `MY_TABLE` where `FIELD2`='foobar'";
 | 
						|
 | 
						|
Bad:
 | 
						|
  sql="select `FIELD1` from `MY_TABLE` where `FIELD2`="foobar";
 | 
						|
 
 | 
						|
 | 
						|
3) All identifiers are uppercase-only, while SQL operators
 | 
						|
   should be all lowercase. This helps improve readability.
 | 
						|
 | 
						|
Good:
 | 
						|
  sql="select `FIELD1`,`FIELD2` from `MY_TABLE` where `ID`=2";
 | 
						|
 | 
						|
Bad:
 | 
						|
  sql="SELECT `FIELD1`,`FIELD2` FROM `MY_TABLE` WHERE `ID`=2";
 | 
						|
 | 
						|
 | 
						|
4) Long or complex SQL statements should be broken into multiple lines in
 | 
						|
   a manner to enhance the readability of both C++ and SQL. For 'select'
 | 
						|
   queries that return more than two fields per row, each field should be
 | 
						|
   commented with its ordinal number to assist in determining the
 | 
						|
   appropriate value to give to 'RDSqlQuery::value()' for referencing
 | 
						|
   the fields.
 | 
						|
 | 
						|
Good:
 | 
						|
  sql=QString("select ")+
 | 
						|
    "`CART`.`TITLE`,"+         // 00
 | 
						|
    "`CART`.`ARTIST`,"+        // 01
 | 
						|
    "`CART`.`PUBLISHER`,"+     // 02
 | 
						|
    "`CART`.`COMPOSER`,"+      // 03
 | 
						|
    "`CART`.`USAGE_CODE`,"+    // 04
 | 
						|
    "`CUTS`.`ISRC`,"+          // 05
 | 
						|
    "`CART`.`ALBUM`,"+         // 06
 | 
						|
    "`CART`.`LABEL`,"+         // 07
 | 
						|
    "`CUTS`.`ISCI`,"+          // 08
 | 
						|
    "`CART`.`CONDUCTOR`,"+     // 09
 | 
						|
    "`CART`.`USER_DEFINED`,"+  // 10
 | 
						|
    "`CART`.`SONG_ID`,"+       // 11
 | 
						|
    "`CUTS`.`DESCRIPTION`,"+   // 12
 | 
						|
    "`CUTS`.`OUTCUE` "+        // 13
 | 
						|
    "from `CART` left join `CUTS` "+
 | 
						|
    "on `CART`.`NUMBER`=`CUTS`.`CART_NUMBER` where "+
 | 
						|
    "`CUTS`.`CUT_NAME`='"+RDEscapeString(button->cutName())+"'";
 | 
						|
 | 
						|
Bad:
 | 
						|
  sql="select `CART`.`TITLE`,`CART`.`ARTIST`,`CART`.`PUBLISHER`,`CART`.`COMPOSER`,`CART`.`USAGE_CODE`,`CUTS.ISRC`,`CART.ALBUM`,`CART.LABEL`,`CUTS`.`ISCI`,`CART`.`CONDUCTOR`,`CART`.`USER_DEFINED`,`CART`.`SONG_ID`,`CUTS`.`DESCRIPTION`,`CUTS.OUTCUE` from `CART` left join `CUTS` on `CART`.`NUMBER`=`CUTS`.`CART_NUMBER` where `CUTS`.`CUT_NAME`='"+RDEscapeString(button->cutName())+"'";
 | 
						|
 | 
						|
 | 
						|
SCHEMA CHANGES:
 | 
						|
Changes that alter the schema of the database must include:
 | 
						|
 | 
						|
  A) Incrementation of the 'RD_VERSION_DATABASE' value in 'lib/dbversion.h'.
 | 
						|
 | 
						|
  B) Code that implements the schema change, in the
 | 
						|
     'utils/rddbmgr/updateschema.cpp' file.
 | 
						|
 | 
						|
  C) Code that implements an exact, perfect reversal of the schema change,
 | 
						|
     in the 'utils/rddbmgr/revertschema.cpp' file.
 | 
						|
 | 
						|
  D) Updating of the schema map in the 'MainObject::InitializeSchemaMap()'
 | 
						|
     method in the 'utils/rddbmgr/schemamap.cpp' file. (See the comment at
 | 
						|
     the top of the method definition for details).
 | 
						|
 | 
						|
  E) Update the table documentation appropriately in 'docs/tables/'.
 | 
						|
 | 
						|
  F) [VERY IMPORTANT] - Document the changes to the schema in your
 | 
						|
     'ChangeLog' entry, including the new value of 'RD_VERSION_DATABASE'.
 | 
						|
 | 
						|
 | 
						|
FONT MANGEMENT:
 | 
						|
All fonts used in Rivendell are managed by the RDFontEngine class, which
 | 
						|
provides them on the basis of abstract "roles" so as to provide consistency
 | 
						|
across the entire set of modules. See the file 'docs/apis/fonts.pdf' for
 | 
						|
a detailed description of this sub-system, including screenshot examples.
 | 
						|
 | 
						|
 | 
						|
WRITING TO THE SYSLOG:
 | 
						|
Rivendell makes extensive use of the syslog(3) system found on all
 | 
						|
POSIX-compliant systems. Sending messages to the syslog should almost
 | 
						|
always be done by means of the following method in 'RDApplication':
 | 
						|
 | 
						|
  void RDApplication::syslog(int priority,const char *format,...)
 | 
						|
 | 
						|
The exception to the above is when the application context does not
 | 
						|
include a global RDApplication object --e.g. in caed(8). For those
 | 
						|
cases, the following static RDApplication method should be used:
 | 
						|
 | 
						|
  void RDApplication::syslog(RDConfig *c,int priority,const char *format,...)
 | 
						|
 | 
						|
For a discussion of the parameters of these methods, see the syslog(3) man
 | 
						|
page. The 'priority' parameter should be one of the following values:
 | 
						|
 | 
						|
    LOG_ERR - Indicates that a fatal error has occurred; 'fatal' meaning
 | 
						|
              that the program is unable to continue and will now exit.
 | 
						|
 | 
						|
LOG_WARNING - Indicates that a non-fatal error has occured; meaning
 | 
						|
              that the program will continue to operate, but with
 | 
						|
              possibly significant operational degradation. This would be
 | 
						|
              appropriate for things like failure to connect to an
 | 
						|
              external switcher or other device.
 | 
						|
 | 
						|
   LOG_INFO - Information useful for tracking operational state --e.g.
 | 
						|
              a cart play-out has begun, a new Rivendell log has been
 | 
						|
              loaded, etc.
 | 
						|
 | 
						|
  LOG_DEBUG - Information useful for tracking or verifying Rivendell
 | 
						|
              software internal state. These messages will not normally
 | 
						|
              be seen by users, but can be made visible to allow for
 | 
						|
	      program debugging.  
 | 
						|
 | 
						|
NOTE: A 'facility' value should *not* be included in the 'priority'
 | 
						|
argument. The appropriate 'facility' value, as determined by the
 | 
						|
'SyslogFacility=' directive in rd.conf(5), will be added automatically.
 | 
						|
 | 
						|
 | 
						|
DATE/TIME FORMATS:
 | 
						|
The formats of date/time values presented in the Rivendell's GUI modules
 | 
						|
are user-specifiable in RDAdmin->SystemSettings. Thus, when handling such,
 | 
						|
the following facilities are available:
 | 
						|
 | 
						|
Value Inputs. The following classes are available:
 | 
						|
 | 
						|
RDDateTimeEdit - Subclass of QDateTimeEdit
 | 
						|
    RDDateEdit - Subclass of QDateEdit
 | 
						|
    RDTimeEdit - Subclass of QTimeEdit.
 | 
						|
 | 
						|
While the underlying Qt 'setDisplayFormat()' method remains available
 | 
						|
in these subclasses, *it should never be used*, as the underlying display
 | 
						|
formats are automatically derived and applied. In addition, these classes
 | 
						|
have a number of additional methods for handling Rivendell-specific
 | 
						|
situations (times to tenths-of-second precision, read-only states, etc).
 | 
						|
See the specific headers in 'lib/' for details.
 | 
						|
 | 
						|
Value Outputs. The following methods are available for easily rendering
 | 
						|
properly formatted date/time strings in GUI module contexts:
 | 
						|
 | 
						|
RDCoreApplication::timeString(const QTime &time,
 | 
						|
                              const QString &padding="") const;
 | 
						|
RDCoreApplication::tenthsTimeString(const QTime &time,
 | 
						|
                                    const QString &padding="") const;
 | 
						|
RDCoreApplication::shortDateString(const QDate &date) const;
 | 
						|
RDCoreApplication::longDateString(const Date &date) const;
 | 
						|
 | 
						|
The methods above that involve time all include support for optionally 
 | 
						|
specifying times with tenth-second precision. At present, the only place in 
 | 
						|
Rivendell where this facility is used is when specifying the 'Start Time' and
 | 
						|
'Grace Time' parameters in Rivendell logs. All other contexts should present
 | 
						|
times to single-second precision.
 | 
						|
 | 
						|
These methods can be easily accessed in GUI module contexts via the global
 | 
						|
'rda' pointer, as illustrated in the following code snippet:
 | 
						|
 | 
						|
*** snip snip ***
 | 
						|
#include <rdapplication.h>
 | 
						|
[..]
 | 
						|
QDate my_date(2021,8,13);  // 13 August 2021
 | 
						|
QString my_string=rda->shortDateString(my_date);
 | 
						|
*** snip snip ***
 | 
						|
 | 
						|
N.B. - These date/time formats are for use when interacting with users in
 | 
						|
a GUI context. They should *not* be used in other contexts, including
 | 
						|
(but not necessarily limited to):
 | 
						|
  1) SQL Statements. Standard SQL date-time formats apply, and should
 | 
						|
     be hard-coded appropriately.
 | 
						|
  2) Command-line Utilities. In the interest of providing stable interfaces
 | 
						|
     for scripting purposes, date/time values in Rivendell command-line
 | 
						|
     tools generally use ISO8601-compliant formats. Where this varies
 | 
						|
     (due to application requirements), it should be documented in the
 | 
						|
     appropriate manpage.
 | 
						|
  3) Standardized APIs. Data interfaces for external systems (JSON, XML,
 | 
						|
     etc) should continue to use the formats appropriate for those
 | 
						|
     contexts.
 | 
						|
  4) Syslog Messages. Any date/time references sent to syslog(3) should
 | 
						|
     use ISO8601-compliant formats.
 | 
						|
 | 
						|
 | 
						|
CONTRIBUTING CHANGES:
 | 
						|
The primary code repository for Rivendell resides at GitHub, and can be
 | 
						|
found at:
 | 
						|
 | 
						|
      https://github.com/ElvishArtisan/rivendell
 | 
						|
 | 
						|
Changes should be submitted in the form of a pull request [PR] against
 | 
						|
the default branch ('v4' as of this writing). Information about drafting and
 | 
						|
submitting PRs can be found at:
 | 
						|
 | 
						|
    https://help.github.com/en/articles/about-pull-requests
 | 
						|
 | 
						|
 | 
						|
PULL REQUEST CHECKLIST:
 | 
						|
Before submitting a pull request, the following guidelines should be
 | 
						|
completed:
 | 
						|
 | 
						|
1) The code should compile without errors or warnings [the '-Werrors' switch
 | 
						|
   for gcc(1) is your friend here!].
 | 
						|
 | 
						|
2) Add an entry to the 'ChangeLog' file at the base of the Rivendell source
 | 
						|
   code tree, describing your changes. The format of the ChangeLog file has
 | 
						|
   the most recent changes at the bottom of the file. Entries start with a
 | 
						|
   date stamp and have a format like:
 | 
						|
 | 
						|
    YYYY-MM-DD NAME <EMAIL>
 | 
						|
    * Description of change
 | 
						|
 | 
						|
For example:
 | 
						|
    2007-02-23 John Coder <coder@example.com>
 | 
						|
	* Modified the code in 'lib/rdimport_audio.cpp' to use the
 | 
						|
	'RDCart::setMetadata()' and 'RDCut::setMetadata()' methods.
 | 
						|
 | 
						|
3) If your changes add, remove or change the behavior of one or more
 | 
						|
   configuration entries in rd.conf(5), update the default configuration
 | 
						|
   file ('conf/rd.conf-sample') accordingly. Similiarly, for PyPAD scripts,
 | 
						|
   be sure to update the corresponding '<plugin-name>-exemplar' files.
 | 
						|
 | 
						|
4) If your changes alter any user-visible aspect (UI or behavior), update
 | 
						|
   the user documentation appropriately. The documentation is written
 | 
						|
   in DocBook 5 markup, and can be found at the following locations in
 | 
						|
   the source tree:
 | 
						|
 | 
						|
   Operations Guide - 'docs/opsguide/'
 | 
						|
 | 
						|
   Manual pages - 'docs/manpages/'
 | 
						|
 | 
						|
   Internal and public APIs - 'docs/apis/'.
 | 
						|
 | 
						|
5) If you wish your work to be mentioned in the 'Credits' list displayed in
 | 
						|
   rdadmin(1), add or modify the appropriate entry in the 'AUTHORS' file.
 | 
						|
   Entries should be sorted by surname, then christian name of the author.
 | 
						|
 | 
						|
 | 
						|
QUESTIONS:
 | 
						|
Questions about coding style, or indeed any aspect of Rivendell development,
 | 
						|
are welcomed on the Rivendell-prog mailing list. Subscription information
 | 
						|
and list archives are available at:
 | 
						|
 | 
						|
    http://caspian.paravelsystems.com/mailman/listinfo/rivendell-prog
 |