diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index af533531..5af2f7aa 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -127,6 +127,7 @@ jobs: exit 1 fi fi + ./sources/$binname -vv - name: Upload binary as artifact if: steps.check-portability.outcome == 'success' && steps.check-portability.conclusion == 'success' diff --git a/doc/form.1 b/doc/form.1 index 26f0b620..b62c3d17 100644 --- a/doc/form.1 +++ b/doc/form.1 @@ -96,6 +96,9 @@ the program. .BR "-v" Only the version will be printed. The program terminates immediately after it. .TP +.BR "-vv" +Same as \fB-v\fR, but additionally prints a list indicating which features are supported. +.TP .BR "-w" This should be followed immediately by a number without any space. The number indicates the number of worker threads for \fBtform\fR. All other versions of diff --git a/doc/manual/startup.tex b/doc/manual/startup.tex index cf9765e1..4b56d0d4 100644 --- a/doc/manual/startup.tex +++ b/doc/manual/startup.tex @@ -62,6 +62,8 @@ \chapter{Running FORM} information see the "On TotalSize;" statement~\ref{ontotalsize}. \item[-v] Only the version will be printed. The program terminates immediately after it. +\item[-vv] Same as -v, but additionally prints a list indicating + which features are supported. \item[-w] This should be followed immediately by a number. The number indicates the number of worker threads for \TFORM\@. All other versions of \FORM\ ignore this parameter. It should be noted that \TFORM\ diff --git a/sources/Makefile.am b/sources/Makefile.am index 01ea914c..ec0e5cfe 100644 --- a/sources/Makefile.am +++ b/sources/Makefile.am @@ -15,6 +15,7 @@ SRCBASE = \ execute.c \ extcmd.c \ factor.c \ + features.cc \ findpat.c \ form3.h \ fsizes.h \ diff --git a/sources/declare.h b/sources/declare.h index cc0f2c2e..119f1f90 100644 --- a/sources/declare.h +++ b/sources/declare.h @@ -671,6 +671,7 @@ extern int Product(UWORD *,WORD *,WORD); extern void PrtLong(UWORD *,WORD,UBYTE *); extern void PrtTerms(void); extern void PrintDeprecation(const char *,const char *); +extern void PrintFeatureList(void); extern void PrintRunningTime(void); extern LONG GetRunningTime(void); extern int PutBracket(PHEAD WORD *); diff --git a/sources/features.cc b/sources/features.cc new file mode 100644 index 00000000..a24f554d --- /dev/null +++ b/sources/features.cc @@ -0,0 +1,212 @@ +/** @file features.cc + * + * Utility code for printing available features. + */ +/* #[ License : */ +/* + * Copyright (C) 1984-2026 J.A.M. Vermaseren + * When using this file you are requested to refer to the publication + * J.A.M.Vermaseren "New features of FORM" math-ph/0010025 + * This is considered a matter of courtesy as the development was paid + * for by FOM the Dutch physics granting agency and we would like to + * be able to track its scientific use to convince FOM of its value + * for the community. + * + * This file is part of FORM. + * + * FORM is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * FORM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along + * with FORM. If not, see . + */ +/* #] License : */ +// #[ Includes : + +extern "C" { +#include "form3.h" +} + +#include +#include +#include + +#ifdef WITHFLINT +#include +#endif + +#ifdef WITHGMP +#include +#endif + +#ifdef WITHMPFR +#include +#endif + +#ifdef WITHZLIB +#include +#endif + +#ifdef WITHZSTD +#include +#endif + +// #] Includes : +// #[ PrintFeatureList : + +/** + * Prints a list of strings in multiple columns to fit within the line length. + * + * @param lines List of strings to print. + */ +static void PrintMulticolumn(const std::vector& lines) +{ + const std::size_t n_lines = lines.size(); + + if ( n_lines == 0 ) return; + + const std::size_t line_len = AC.LineLength > 0 ? AC.LineLength : 79; + constexpr std::size_t max_cols = 6; + constexpr std::size_t col_spacing = 2; + + std::vector col_lens(max_cols); + + for ( std::size_t n_cols = max_cols; n_cols >= 2; n_cols-- ) { + const std::size_t n_rows = (n_lines - 1) / n_cols + 1; + + // Check whether `n_cols` columns fit within the line length. + // Columns are filled top-to-bottom, then left-to-right. + + std::fill(col_lens.begin(),col_lens.begin()+n_cols,0); + + std::size_t total_len = 0; + for ( std::size_t j = 0; j < n_cols; j++ ) { + for ( std::size_t i = 0; i < n_rows; i++ ) { + const std::size_t k = i + j * n_rows; + if ( k >= n_lines ) break; + col_lens[j] = std::max(col_lens[j],lines[k].size()); + } + total_len += col_lens[j]; + } + total_len += (n_cols - 1) * col_spacing; + + if ( total_len > line_len ) continue; + + // Output using `n_cols` columns. + + std::string line; + line.reserve(line_len); + for ( std::size_t i = 0; i < n_rows; i++ ) { + line.clear(); + for ( std::size_t j = 0; j < n_cols; j++ ) { + const std::size_t k = i + j * n_rows; + if ( k >= n_lines ) break; + line += lines[k]; + if ( j < n_cols - 1 ) { + line += std::string(col_lens[j]-lines[k].size()+col_spacing,' '); + } + } + MesPrint("%s",line.c_str()); + } + return; + } + + // Fallback to a single column. + + for ( const auto& f : lines ) { + MesPrint("%s",f.c_str()); + } +} + +/** + * Prints the list of available features. + */ +void PrintFeatureList(void) +{ + std::vector feature_list = { + +#ifdef ENABLE_BACKTRACE + "+backtrace", +#else + "-backtrace", +#endif + +#ifdef DEBUGGING + "+debugging", +#else + "-debugging", +#endif + +#ifdef WITHFLINT + "+flint=" + std::string(flint_version), +#else + "-flint", +#endif + +#ifdef WITHFLOAT + "+float", +#else + "-float", +#endif + +#ifdef WITHGMP + "+gmp=" + std::string(gmp_version), +#else + "-gmp", +#endif + +#ifdef WITHMPFR + "+mpfr=" + std::string(mpfr_get_version()), +#else + "-mpfr", +#endif + +#ifdef WITHMPI + "+mpi", +#else + "-mpi", +#endif + +#ifdef UNIX + "+posix", +#else + "-posix", +#endif + +#ifdef WITHPTHREADS + "+pthreads", +#else + "-pthreads", +#endif + +#ifdef WINDOWS + "+windows", +#else + "-windows", +#endif + +#ifdef WITHZLIB + "+zlib=" + std::string(zlibVersion()), +#else + "-zlib", +#endif + +#ifdef WITHZSTD + "+zstd=" + std::string(ZSTD_versionString()), +#else + "-zstd", +#endif + + }; + + PrintMulticolumn(feature_list); +} + +// #] PrintFeatureList : diff --git a/sources/startup.c b/sources/startup.c index db5f0da5..7f4a2a72 100644 --- a/sources/startup.c +++ b/sources/startup.c @@ -109,9 +109,12 @@ /** * Prints the header line of the output. * - * @param with_full_info True for printing also runtime information. + * @param par Controls the output mode + * (0: default, + * 1: including runtime information, + * 2: including the feature list). */ -static void PrintHeader(int with_full_info) +static void PrintHeader(int par) { #ifdef WITHMPI if ( PF.me == MASTER && !AM.silent ) { @@ -147,7 +150,7 @@ static void PrintHeader(int with_full_info) s += snprintf(s,250-(s-buffer1)," %d-bits",(WORD)(sizeof(WORD)*16)); *s = 0; */ - if ( with_full_info ) { + if ( par == 1 ) { #if defined(WITHPTHREADS) || defined(WITHMPI) #if defined(WITHPTHREADS) int nworkers = AM.totalnumberofthreads-1; @@ -200,6 +203,10 @@ static void PrintHeader(int with_full_info) MesPrint("%s",buffer1); AC.LineLength = oldLineLength; } + + if ( par == 2 ) { + PrintFeatureList(); + } } #ifdef WINDOWS PrintDeprecation("the native Windows version", "issues/623"); @@ -414,12 +421,13 @@ int DoTail(int argc, UBYTE **argv) break; case 'T': /* Print the total size used at end of job */ AM.PrintTotalSize = 1; break; - case 'v': + case 'v': /* Print version information */ + if ( s[1] == 'v' ) { + PrintHeader(2); + return(1); + } printversion:; -#ifdef WITHMPI - if ( PF.me == MASTER ) -#endif - PrintHeader(0); + PrintHeader(0); if ( onlyversion ) return(1); goto NoFile; case 'y': /* Preprocessor dumps output. No compilation. */