<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>http://try-as400.pocnet.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Heiko</id>
	<title>Try-AS/400 - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="http://try-as400.pocnet.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Heiko"/>
	<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/wiki/Special:Contributions/Heiko"/>
	<updated>2026-04-15T08:12:27Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.8</generator>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=Query_database_using_ODBC_from_a_linux_machine&amp;diff=873</id>
		<title>Query database using ODBC from a linux machine</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=Query_database_using_ODBC_from_a_linux_machine&amp;diff=873"/>
		<updated>2020-05-19T15:17:39Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* PHP Code using ODBC */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{FIXME|Rephrase, reformat, set links and wade out unneccessary stuff. Maybe move to user&#039;s subpage?}}&lt;br /&gt;
Accessing a AS/400 via ODBC is something that might come in handy some day, so I decided to explore how it can be done.&lt;br /&gt;
&lt;br /&gt;
Be warned: This is more like a log, showing (and hopefully solving) all issues I ran into doing this. I think this is more helpful than a ideal world example.&lt;br /&gt;
&lt;br /&gt;
== Create a database ==&lt;br /&gt;
I suggest you try [[99 Bottles of Beer (using REXX)]] and [[Hello World (using database, display file and RPG)]] before you try this!&amp;lt;ref&amp;gt;[[User:Heiko|Heiko]] made this pretty brief, f.e. not every &amp;lt;code&amp;gt;F3&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;&amp;amp;#x23CE;&amp;lt;/code&amp;gt; is noted.&amp;lt;/ref&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Create a database to play with ===&lt;br /&gt;
* This is the third project [[User:Heiko|Heiko]] did, so his personal Library was getting a bit cluttered. Therefore, let&#039;s create a library just for this niew project:&lt;br /&gt;
** &amp;lt;code&amp;gt;CRTLIB LIB(ODBC) TEXT(Library for ODBC project source)&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;CRTSRCPF FILE(ODBC/ODBCDB) RCDLEN(112) TEXT(&#039;Project ODBC and Database&#039;)&amp;lt;/code&amp;gt; to create new physical file to hold the DDS.&lt;br /&gt;
* &amp;lt;code&amp;gt;WRKMBRPDM FILE(ODBC/ODBCDB)&amp;lt;/code&amp;gt; Work with this file.&lt;br /&gt;
* &amp;lt;code&amp;gt;F6&amp;lt;/code&amp;gt; to create new member, insert member&#039;s name &amp;lt;code&amp;gt;ODBCDB&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;This wil change later. Read on...&amp;lt;/ref&amp;gt; and the type &amp;lt;code&amp;gt;PF&amp;lt;/code&amp;gt;:&amp;lt;br/&amp;gt;[[Image:ODBCDB01.png|666px]]&lt;br /&gt;
* Enter this DDS: ([https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/rzakc/rzakcdatel.htm Learn what the below means] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzasb/cpdtex.htm Especially time- and dateformats] [https://www.db2tutorial.com/db2-basics/db2-time/ Even more about wibbly-wobbly-timey-wimey-stuff] [https://www.ibm.com/support/knowledgecenter/en/SSEPEK_11.0.0/intro/src/tpc/db2z_datetimetimestamp.html and more])&lt;br /&gt;
         ***************** Datenanfang *******************************************************************************************&lt;br /&gt;
 0001.00      A          R CALLS                                                                                  191002          &lt;br /&gt;
 0002.00      A            CALLER        42A                                                                      191002          &lt;br /&gt;
 0003.00      A            CALLED        42A                                                                      191002          &lt;br /&gt;
 0004.00      A            DATE            L                TIMFMT(*ISO)                                          191002          &lt;br /&gt;
 0005.00      A            TIME            T                                                                      191002          &lt;br /&gt;
 0006.00      A            TIMESTAMP       Z                                                                      191002          &lt;br /&gt;
         ******************Datenende *********************************************************************************************&lt;br /&gt;
* &amp;lt;code&amp;gt;14&amp;lt;/code&amp;gt; to compile&amp;amp;#x2026;&amp;lt;br/&amp;gt;[[Image:ODBCDB02.png|666px]]&amp;lt;br/&amp;gt;&amp;amp;#x2026;I failed again. Stupid me. I can&#039;t create a new physical database file in the same place, where source physical file (with the same name!) exists.&lt;br /&gt;
** Just rename the DDS member from &amp;lt;code&amp;gt;ODBCDB&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;ODBCDBPF&amp;lt;/code&amp;gt;:&amp;lt;br/&amp;gt;[[Image:ODBCDB03.png|666px]]&amp;lt;br/&amp;gt;[[Image:ODBCDB04.png|666px]]&lt;br /&gt;
** And try again.&lt;br /&gt;
** Check with &amp;lt;code&amp;gt;DSPMSG&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;or use [[Compile Sources Without Queuing]]&amp;lt;/ref&amp;gt; whether the compile was successful or not. If it did, you find the new PF in the library:&amp;lt;br/&amp;gt;[[Image:ODBCDB10.png|666px]]&lt;br /&gt;
&lt;br /&gt;
=== Insert content into the database ===&lt;br /&gt;
* &amp;lt;code&amp;gt;STRSQL&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;F4&amp;lt;/code&amp;gt;&lt;br /&gt;
** Enter the library name, in this example &amp;lt;code&amp;gt;ODBC&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Shortcut: &amp;lt;code&amp;gt;STRSQL LIBOPT(ODBC)&amp;lt;/code&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
* In the interactive SQL session, enter:&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;INSERT INTO CALLS (CALLER, CALLED, DATE, TIME, TIMESTAMP) VALUES (&#039;Ernie&#039;, &#039;Bert&#039;, &#039;2019-10-05&#039;, &#039;23.23&#039;, &#039;2019-10-05 23:23:42&#039;)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Timestamp format: https://www.ibm.com/support/knowledgecenter/SSFMBX/com.ibm.swg.im.dashdb.sql.ref.doc/doc/r0007107.html&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;You can use either &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;:&amp;lt;/code&amp;gt; as delimiter in time fields. The proper way, according to the documentation I found, is: &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
* There are many ways to display the result:&lt;br /&gt;
** If you&#039;re still in STRSQL, enter: &amp;lt;code&amp;gt;SELECT * FROM CALLS&amp;lt;/code&amp;gt;&lt;br /&gt;
** On command line, try this: &amp;lt;code&amp;gt;DSPF FILE(ODBC/ODBCDBPF)&amp;lt;/code&amp;gt;&lt;br /&gt;
** Or use &amp;lt;code&amp;gt;STRDFU&amp;lt;/code&amp;gt;, select option 5 and fill out the displayed form&lt;br /&gt;
[[Image:ODBC_DSPF01.png|666px|Displayed using &amp;lt;code&amp;gt;DSPF&amp;lt;/code&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
== ODBC Queries ==&lt;br /&gt;
Make sure you&#039;ve set up your ODBC connection (&amp;lt;tt&amp;gt;/etc/odbc.ini&amp;lt;/tt&amp;gt;) correctly.&lt;br /&gt;
&lt;br /&gt;
=== Perl ===&lt;br /&gt;
Here is a nice [https://www.ibm.com/developerworks/data/library/techarticle/dm-0512greenstein/index.html HowTo] from IBM. Worth reading.&lt;br /&gt;
==== Script Source Code ====&lt;br /&gt;
 #!/usr/bin/perl&lt;br /&gt;
 use strict;&lt;br /&gt;
 use DBI;&lt;br /&gt;
 &lt;br /&gt;
 my $db_cfg=&amp;quot;YOURCONFIG&amp;quot;; # See your /etc/odbc.ini&lt;br /&gt;
 my $db_pwd=&amp;quot;YOURUSER&amp;quot;;&lt;br /&gt;
 my $db_user=&amp;quot;YOURPASSWORD&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 printf(&amp;quot;Connecting to source database on $db_cfg...\n&amp;quot;);&lt;br /&gt;
 my $dbh = DBI-&amp;gt;connect(&#039;DBI:ODBC:&#039; . $db_cfg, $db_user, $db_pwd, {PrintError =&amp;gt; 1, AutoCommit =&amp;gt; 1}); # Connecting to Db2 database&lt;br /&gt;
 if ( $dbh )&lt;br /&gt;
 {&lt;br /&gt;
 	my $sth = $dbh-&amp;gt;prepare (&amp;quot;SELECT * FROM ODBC/ODBCDBPF&amp;quot;);&lt;br /&gt;
 	if (!$sth-&amp;gt;execute)&lt;br /&gt;
 	{&lt;br /&gt;
 		printf(&amp;quot;Error: Preparing select on source failed.\n&amp;quot;);&lt;br /&gt;
 		die;&lt;br /&gt;
 	}&lt;br /&gt;
 	&lt;br /&gt;
 	my $fCaller; &lt;br /&gt;
 	my $fCalled;&lt;br /&gt;
 	my $fDate;&lt;br /&gt;
 	my $fTime;&lt;br /&gt;
 	my $fTS;	&lt;br /&gt;
 	while ( ($fCaller, $fCalled, $fDate, $fTime, $fTS) = $sth-&amp;gt;fetchrow ) # Read one row from source table&lt;br /&gt;
 	{&lt;br /&gt;
 		printf(&amp;quot;%s, %s, %s, %s, %s\n&amp;quot;, $fCaller, $fCalled, $fDate, $fTime, $fTS);&lt;br /&gt;
 	} &lt;br /&gt;
 &lt;br /&gt;
 	# Clean up last statements&lt;br /&gt;
 	$sth-&amp;gt;finish;&lt;br /&gt;
 &lt;br /&gt;
 	# Disconnect from database&lt;br /&gt;
 	if ( $dbh )&lt;br /&gt;
 	{&lt;br /&gt;
 		print(&amp;quot;Disconnecting from $db_cfg...\n&amp;quot;);&lt;br /&gt;
 		$dbh-&amp;gt;disconnect;&lt;br /&gt;
 	}&lt;br /&gt;
 }&lt;br /&gt;
 else&lt;br /&gt;
 {&lt;br /&gt;
 	printf(&amp;quot;Error: Connection to database (%s) failed:\n%s\n%s\n%s\n&amp;quot;, $db_cfg,	$DBI::err, $DBI::errstr, $DBI::state);&lt;br /&gt;
 	die;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
 $ ./as400-odbc.pl &lt;br /&gt;
 Connecting to source database on YOURCONFIG...&lt;br /&gt;
 Ernie                                      Bert                                       2019-10-05 23:24:00 2019-10-05 23:23:42.000000&lt;br /&gt;
 Bob                                        Heppo                                      2019-11-06 05:05:05 2019-10-05 23:23:42.000000&lt;br /&gt;
 Disconnecting from YOURCONFIG...&lt;br /&gt;
&lt;br /&gt;
=== PHP ===&lt;br /&gt;
I found several possible approaches:&lt;br /&gt;
* Use &amp;lt;code&amp;gt;odbc_&amp;lt;/code&amp;gt; command set&lt;br /&gt;
** [https://www.ibm.com/developerworks/library/os-php-odbc/index.html HowTo use PHP and ODBC]&amp;lt;ref&amp;gt;Sadly this is for mySQL. Db2 would be much more appreciated.&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Use &amp;lt;tt&amp;gt;PDO&amp;lt;/tt&amp;gt;&lt;br /&gt;
** [https://www.php.net/manual/en/ref.pdo-ibm.php Short Overview] &#039;&#039;&#039;&#039;&#039;@PoC: Is this compatible???&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
* Use Db2 driver &#039;&#039;&#039;&#039;&#039;@PoC: Is this compatible???&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
** [https://www.ibm.com/support/knowledgecenter/en/SS6NHC/com.ibm.swg.im.dashdb.doc/connecting/connect_driver_package.html Db2 client] &amp;amp; [https://public.dhe.ibm.com/ibmdl/export/pub/software/data/db2/drivers/odbc_cli/ direct link]&lt;br /&gt;
** [https://github.com/php/pecl-database-ibm_db2 Installation instructions]&lt;br /&gt;
** [https://www.php.net/manual/en/function.db2-connect.php Usage] and after client installation: &amp;lt;code&amp;gt;TBD -h&amp;lt;/code&amp;gt; might help!&lt;br /&gt;
&lt;br /&gt;
==== PHP Code using ODBC ====&lt;br /&gt;
Let me say right away, that didn&#039;t work out as easy as I hoped.&lt;br /&gt;
 &amp;lt;?php&lt;br /&gt;
 &lt;br /&gt;
 /* Sample Code: How to query a Db2 database on a AS/400 (iSeries) &lt;br /&gt;
  * Note:        apt-get install php-odbc might be necessary&lt;br /&gt;
  * About:       https://try-as400.pocnet.net&lt;br /&gt;
  * */&lt;br /&gt;
 &lt;br /&gt;
 $db_cfg=&amp;quot;YOURCONFIG&amp;quot;; # See your /etc/odbc.ini&lt;br /&gt;
 $db_user=&amp;quot;YOURUSER&amp;quot;;&lt;br /&gt;
 $db_pwd=&amp;quot;YOURPASSWORD&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 $dbh=odbc_connect($db_cfg, $db_user, $db_pwd);&lt;br /&gt;
 if ($dbh)&lt;br /&gt;
 {&lt;br /&gt;
 	$sql=&amp;quot;SELECT * FROM ODBC/ODBCDBPF&amp;quot;;&lt;br /&gt;
 	printf(&amp;quot;Preparing \&amp;quot;$sql\&amp;quot;...\n&amp;quot;);&lt;br /&gt;
 	$sth=odbc_prepare($dbh, $sql);&lt;br /&gt;
&lt;br /&gt;
As you can see, the source isn&#039;t complete. That&#039;s because I wasn&#039;t able to execute it any further. Output so far:&lt;br /&gt;
 Preparing &amp;quot;SELECT * FROM ODBC/ODBCDBPF&amp;quot;...&lt;br /&gt;
 &lt;br /&gt;
 mmap() failed: [12] Cannot allocate memory&lt;br /&gt;
 &lt;br /&gt;
 PHP Fatal error:  Out of memory (allocated 2097152) (tried to allocate 206158430251 bytes)&lt;br /&gt;
The driver seems to need 206158430251 bytes, that&#039;s 192GB, a bit greedy for my taste.&lt;br /&gt;
&lt;br /&gt;
After some research&amp;lt;ref&amp;gt;php-mmap-issue: https://stackoverflow.com/questions/42132558/odbc-prepare-gives-fatal-error-allowed-memory-size-exhausted&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;php-mmap-issue: https://stackoverflow.com/questions/21286589/linux-odbc-fatal-error-allowed-memory-size/21412667#21412667&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;unixodbc-32/64bit drivers: http://www.unixodbc.org/doc/db2.html&amp;lt;/ref&amp;gt;I&#039;m pretty sure, its old 32bit ODBC-drivers conflicting with 64bit PHP&amp;lt;ref&amp;gt;Oddly, the same drivers work with perl&amp;lt;/ref&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
UPDATE: Installing an newer driver fixed this problem. Unfortunately it has another flaw: If a query result contains an [https://en.wikipedia.org/wiki/Umlaut german umlaut], &amp;lt;code&amp;gt;odbc_fetch_array()&amp;lt;/code&amp;gt; causes an &amp;lt;tt&amp;gt;segmentation fault&amp;lt;/tt&amp;gt;. After some digging I used &amp;lt;code&amp;gt;setlocale (LC_ALL, &#039;de_DE&#039;);&amp;lt;/code&amp;gt; to get it working.&lt;br /&gt;
&lt;br /&gt;
==== PHP Code using DB2 client ====&lt;br /&gt;
That wasn&#039;t very smooth, either.&lt;br /&gt;
&lt;br /&gt;
I first installed some software:&lt;br /&gt;
* Get IBM&#039;s CLI driver: https://public.dhe.ibm.com/ibmdl/export/pub/software/data/db2/drivers/odbc_cli/ and move it to /home/clidriver&lt;br /&gt;
* Insert this into .bashrc:&lt;br /&gt;
 # CLI Driver (PHP -&amp;gt; Db2 (AS/400),&lt;br /&gt;
 export IBM_DB_HOME=/home/clidriver&lt;br /&gt;
 export LD_LIBRARY_PATH=${IBM_DB_HOME}/lib&lt;br /&gt;
 export PATH=${IBM_DB_HOME}/bin:$PATH&lt;br /&gt;
* apt-get install php-dev&lt;br /&gt;
* pecl install ibm_db2&lt;br /&gt;
* add extension=ibm_db2.so to /etc/php/7.0/cli/php.ini&lt;br /&gt;
* If used with apache (untested):&lt;br /&gt;
** add LD_LIBRARY_PATH as shown above to httpd.conf&lt;br /&gt;
** add extension=ibm_db2.so to /etc/php/7.0/apache2/php.ini&lt;br /&gt;
** Beyond: https://www.php.net/manual/en/ibm-db2.installation.php || https://github.com/php/pecl-database-ibm_db2 || https://public.dhe.ibm.com/ibmdl/export/pub/software/data/db2/drivers/odbc_cli/&lt;br /&gt;
&lt;br /&gt;
 $db_user=&amp;quot;YOURUSER&amp;quot;;&lt;br /&gt;
 $db_pwd=&amp;quot;YOURPASSWORT&amp;quot;;&lt;br /&gt;
 $db_db = &#039;ODBC&#039;;&lt;br /&gt;
 $db_hostname = &#039;silverlake.intern.mathpeter.com&#039;;&lt;br /&gt;
 $db_port = 8471; //50000; /* https://www.ibm.com/support/pages/tcpip-ports-required-ibm-i-access-and-related-functions */&lt;br /&gt;
 $db_options = array(&#039;autocommit&#039; =&amp;gt; DB2_AUTOCOMMIT_ON);&lt;br /&gt;
 &lt;br /&gt;
 ini_set(&amp;quot;display_errors&amp;quot;, 1);&lt;br /&gt;
 &lt;br /&gt;
 //$connectionString = &amp;quot;DRIVER={IBM DB2 ODBC DRIVER};DATABASE=$db_db;HOSTNAME=$db_hostname;PORT=$db_port;PROTOCOL=TCPIP;UID=$db_user;PWD=$db_pwd;&amp;quot;; // takes for ever to connect&lt;br /&gt;
 $connectionString = &amp;quot;DATABASE=$db_db;HOSTNAME=$db_hostname;PORT=$db_port;PROTOCOL=TCPIP;UID=$db_user;PWD=$db_pwd;&amp;quot;; // takes for ever to connect&lt;br /&gt;
 printf(&amp;quot;connectionString: $connectionString\n&amp;quot;);&lt;br /&gt;
 $dbh=db2_connect($connectionString, NULL, NULL, $db_options); // https://www.php.net/manual/en/function.db2-connect.php &lt;br /&gt;
&lt;br /&gt;
This code stalls at &amp;lt;code&amp;gt;db2_connect()&amp;lt;/code&amp;gt;. &amp;lt;tt&amp;gt;netstat&amp;lt;/tt&amp;gt; shows that the TCP-connection is &amp;lt;tt&amp;gt;ESTABLISHED&amp;lt;/tt&amp;gt;. It doesn&#039;t create heavy load or traffic. It doesn&#039;t run into a timeout.&lt;br /&gt;
&lt;br /&gt;
STAY TUNED - MAYBE I CAN GET THIS WORKING.&lt;br /&gt;
&lt;br /&gt;
==== PHP Code using PDO ====&lt;br /&gt;
TBD&lt;br /&gt;
&lt;br /&gt;
=== C ===&lt;br /&gt;
Nice to know:&lt;br /&gt;
* http://www.unixodbc.org&lt;br /&gt;
* http://www.unixodbc.org/doc/db2.html&lt;br /&gt;
* https://www.easysoft.com/developer/interfaces/odbc/linux.html&lt;br /&gt;
* https://www.easysoft.com/developer/languages/c/odbc_tutorial.html&lt;br /&gt;
* https://stackoverflow.com/questions/33020646/gcc-odbc-on-linux-is-not-linking&lt;br /&gt;
* You might need to install &amp;lt;tt&amp;gt;unixodbc-dev&amp;lt;/tt&amp;gt;&lt;br /&gt;
==== C Source Code ====&lt;br /&gt;
 /* File: as400-odbc.c&lt;br /&gt;
 * About: Learn more here: https://try-as400.pocnet.net&lt;br /&gt;
 */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;sql.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;sqlext.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 #define RESULT_LEN  256&lt;br /&gt;
 &lt;br /&gt;
 char *odbcConnectionString = &amp;quot;DSN=YOURCONFIG;UID=YOURLOGIN;PWD=YOURPASSWORD;&amp;quot;; // See /etc/odbc.ini for DSN, use your AS/400 account as credentials.&lt;br /&gt;
 &lt;br /&gt;
 #define CHECK_ERROR(e, s, h, t)\&lt;br /&gt;
 	(\&lt;br /&gt;
 		{\&lt;br /&gt;
 			if (e!=SQL_SUCCESS &amp;amp;&amp;amp; e != SQL_SUCCESS_WITH_INFO)\&lt;br /&gt;
 			{ extract_error(s, h, t); goto exit;}\&lt;br /&gt;
 		}\&lt;br /&gt;
 	)&lt;br /&gt;
 &lt;br /&gt;
 void extract_error(char *fn, SQLHANDLE handle, SQLSMALLINT type)&lt;br /&gt;
 {&lt;br /&gt;
 	SQLINTEGER i = 0;&lt;br /&gt;
 	SQLINTEGER NativeError;&lt;br /&gt;
 	SQLCHAR SQLState[7];&lt;br /&gt;
 	SQLCHAR MessageText[256];&lt;br /&gt;
 	SQLSMALLINT TextLength;&lt;br /&gt;
 	SQLRETURN ret;&lt;br /&gt;
 &lt;br /&gt;
 	fprintf(stderr, &amp;quot;\nThe driver reported the following error %s\n&amp;quot;, fn);&lt;br /&gt;
 	do&lt;br /&gt;
  	{&lt;br /&gt;
 		ret = SQLGetDiagRec(type, handle, ++i, SQLState, &amp;amp;NativeError,&lt;br /&gt;
 			MessageText, sizeof(MessageText), &amp;amp;TextLength);&lt;br /&gt;
 		if (SQL_SUCCEEDED(ret)) {&lt;br /&gt;
 			printf(&amp;quot;%s:%ld:%ld:%s\n&amp;quot;,&lt;br /&gt;
 				SQLState, (long)i, (long)NativeError, MessageText);&lt;br /&gt;
 		}&lt;br /&gt;
 	} while (ret == SQL_SUCCESS); &lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 int main()&lt;br /&gt;
 {&lt;br /&gt;
 &lt;br /&gt;
 	SQLHENV   henv = SQL_NULL_HENV;    // Environment&lt;br /&gt;
 	SQLHDBC   hdbc = SQL_NULL_HDBC;    // Connection handle&lt;br /&gt;
 	SQLHSTMT  hstmt = SQL_NULL_HSTMT;  // Statement handle&lt;br /&gt;
 	SQLRETURN retcode;&lt;br /&gt;
 	SQLCHAR   fCaller[RESULT_LEN];&lt;br /&gt;
 	SQLCHAR   fCalled[RESULT_LEN];&lt;br /&gt;
 	SQLCHAR   fDate[RESULT_LEN];&lt;br /&gt;
 	SQLCHAR   fTime[RESULT_LEN];&lt;br /&gt;
 	SQLCHAR   fTS[RESULT_LEN];&lt;br /&gt;
 	SQLCHAR   outstr[1024];&lt;br /&gt;
 	SQLSMALLINT outstrlen;&lt;br /&gt;
 	int i = 0;&lt;br /&gt;
 &lt;br /&gt;
 	// Allocate environment handle&lt;br /&gt;
 	retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &amp;amp;henv);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLAllocHandle(SQL_HANDLE_ENV)&amp;quot;, henv, SQL_HANDLE_ENV);&lt;br /&gt;
 &lt;br /&gt;
 	// Set the ODBC version environment attribute&lt;br /&gt;
 	retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLSetEnvAttr(SQL_ATTR_ODBC_VERSION)&amp;quot;, henv, SQL_HANDLE_ENV);&lt;br /&gt;
 &lt;br /&gt;
 	retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLSetEnvAttr(SQL_ATTR_ODBC_VERSION)&amp;quot;, henv, SQL_HANDLE_ENV);&lt;br /&gt;
 &lt;br /&gt;
 	// Allocate connection handle&lt;br /&gt;
 	retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &amp;amp;hdbc);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLAllocHandle(SQL_HANDLE_DBC)&amp;quot;, hdbc, SQL_HANDLE_DBC);&lt;br /&gt;
 &lt;br /&gt;
 	// Set login timeout to 5 seconds&lt;br /&gt;
 	SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLSetConnectAttr(SQL_LOGIN_TIMEOUT)&amp;quot;, hdbc, SQL_HANDLE_DBC);&lt;br /&gt;
 &lt;br /&gt;
 	// Connect to data source, replace with your connection string&lt;br /&gt;
 	retcode = SQLDriverConnect(hdbc, NULL, odbcConnectionString, SQL_NTS, outstr, sizeof(outstr), &amp;amp;outstrlen, SQL_DRIVER_NOPROMPT);&lt;br /&gt;
 &lt;br /&gt;
 	// Allocate statement handle&lt;br /&gt;
 	retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &amp;amp;hstmt);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLAllocHandle(SQL_HANDLE_STMT)&amp;quot;,	hstmt, SQL_HANDLE_STMT);&lt;br /&gt;
 &lt;br /&gt;
 	// Execute SQL Query&lt;br /&gt;
 	retcode = SQLExecDirect(hstmt, (SQLCHAR*) &amp;quot;SELECT * FROM ODBC/ODBCDBPF&amp;quot;, SQL_NTS);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLExecDirect()&amp;quot;, hstmt, SQL_HANDLE_STMT);&lt;br /&gt;
 &lt;br /&gt;
 	// Bind columns&lt;br /&gt;
 	retcode = SQLBindCol(hstmt, 1, SQL_C_CHAR, &amp;amp;fCaller, RESULT_LEN, 0);&lt;br /&gt;
 	retcode = SQLBindCol(hstmt, 2, SQL_C_CHAR, &amp;amp;fCalled, RESULT_LEN, 0);&lt;br /&gt;
 	retcode = SQLBindCol(hstmt, 3, SQL_C_CHAR, &amp;amp;fDate, RESULT_LEN, 0);&lt;br /&gt;
 	retcode = SQLBindCol(hstmt, 4, SQL_C_CHAR, &amp;amp;fTime, RESULT_LEN, 0);&lt;br /&gt;
 	retcode = SQLBindCol(hstmt, 5, SQL_C_CHAR, &amp;amp;fTS, RESULT_LEN, 0);&lt;br /&gt;
 &lt;br /&gt;
 	// Fetch and print each row of data until SQL_NO_DATA returned.&lt;br /&gt;
 	for (i = 0; ; i++)&lt;br /&gt;
 	{&lt;br /&gt;
 		retcode = SQLFetch(hstmt);&lt;br /&gt;
 		if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)&lt;br /&gt;
 		{&lt;br /&gt;
 			printf(&amp;quot;Row %d: %s\t%s\t%s\t%s\t%s\n&amp;quot;, i, fCaller, fCalled, fDate, fTime, fTS);&lt;br /&gt;
 		}&lt;br /&gt;
 		else&lt;br /&gt;
 		{&lt;br /&gt;
 			if (retcode != SQL_NO_DATA)&lt;br /&gt;
 			{&lt;br /&gt;
 				CHECK_ERROR(retcode, &amp;quot;SQLFetch()&amp;quot;, hstmt, SQL_HANDLE_STMT);&lt;br /&gt;
 			}&lt;br /&gt;
 			else&lt;br /&gt;
 			{&lt;br /&gt;
 				break;&lt;br /&gt;
 			}&lt;br /&gt;
 		}&lt;br /&gt;
 	}&lt;br /&gt;
 &lt;br /&gt;
 exit:&lt;br /&gt;
 &lt;br /&gt;
 	//&lt;br /&gt;
 	// Free handles&lt;br /&gt;
 	//&lt;br /&gt;
 	// Statement&lt;br /&gt;
 	if (hstmt != SQL_NULL_HSTMT)&lt;br /&gt;
 	{&lt;br /&gt;
 		SQLFreeHandle(SQL_HANDLE_STMT, hstmt);&lt;br /&gt;
 	}&lt;br /&gt;
 &lt;br /&gt;
 	// Connection&lt;br /&gt;
 	if (hdbc != SQL_NULL_HDBC)&lt;br /&gt;
 	{&lt;br /&gt;
 		SQLDisconnect(hdbc);&lt;br /&gt;
 		SQLFreeHandle(SQL_HANDLE_DBC, hdbc);&lt;br /&gt;
 	}&lt;br /&gt;
 &lt;br /&gt;
 	// Environment&lt;br /&gt;
 	if (henv != SQL_NULL_HENV)&lt;br /&gt;
 	{&lt;br /&gt;
 		SQLFreeHandle(SQL_HANDLE_ENV, henv);&lt;br /&gt;
 	}&lt;br /&gt;
 &lt;br /&gt;
 	return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
==== Compiling ====&lt;br /&gt;
 #!/bin/bash&lt;br /&gt;
 &lt;br /&gt;
 clear&lt;br /&gt;
 gcc as400-odbc.c -o as400-odbc_c -lodbc&lt;br /&gt;
Note the &amp;lt;code&amp;gt;-lodbc&amp;lt;/code&amp;gt; for linking against the ODBC-libraries.&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
 $./as400-odbc_c &lt;br /&gt;
 Row 0: Ernie                                     	Bert                                      	2019-10-05	23:24:00	2019-10-05 23:23:42.000000&lt;br /&gt;
 Row 1: Bob                                       	Heppo                                     	2019-11-06	05:05:05	2019-10-05 23:23:42.000000&lt;br /&gt;
 $ &lt;br /&gt;
&lt;br /&gt;
\o/&lt;br /&gt;
----&lt;br /&gt;
Footnotes and references:&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=Query_database_using_ODBC_from_a_linux_machine&amp;diff=870</id>
		<title>Query database using ODBC from a linux machine</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=Query_database_using_ODBC_from_a_linux_machine&amp;diff=870"/>
		<updated>2020-05-05T11:01:32Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* Create a database */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{FIXME|Rephrase, reformat, set links and wade out unneccessary stuff. Maybe move to user&#039;s subpage?}}&lt;br /&gt;
Accessing a AS/400 via ODBC is something that might come in handy some day, so I decided to explore how it can be done.&lt;br /&gt;
&lt;br /&gt;
Be warned: This is more like a log, showing (and hopefully solving) all issues I ran into doing this. I think this is more helpful than a ideal world example.&lt;br /&gt;
&lt;br /&gt;
== Create a database ==&lt;br /&gt;
I suggest you try [[99 Bottles of Beer (using REXX)]] and [[Hello World (using database, display file and RPG)]] before you try this!&amp;lt;ref&amp;gt;[[User:Heiko|Heiko]] made this pretty brief, f.e. not every &amp;lt;code&amp;gt;F3&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;&amp;amp;#x23CE;&amp;lt;/code&amp;gt; is noted.&amp;lt;/ref&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Create a database to play with ===&lt;br /&gt;
* This is the third project [[User:Heiko|Heiko]] did, so his personal Library was getting a bit cluttered. Therefore, let&#039;s create a library just for this niew project:&lt;br /&gt;
** &amp;lt;code&amp;gt;CRTLIB LIB(ODBC) TEXT(Library for ODBC project source)&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;CRTSRCPF FILE(ODBC/ODBCDB) RCDLEN(112) TEXT(&#039;Project ODBC and Database&#039;)&amp;lt;/code&amp;gt; to create new physical file to hold the DDS.&lt;br /&gt;
* &amp;lt;code&amp;gt;WRKMBRPDM FILE(ODBC/ODBCDB)&amp;lt;/code&amp;gt; Work with this file.&lt;br /&gt;
* &amp;lt;code&amp;gt;F6&amp;lt;/code&amp;gt; to create new member, insert member&#039;s name &amp;lt;code&amp;gt;ODBCDB&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;This wil change later. Read on...&amp;lt;/ref&amp;gt; and the type &amp;lt;code&amp;gt;PF&amp;lt;/code&amp;gt;:&amp;lt;br/&amp;gt;[[Image:ODBCDB01.png|666px]]&lt;br /&gt;
* Enter this DDS: ([https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/rzakc/rzakcdatel.htm Learn what the below means] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzasb/cpdtex.htm Especially time- and dateformats] [https://www.db2tutorial.com/db2-basics/db2-time/ Even more about wibbly-wobbly-timey-wimey-stuff] [https://www.ibm.com/support/knowledgecenter/en/SSEPEK_11.0.0/intro/src/tpc/db2z_datetimetimestamp.html and more])&lt;br /&gt;
         ***************** Datenanfang *******************************************************************************************&lt;br /&gt;
 0001.00      A          R CALLS                                                                                  191002          &lt;br /&gt;
 0002.00      A            CALLER        42A                                                                      191002          &lt;br /&gt;
 0003.00      A            CALLED        42A                                                                      191002          &lt;br /&gt;
 0004.00      A            DATE            L                TIMFMT(*ISO)                                          191002          &lt;br /&gt;
 0005.00      A            TIME            T                                                                      191002          &lt;br /&gt;
 0006.00      A            TIMESTAMP       Z                                                                      191002          &lt;br /&gt;
         ******************Datenende *********************************************************************************************&lt;br /&gt;
* &amp;lt;code&amp;gt;14&amp;lt;/code&amp;gt; to compile&amp;amp;#x2026;&amp;lt;br/&amp;gt;[[Image:ODBCDB02.png|666px]]&amp;lt;br/&amp;gt;&amp;amp;#x2026;I failed again. Stupid me. I can&#039;t create a new physical database file in the same place, where source physical file (with the same name!) exists.&lt;br /&gt;
** Just rename the DDS member from &amp;lt;code&amp;gt;ODBCDB&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;ODBCDBPF&amp;lt;/code&amp;gt;:&amp;lt;br/&amp;gt;[[Image:ODBCDB03.png|666px]]&amp;lt;br/&amp;gt;[[Image:ODBCDB04.png|666px]]&lt;br /&gt;
** And try again.&lt;br /&gt;
** Check with &amp;lt;code&amp;gt;DSPMSG&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;or use [[Compile Sources Without Queuing]]&amp;lt;/ref&amp;gt; whether the compile was successful or not. If it did, you find the new PF in the library:&amp;lt;br/&amp;gt;[[Image:ODBCDB10.png|666px]]&lt;br /&gt;
&lt;br /&gt;
=== Insert content into the database ===&lt;br /&gt;
* &amp;lt;code&amp;gt;STRSQL&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;F4&amp;lt;/code&amp;gt;&lt;br /&gt;
** Enter the library name, in this example &amp;lt;code&amp;gt;ODBC&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Shortcut: &amp;lt;code&amp;gt;STRSQL LIBOPT(ODBC)&amp;lt;/code&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
* In the interactive SQL session, enter:&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;INSERT INTO CALLS (CALLER, CALLED, DATE, TIME, TIMESTAMP) VALUES (&#039;Ernie&#039;, &#039;Bert&#039;, &#039;2019-10-05&#039;, &#039;23.23&#039;, &#039;2019-10-05 23:23:42&#039;)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Timestamp format: https://www.ibm.com/support/knowledgecenter/SSFMBX/com.ibm.swg.im.dashdb.sql.ref.doc/doc/r0007107.html&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;You can use either &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;:&amp;lt;/code&amp;gt; as delimiter in time fields. The proper way, according to the documentation I found, is: &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
* There are many ways to display the result:&lt;br /&gt;
** If you&#039;re still in STRSQL, enter: &amp;lt;code&amp;gt;SELECT * FROM CALLS&amp;lt;/code&amp;gt;&lt;br /&gt;
** On command line, try this: &amp;lt;code&amp;gt;DSPF FILE(ODBC/ODBCDBPF)&amp;lt;/code&amp;gt;&lt;br /&gt;
** Or use &amp;lt;code&amp;gt;STRDFU&amp;lt;/code&amp;gt;, select option 5 and fill out the displayed form&lt;br /&gt;
[[Image:ODBC_DSPF01.png|666px|Displayed using &amp;lt;code&amp;gt;DSPF&amp;lt;/code&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
== ODBC Queries ==&lt;br /&gt;
Make sure you&#039;ve set up your ODBC connection (&amp;lt;tt&amp;gt;/etc/odbc.ini&amp;lt;/tt&amp;gt;) correctly.&lt;br /&gt;
&lt;br /&gt;
=== Perl ===&lt;br /&gt;
Here is a nice [https://www.ibm.com/developerworks/data/library/techarticle/dm-0512greenstein/index.html HowTo] from IBM. Worth reading.&lt;br /&gt;
==== Script Source Code ====&lt;br /&gt;
 #!/usr/bin/perl&lt;br /&gt;
 use strict;&lt;br /&gt;
 use DBI;&lt;br /&gt;
 &lt;br /&gt;
 my $db_cfg=&amp;quot;YOURCONFIG&amp;quot;; # See your /etc/odbc.ini&lt;br /&gt;
 my $db_pwd=&amp;quot;YOURUSER&amp;quot;;&lt;br /&gt;
 my $db_user=&amp;quot;YOURPASSWORD&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 printf(&amp;quot;Connecting to source database on $db_cfg...\n&amp;quot;);&lt;br /&gt;
 my $dbh = DBI-&amp;gt;connect(&#039;DBI:ODBC:&#039; . $db_cfg, $db_user, $db_pwd, {PrintError =&amp;gt; 1, AutoCommit =&amp;gt; 1}); # Connecting to Db2 database&lt;br /&gt;
 if ( $dbh )&lt;br /&gt;
 {&lt;br /&gt;
 	my $sth = $dbh-&amp;gt;prepare (&amp;quot;SELECT * FROM ODBC/ODBCDBPF&amp;quot;);&lt;br /&gt;
 	if (!$sth-&amp;gt;execute)&lt;br /&gt;
 	{&lt;br /&gt;
 		printf(&amp;quot;Error: Preparing select on source failed.\n&amp;quot;);&lt;br /&gt;
 		die;&lt;br /&gt;
 	}&lt;br /&gt;
 	&lt;br /&gt;
 	my $fCaller; &lt;br /&gt;
 	my $fCalled;&lt;br /&gt;
 	my $fDate;&lt;br /&gt;
 	my $fTime;&lt;br /&gt;
 	my $fTS;	&lt;br /&gt;
 	while ( ($fCaller, $fCalled, $fDate, $fTime, $fTS) = $sth-&amp;gt;fetchrow ) # Read one row from source table&lt;br /&gt;
 	{&lt;br /&gt;
 		printf(&amp;quot;%s, %s, %s, %s, %s\n&amp;quot;, $fCaller, $fCalled, $fDate, $fTime, $fTS);&lt;br /&gt;
 	} &lt;br /&gt;
 &lt;br /&gt;
 	# Clean up last statements&lt;br /&gt;
 	$sth-&amp;gt;finish;&lt;br /&gt;
 &lt;br /&gt;
 	# Disconnect from database&lt;br /&gt;
 	if ( $dbh )&lt;br /&gt;
 	{&lt;br /&gt;
 		print(&amp;quot;Disconnecting from $db_cfg...\n&amp;quot;);&lt;br /&gt;
 		$dbh-&amp;gt;disconnect;&lt;br /&gt;
 	}&lt;br /&gt;
 }&lt;br /&gt;
 else&lt;br /&gt;
 {&lt;br /&gt;
 	printf(&amp;quot;Error: Connection to database (%s) failed:\n%s\n%s\n%s\n&amp;quot;, $db_cfg,	$DBI::err, $DBI::errstr, $DBI::state);&lt;br /&gt;
 	die;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
 $ ./as400-odbc.pl &lt;br /&gt;
 Connecting to source database on YOURCONFIG...&lt;br /&gt;
 Ernie                                      Bert                                       2019-10-05 23:24:00 2019-10-05 23:23:42.000000&lt;br /&gt;
 Bob                                        Heppo                                      2019-11-06 05:05:05 2019-10-05 23:23:42.000000&lt;br /&gt;
 Disconnecting from YOURCONFIG...&lt;br /&gt;
&lt;br /&gt;
=== PHP ===&lt;br /&gt;
I found several possible approaches:&lt;br /&gt;
* Use &amp;lt;code&amp;gt;odbc_&amp;lt;/code&amp;gt; command set&lt;br /&gt;
** [https://www.ibm.com/developerworks/library/os-php-odbc/index.html HowTo use PHP and ODBC]&amp;lt;ref&amp;gt;Sadly this is for mySQL. Db2 would be much more appreciated.&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Use &amp;lt;tt&amp;gt;PDO&amp;lt;/tt&amp;gt;&lt;br /&gt;
** [https://www.php.net/manual/en/ref.pdo-ibm.php Short Overview] &#039;&#039;&#039;&#039;&#039;@PoC: Is this compatible???&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
* Use Db2 driver &#039;&#039;&#039;&#039;&#039;@PoC: Is this compatible???&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
** [https://www.ibm.com/support/knowledgecenter/en/SS6NHC/com.ibm.swg.im.dashdb.doc/connecting/connect_driver_package.html Db2 client] &amp;amp; [https://public.dhe.ibm.com/ibmdl/export/pub/software/data/db2/drivers/odbc_cli/ direct link]&lt;br /&gt;
** [https://github.com/php/pecl-database-ibm_db2 Installation instructions]&lt;br /&gt;
** [https://www.php.net/manual/en/function.db2-connect.php Usage] and after client installation: &amp;lt;code&amp;gt;TBD -h&amp;lt;/code&amp;gt; might help!&lt;br /&gt;
&lt;br /&gt;
==== PHP Code using ODBC ====&lt;br /&gt;
Let me say right away, that didn&#039;t work out as easy as I hoped.&lt;br /&gt;
 &amp;lt;?php&lt;br /&gt;
 &lt;br /&gt;
 /* Sample Code: How to query a Db2 database on a AS/400 (iSeries) &lt;br /&gt;
  * Note:        apt-get install php-odbc might be necessary&lt;br /&gt;
  * About:       https://try-as400.pocnet.net&lt;br /&gt;
  * */&lt;br /&gt;
 &lt;br /&gt;
 $db_cfg=&amp;quot;YOURCONFIG&amp;quot;; # See your /etc/odbc.ini&lt;br /&gt;
 $db_user=&amp;quot;YOURUSER&amp;quot;;&lt;br /&gt;
 $db_pwd=&amp;quot;YOURPASSWORD&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 $dbh=odbc_connect($db_cfg, $db_user, $db_pwd);&lt;br /&gt;
 if ($dbh)&lt;br /&gt;
 {&lt;br /&gt;
 	$sql=&amp;quot;SELECT * FROM ODBC/ODBCDBPF&amp;quot;;&lt;br /&gt;
 	printf(&amp;quot;Preparing \&amp;quot;$sql\&amp;quot;...\n&amp;quot;);&lt;br /&gt;
 	$sth=odbc_prepare($dbh, $sql);&lt;br /&gt;
&lt;br /&gt;
As you can see, the source isn&#039;t complete. That&#039;s because I wasn&#039;t able to execute it any further. Output so far:&lt;br /&gt;
 Preparing &amp;quot;SELECT * FROM ODBC/ODBCDBPF&amp;quot;...&lt;br /&gt;
 &lt;br /&gt;
 mmap() failed: [12] Cannot allocate memory&lt;br /&gt;
 &lt;br /&gt;
 PHP Fatal error:  Out of memory (allocated 2097152) (tried to allocate 206158430251 bytes)&lt;br /&gt;
The driver seems to need 206158430251 bytes, that&#039;s 192GB, a bit greedy for my taste.&lt;br /&gt;
&lt;br /&gt;
After some research&amp;lt;ref&amp;gt;php-mmap-issue: https://stackoverflow.com/questions/42132558/odbc-prepare-gives-fatal-error-allowed-memory-size-exhausted&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;php-mmap-issue: https://stackoverflow.com/questions/21286589/linux-odbc-fatal-error-allowed-memory-size/21412667#21412667&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;unixodbc-32/64bit drivers: http://www.unixodbc.org/doc/db2.html&amp;lt;/ref&amp;gt;I&#039;m pretty sure, its old 32bit ODBC-drivers conflicting with 64bit PHP&amp;lt;ref&amp;gt;Oddly, the same drivers work with perl&amp;lt;/ref&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
STAY TUNED WE ARE WORKING ON A SOLUTION.&lt;br /&gt;
&lt;br /&gt;
==== PHP Code using DB2 client ====&lt;br /&gt;
That wasn&#039;t very smooth, either.&lt;br /&gt;
&lt;br /&gt;
I first installed some software:&lt;br /&gt;
* Get IBM&#039;s CLI driver: https://public.dhe.ibm.com/ibmdl/export/pub/software/data/db2/drivers/odbc_cli/ and move it to /home/clidriver&lt;br /&gt;
* Insert this into .bashrc:&lt;br /&gt;
 # CLI Driver (PHP -&amp;gt; Db2 (AS/400),&lt;br /&gt;
 export IBM_DB_HOME=/home/clidriver&lt;br /&gt;
 export LD_LIBRARY_PATH=${IBM_DB_HOME}/lib&lt;br /&gt;
 export PATH=${IBM_DB_HOME}/bin:$PATH&lt;br /&gt;
* apt-get install php-dev&lt;br /&gt;
* pecl install ibm_db2&lt;br /&gt;
* add extension=ibm_db2.so to /etc/php/7.0/cli/php.ini&lt;br /&gt;
* If used with apache (untested):&lt;br /&gt;
** add LD_LIBRARY_PATH as shown above to httpd.conf&lt;br /&gt;
** add extension=ibm_db2.so to /etc/php/7.0/apache2/php.ini&lt;br /&gt;
** Beyond: https://www.php.net/manual/en/ibm-db2.installation.php || https://github.com/php/pecl-database-ibm_db2 || https://public.dhe.ibm.com/ibmdl/export/pub/software/data/db2/drivers/odbc_cli/&lt;br /&gt;
&lt;br /&gt;
 $db_user=&amp;quot;YOURUSER&amp;quot;;&lt;br /&gt;
 $db_pwd=&amp;quot;YOURPASSWORT&amp;quot;;&lt;br /&gt;
 $db_db = &#039;ODBC&#039;;&lt;br /&gt;
 $db_hostname = &#039;silverlake.intern.mathpeter.com&#039;;&lt;br /&gt;
 $db_port = 8471; //50000; /* https://www.ibm.com/support/pages/tcpip-ports-required-ibm-i-access-and-related-functions */&lt;br /&gt;
 $db_options = array(&#039;autocommit&#039; =&amp;gt; DB2_AUTOCOMMIT_ON);&lt;br /&gt;
 &lt;br /&gt;
 ini_set(&amp;quot;display_errors&amp;quot;, 1);&lt;br /&gt;
 &lt;br /&gt;
 //$connectionString = &amp;quot;DRIVER={IBM DB2 ODBC DRIVER};DATABASE=$db_db;HOSTNAME=$db_hostname;PORT=$db_port;PROTOCOL=TCPIP;UID=$db_user;PWD=$db_pwd;&amp;quot;; // takes for ever to connect&lt;br /&gt;
 $connectionString = &amp;quot;DATABASE=$db_db;HOSTNAME=$db_hostname;PORT=$db_port;PROTOCOL=TCPIP;UID=$db_user;PWD=$db_pwd;&amp;quot;; // takes for ever to connect&lt;br /&gt;
 printf(&amp;quot;connectionString: $connectionString\n&amp;quot;);&lt;br /&gt;
 $dbh=db2_connect($connectionString, NULL, NULL, $db_options); // https://www.php.net/manual/en/function.db2-connect.php &lt;br /&gt;
&lt;br /&gt;
This code stalls at &amp;lt;code&amp;gt;db2_connect()&amp;lt;/code&amp;gt;. &amp;lt;tt&amp;gt;netstat&amp;lt;/tt&amp;gt; shows that the TCP-connection is &amp;lt;tt&amp;gt;ESTABLISHED&amp;lt;/tt&amp;gt;. It doesn&#039;t create heavy load or traffic. It doesn&#039;t run into a timeout.&lt;br /&gt;
&lt;br /&gt;
STAY TUNED - MAYBE I CAN GET THIS WORKING.&lt;br /&gt;
&lt;br /&gt;
==== PHP Code using PDO ====&lt;br /&gt;
TBD&lt;br /&gt;
&lt;br /&gt;
=== C ===&lt;br /&gt;
Nice to know:&lt;br /&gt;
* http://www.unixodbc.org&lt;br /&gt;
* http://www.unixodbc.org/doc/db2.html&lt;br /&gt;
* https://www.easysoft.com/developer/interfaces/odbc/linux.html&lt;br /&gt;
* https://www.easysoft.com/developer/languages/c/odbc_tutorial.html&lt;br /&gt;
* https://stackoverflow.com/questions/33020646/gcc-odbc-on-linux-is-not-linking&lt;br /&gt;
* You might need to install &amp;lt;tt&amp;gt;unixodbc-dev&amp;lt;/tt&amp;gt;&lt;br /&gt;
==== C Source Code ====&lt;br /&gt;
 /* File: as400-odbc.c&lt;br /&gt;
 * About: Learn more here: https://try-as400.pocnet.net&lt;br /&gt;
 */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;sql.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;sqlext.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 #define RESULT_LEN  256&lt;br /&gt;
 &lt;br /&gt;
 char *odbcConnectionString = &amp;quot;DSN=YOURCONFIG;UID=YOURLOGIN;PWD=YOURPASSWORD;&amp;quot;; // See /etc/odbc.ini for DSN, use your AS/400 account as credentials.&lt;br /&gt;
 &lt;br /&gt;
 #define CHECK_ERROR(e, s, h, t)\&lt;br /&gt;
 	(\&lt;br /&gt;
 		{\&lt;br /&gt;
 			if (e!=SQL_SUCCESS &amp;amp;&amp;amp; e != SQL_SUCCESS_WITH_INFO)\&lt;br /&gt;
 			{ extract_error(s, h, t); goto exit;}\&lt;br /&gt;
 		}\&lt;br /&gt;
 	)&lt;br /&gt;
 &lt;br /&gt;
 void extract_error(char *fn, SQLHANDLE handle, SQLSMALLINT type)&lt;br /&gt;
 {&lt;br /&gt;
 	SQLINTEGER i = 0;&lt;br /&gt;
 	SQLINTEGER NativeError;&lt;br /&gt;
 	SQLCHAR SQLState[7];&lt;br /&gt;
 	SQLCHAR MessageText[256];&lt;br /&gt;
 	SQLSMALLINT TextLength;&lt;br /&gt;
 	SQLRETURN ret;&lt;br /&gt;
 &lt;br /&gt;
 	fprintf(stderr, &amp;quot;\nThe driver reported the following error %s\n&amp;quot;, fn);&lt;br /&gt;
 	do&lt;br /&gt;
  	{&lt;br /&gt;
 		ret = SQLGetDiagRec(type, handle, ++i, SQLState, &amp;amp;NativeError,&lt;br /&gt;
 			MessageText, sizeof(MessageText), &amp;amp;TextLength);&lt;br /&gt;
 		if (SQL_SUCCEEDED(ret)) {&lt;br /&gt;
 			printf(&amp;quot;%s:%ld:%ld:%s\n&amp;quot;,&lt;br /&gt;
 				SQLState, (long)i, (long)NativeError, MessageText);&lt;br /&gt;
 		}&lt;br /&gt;
 	} while (ret == SQL_SUCCESS); &lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 int main()&lt;br /&gt;
 {&lt;br /&gt;
 &lt;br /&gt;
 	SQLHENV   henv = SQL_NULL_HENV;    // Environment&lt;br /&gt;
 	SQLHDBC   hdbc = SQL_NULL_HDBC;    // Connection handle&lt;br /&gt;
 	SQLHSTMT  hstmt = SQL_NULL_HSTMT;  // Statement handle&lt;br /&gt;
 	SQLRETURN retcode;&lt;br /&gt;
 	SQLCHAR   fCaller[RESULT_LEN];&lt;br /&gt;
 	SQLCHAR   fCalled[RESULT_LEN];&lt;br /&gt;
 	SQLCHAR   fDate[RESULT_LEN];&lt;br /&gt;
 	SQLCHAR   fTime[RESULT_LEN];&lt;br /&gt;
 	SQLCHAR   fTS[RESULT_LEN];&lt;br /&gt;
 	SQLCHAR   outstr[1024];&lt;br /&gt;
 	SQLSMALLINT outstrlen;&lt;br /&gt;
 	int i = 0;&lt;br /&gt;
 &lt;br /&gt;
 	// Allocate environment handle&lt;br /&gt;
 	retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &amp;amp;henv);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLAllocHandle(SQL_HANDLE_ENV)&amp;quot;, henv, SQL_HANDLE_ENV);&lt;br /&gt;
 &lt;br /&gt;
 	// Set the ODBC version environment attribute&lt;br /&gt;
 	retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLSetEnvAttr(SQL_ATTR_ODBC_VERSION)&amp;quot;, henv, SQL_HANDLE_ENV);&lt;br /&gt;
 &lt;br /&gt;
 	retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLSetEnvAttr(SQL_ATTR_ODBC_VERSION)&amp;quot;, henv, SQL_HANDLE_ENV);&lt;br /&gt;
 &lt;br /&gt;
 	// Allocate connection handle&lt;br /&gt;
 	retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &amp;amp;hdbc);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLAllocHandle(SQL_HANDLE_DBC)&amp;quot;, hdbc, SQL_HANDLE_DBC);&lt;br /&gt;
 &lt;br /&gt;
 	// Set login timeout to 5 seconds&lt;br /&gt;
 	SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLSetConnectAttr(SQL_LOGIN_TIMEOUT)&amp;quot;, hdbc, SQL_HANDLE_DBC);&lt;br /&gt;
 &lt;br /&gt;
 	// Connect to data source, replace with your connection string&lt;br /&gt;
 	retcode = SQLDriverConnect(hdbc, NULL, odbcConnectionString, SQL_NTS, outstr, sizeof(outstr), &amp;amp;outstrlen, SQL_DRIVER_NOPROMPT);&lt;br /&gt;
 &lt;br /&gt;
 	// Allocate statement handle&lt;br /&gt;
 	retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &amp;amp;hstmt);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLAllocHandle(SQL_HANDLE_STMT)&amp;quot;,	hstmt, SQL_HANDLE_STMT);&lt;br /&gt;
 &lt;br /&gt;
 	// Execute SQL Query&lt;br /&gt;
 	retcode = SQLExecDirect(hstmt, (SQLCHAR*) &amp;quot;SELECT * FROM ODBC/ODBCDBPF&amp;quot;, SQL_NTS);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLExecDirect()&amp;quot;, hstmt, SQL_HANDLE_STMT);&lt;br /&gt;
 &lt;br /&gt;
 	// Bind columns&lt;br /&gt;
 	retcode = SQLBindCol(hstmt, 1, SQL_C_CHAR, &amp;amp;fCaller, RESULT_LEN, 0);&lt;br /&gt;
 	retcode = SQLBindCol(hstmt, 2, SQL_C_CHAR, &amp;amp;fCalled, RESULT_LEN, 0);&lt;br /&gt;
 	retcode = SQLBindCol(hstmt, 3, SQL_C_CHAR, &amp;amp;fDate, RESULT_LEN, 0);&lt;br /&gt;
 	retcode = SQLBindCol(hstmt, 4, SQL_C_CHAR, &amp;amp;fTime, RESULT_LEN, 0);&lt;br /&gt;
 	retcode = SQLBindCol(hstmt, 5, SQL_C_CHAR, &amp;amp;fTS, RESULT_LEN, 0);&lt;br /&gt;
 &lt;br /&gt;
 	// Fetch and print each row of data until SQL_NO_DATA returned.&lt;br /&gt;
 	for (i = 0; ; i++)&lt;br /&gt;
 	{&lt;br /&gt;
 		retcode = SQLFetch(hstmt);&lt;br /&gt;
 		if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)&lt;br /&gt;
 		{&lt;br /&gt;
 			printf(&amp;quot;Row %d: %s\t%s\t%s\t%s\t%s\n&amp;quot;, i, fCaller, fCalled, fDate, fTime, fTS);&lt;br /&gt;
 		}&lt;br /&gt;
 		else&lt;br /&gt;
 		{&lt;br /&gt;
 			if (retcode != SQL_NO_DATA)&lt;br /&gt;
 			{&lt;br /&gt;
 				CHECK_ERROR(retcode, &amp;quot;SQLFetch()&amp;quot;, hstmt, SQL_HANDLE_STMT);&lt;br /&gt;
 			}&lt;br /&gt;
 			else&lt;br /&gt;
 			{&lt;br /&gt;
 				break;&lt;br /&gt;
 			}&lt;br /&gt;
 		}&lt;br /&gt;
 	}&lt;br /&gt;
 &lt;br /&gt;
 exit:&lt;br /&gt;
 &lt;br /&gt;
 	//&lt;br /&gt;
 	// Free handles&lt;br /&gt;
 	//&lt;br /&gt;
 	// Statement&lt;br /&gt;
 	if (hstmt != SQL_NULL_HSTMT)&lt;br /&gt;
 	{&lt;br /&gt;
 		SQLFreeHandle(SQL_HANDLE_STMT, hstmt);&lt;br /&gt;
 	}&lt;br /&gt;
 &lt;br /&gt;
 	// Connection&lt;br /&gt;
 	if (hdbc != SQL_NULL_HDBC)&lt;br /&gt;
 	{&lt;br /&gt;
 		SQLDisconnect(hdbc);&lt;br /&gt;
 		SQLFreeHandle(SQL_HANDLE_DBC, hdbc);&lt;br /&gt;
 	}&lt;br /&gt;
 &lt;br /&gt;
 	// Environment&lt;br /&gt;
 	if (henv != SQL_NULL_HENV)&lt;br /&gt;
 	{&lt;br /&gt;
 		SQLFreeHandle(SQL_HANDLE_ENV, henv);&lt;br /&gt;
 	}&lt;br /&gt;
 &lt;br /&gt;
 	return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
==== Compiling ====&lt;br /&gt;
 #!/bin/bash&lt;br /&gt;
 &lt;br /&gt;
 clear&lt;br /&gt;
 gcc as400-odbc.c -o as400-odbc_c -lodbc&lt;br /&gt;
Note the &amp;lt;code&amp;gt;-lodbc&amp;lt;/code&amp;gt; for linking against the ODBC-libraries.&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
 $./as400-odbc_c &lt;br /&gt;
 Row 0: Ernie                                     	Bert                                      	2019-10-05	23:24:00	2019-10-05 23:23:42.000000&lt;br /&gt;
 Row 1: Bob                                       	Heppo                                     	2019-11-06	05:05:05	2019-10-05 23:23:42.000000&lt;br /&gt;
 $ &lt;br /&gt;
&lt;br /&gt;
\o/&lt;br /&gt;
----&lt;br /&gt;
Footnotes and references:&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=User:Heiko&amp;diff=754</id>
		<title>User:Heiko</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=User:Heiko&amp;diff=754"/>
		<updated>2020-02-23T21:44:31Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* Articles to maintain */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== About ==&lt;br /&gt;
This is [[User:Heiko|Heiko]]s personal page, in which he maybe shares some private information or collects bits for new articles.&lt;br /&gt;
&lt;br /&gt;
=== Personal Information ===&lt;br /&gt;
[[User:Heiko|Heiko]] has been in IT since the 90s, but never worked with an AS/400&amp;amp;#x2026;until 2019. He&#039;ll document his first steps in the hope they will be useful to others.&lt;br /&gt;
&lt;br /&gt;
== Ideas for new articles ==&lt;br /&gt;
tbd&lt;br /&gt;
&lt;br /&gt;
== Articles to maintain ==&lt;br /&gt;
* [[:Category:Programming]]&lt;br /&gt;
** [[99 Bottles Of Beer (using REXX)]]&lt;br /&gt;
** [[Hello World (using C)]]&lt;br /&gt;
** [[Hello World (using database, display file and RPG)]]&lt;br /&gt;
** [[Create a database and query it using ODBC from a linux machine]] &amp;lt;-- NEEDS A LOT OF WORK IN THE PHP DEPARTMENT!&lt;br /&gt;
* [[Editing Source Files using Eclipse and FTP]]&lt;br /&gt;
* [[Compile Sources Without Queuing]]&lt;br /&gt;
* [[How to solve Variadic Arguments issue (using C)]]&lt;br /&gt;
&lt;br /&gt;
== Too many F-Keys to memorize ==&lt;br /&gt;
I&#039;m using a small apple keyboard on which the F-keys aren&#039;t labeled very well. This helps a lot:&lt;br /&gt;
&lt;br /&gt;
[[Image:F-Tasten F13-F24 v2 Photo.jpg|666px]]&lt;br /&gt;
&lt;br /&gt;
You can download it here: [[File:F-Tasten F13-F24 v2.pdf]]&lt;br /&gt;
&lt;br /&gt;
== Sandbox ==&lt;br /&gt;
=== Screen mit MW-Bordmitteln ===&lt;br /&gt;
&lt;br /&gt;
                                   Anmelden            &lt;br /&gt;
                                               System  . . . . . :   SLVRLAKE&lt;br /&gt;
                                               Subsystem . . . . :   QINTER&lt;br /&gt;
                                               Bildschirm  . . . :   QPADEV0004&lt;br /&gt;
 &lt;br /&gt;
                Benutzer  . . . . . . . . . . . .             &lt;br /&gt;
                Kennwort  . . . . . . . . . . . .&lt;br /&gt;
                Programm/Prozedur . . . . . . . .             &lt;br /&gt;
                Men}  . . . . . . . . . . . . . .             &lt;br /&gt;
                Aktuelle Bibliothek . . . . . . .             &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
                                        (C) COPYRIGHT IBM CORP. 1980, 2013.&lt;br /&gt;
&lt;br /&gt;
=== Und nun Screen mit Bordmitteln und etwas HTML-Foo ===&lt;br /&gt;
&amp;lt;p style=&amp;quot;color:green; background-color:black&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
                                   Anmelden                                       &amp;lt;br/&amp;gt;&lt;br /&gt;
                                               System  . . . . . :   SLVRLAKE     &amp;lt;br/&amp;gt;&lt;br /&gt;
                                               Subsystem . . . . :   QINTER       &amp;lt;br/&amp;gt;&lt;br /&gt;
                                               Bildschirm  . . . :   QPADEV0004   &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                Benutzer  . . . . . . . . . . . .                                 &amp;lt;br/&amp;gt;&lt;br /&gt;
                Kennwort  . . . . . . . . . . . .                                 &amp;lt;br/&amp;gt;&lt;br /&gt;
                Programm/Prozedur . . . . . . . .                                 &amp;lt;br/&amp;gt;&lt;br /&gt;
                Men}  . . . . . . . . . . . . . .                                 &amp;lt;br/&amp;gt;&lt;br /&gt;
                Aktuelle Bibliothek . . . . . . .                                 &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                        (C) COPYRIGHT IBM CORP. 1980, 2013.       &amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using (not-working) console-tag ===&lt;br /&gt;
&amp;lt;console&amp;gt;&lt;br /&gt;
Test&lt;br /&gt;
&amp;lt;/console&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;console&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                                   Anmelden            &lt;br /&gt;
                                               System  . . . . . :   SLVRLAKE&lt;br /&gt;
                                               Subsystem . . . . :   QINTER&lt;br /&gt;
                                               Bildschirm  . . . :   QPADEV0004&lt;br /&gt;
 &lt;br /&gt;
                Benutzer  . . . . . . . . . . . .             &lt;br /&gt;
                Kennwort  . . . . . . . . . . . .&lt;br /&gt;
                Programm/Prozedur . . . . . . . .             &lt;br /&gt;
                Men}  . . . . . . . . . . . . . .             &lt;br /&gt;
                Aktuelle Bibliothek . . . . . . .             &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
                                        (C) COPYRIGHT IBM CORP. 1980, 2013.&lt;br /&gt;
&amp;lt;/console&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[Basic Commands]]&lt;br /&gt;
&lt;br /&gt;
== Footnotes ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=Basic_Commands&amp;diff=723</id>
		<title>Basic Commands</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=Basic_Commands&amp;diff=723"/>
		<updated>2020-01-22T10:36:00Z</updated>

		<summary type="html">&lt;p&gt;Heiko: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This article describes the basic commands for easy reference. Even more can be found at [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71 IBM&#039;s documentation].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Command&lt;br /&gt;
! Short description&lt;br /&gt;
! Link to detailed description&lt;br /&gt;
! Category&lt;br /&gt;
|-&lt;br /&gt;
| CRTSRCPF&lt;br /&gt;
| Creates a physical file for storing sources, f.&amp;amp;thinsp;e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;CRTSRCPF FILE(SOMELIBRARY/SOMEFILE) RCDLEN(112) TEXT(&#039;My file description&#039;)&amp;lt;/code &amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/ddp/rbae5crtsrcp.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| DLTF&lt;br /&gt;
| Deletes a file, f.&amp;amp;thinsp;e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DLTF FILE(SOMELIBRARY/SOMEFILE)&amp;lt;/code&amp;gt;&amp;lt;br/&amp;gt;Please note that this only deletes files like databases. Programs must be deleted using &amp;lt;code&amp;gt;DLTPGM&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/dltf.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| DLTPGM&lt;br /&gt;
| Deletes a program, f.&amp;amp;thinsp;e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DLTPGM PGM(SOMELIBRARY/SOMEPGM)&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/dltpgm.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| WRKMBRPDM&lt;br /&gt;
| Work with source files using the Programming Development Manager&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/wrkmbrpdm.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| STRSEU&lt;br /&gt;
| Starts the source code editor.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/strseu.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| SEU&lt;br /&gt;
| Source code Edit Utility&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/rzasc/hseu.htm Details]&amp;lt;br/&amp;gt;&amp;amp;#x2026;and more useful&amp;amp;#x2026;&amp;lt;br/&amp;gt;[https://as400i.com/2013/03/13/using-the-source-entry-utility-seu-as400/ Usage]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| STRREXPRC&lt;br /&gt;
| Start a REXX procedure (aka: script), f.&amp;amp;thinsp;e.:&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;STRREXPRC SRCMBR(SOMEMEMBER) SRCFILE(SOMEPHYSICALSOURCEFILE)&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/cl/strrexprc.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTPGM&lt;br /&gt;
| Creates a program from source code&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/crtpgm.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| DSPUSRPRF&lt;br /&gt;
| Shows user profile, f.&amp;amp;thinsp;e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DSPUSRPRF HKRETSCHME&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/cl/dspusrprf.htm Details]&lt;br /&gt;
| Administration&lt;br /&gt;
|-&lt;br /&gt;
| DSPMSG&lt;br /&gt;
| Displays your messages, their origin might be another user or the compiler.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/dspmsg.htm Details]&lt;br /&gt;
| Administration&lt;br /&gt;
|-&lt;br /&gt;
| STRSQL&lt;br /&gt;
| Start interactive SQL session&amp;lt;br/&amp;gt;to view or change contents of your databases.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/strsql.htm Details] and [TBD about usage]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| STRDFU&lt;br /&gt;
| Start Data File Utility.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/strdfu.htm Details]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| DSPF&lt;br /&gt;
| Display the contents of a file, f.&amp;amp;thinsp;e.:&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DSPF FILE(SOMELIB/SOMEDBFILE)&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/cl/dspf.htm Details]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| CRTDSPF&lt;br /&gt;
| Create Display Files&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/cl/crtdspf.htm Details]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| RNMOBJ&lt;br /&gt;
| Rename Object&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/rnmobj.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| MOVOBJ&lt;br /&gt;
| Moves an object, like a physical file, to another library.&amp;lt;br/&amp;gt;Example: &amp;lt;code&amp;gt;MOVOBJ OBJ(HKRETSCHME/HELLO01) OBJTYPE(*FILE) TOLIB(HELLOWRLD)&amp;lt;/code&amp;gt; for physical files, or&amp;amp;#x2026;&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;MOVOBJ OBJ(HKRETSCHME/HELLO01) OBJTYPE(*PGM) TOLIB(HELLOWRLD)&amp;lt;/code&amp;gt; &amp;amp;#x2026;for programs.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/cl/movobj.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| FNDSTRPDM&lt;br /&gt;
| Find a string in a file&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/fndstrpdm.htm Details]&lt;br /&gt;
| Files, Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTCMOD&lt;br /&gt;
| Create a module&amp;lt;ref&amp;gt;In gcc-terms &amp;quot;object&amp;quot;&amp;lt;/ref&amp;gt; from C-Source. &amp;lt;br/&amp;gt; f.&amp;amp;thinsp;e. &amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG)&amp;lt;/code&amp;gt; &lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/crtcmod.htm Details] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/rzarf/clcommands.htm General C-Compiling] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzasc/bndmodpgm.htm About 2-Step-Compiling]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTPGM&lt;br /&gt;
| Links the modules&amp;lt;ref&amp;gt;In gcc-terms &amp;quot;objects&amp;quot;&amp;lt;/ref&amp;gt; into one program.&amp;lt;br/&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzasc/crtpgm9.htm Details] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/rzarf/clcommands.htm General C-Compiling] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzasc/bndmodpgm.htm About 2-Step-Compiling]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTBNDC&lt;br /&gt;
| Creates a program from C-Source (CRTCMOD and CRT in one step). &lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/crtbndc.htm Details] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/rzarf/clcommands.htm General C-Compiling]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| CHGCURLIB&lt;br /&gt;
| Changes current Library, f.&amp;amp;thinsp;e. &amp;lt;code&amp;gt;CHGCURLIB SPLAMGMT&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_72/cl/chgcurlib.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| DSPFD&lt;br /&gt;
| Displays informations about physical files, f.&amp;amp;thinsp;e. &amp;lt;code&amp;gt;DSPFD ARTIKELPF&amp;lt;/code&amp;gt;.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_72/cl/dspfd.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| CHGPF&lt;br /&gt;
| Change Physical File. Allows to set file-specific flags without recompile, and easy recompile of existing PFs with new or changed fields. Includes a pretty good copy routine, so data isn&#039;t lost and if it would, chgpf warns with an inquiry message.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/cl/chgpf.htm Details] &lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| DSPLIB&lt;br /&gt;
| Shows contents of a specific library.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_74/cl/dsplib.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[UNIX-User&#039;s Cheater Table]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Basic Knowledge]]&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=Basic_Commands&amp;diff=722</id>
		<title>Basic Commands</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=Basic_Commands&amp;diff=722"/>
		<updated>2020-01-21T10:12:34Z</updated>

		<summary type="html">&lt;p&gt;Heiko: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This article describes the basic commands for easy reference. Even more can be found at [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71 IBM&#039;s documentation].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Command&lt;br /&gt;
! Short description&lt;br /&gt;
! Link to detailed description&lt;br /&gt;
! Category&lt;br /&gt;
|-&lt;br /&gt;
| CRTSRCPF&lt;br /&gt;
| Creates a physical file for storing sources, f.&amp;amp;thinsp;e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;CRTSRCPF FILE(SOMELIBRARY/SOMEFILE) RCDLEN(112) TEXT(&#039;My file description&#039;)&amp;lt;/code &amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/ddp/rbae5crtsrcp.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| DLTF&lt;br /&gt;
| Deletes a file, f.&amp;amp;thinsp;e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DLTF FILE(SOMELIBRARY/SOMEFILE)&amp;lt;/code&amp;gt;&amp;lt;br/&amp;gt;Please note that this only deletes files like databases. Programs must be deleted using &amp;lt;code&amp;gt;DLTPGM&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/dltf.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| DLTPGM&lt;br /&gt;
| Deletes a program, f.&amp;amp;thinsp;e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DLTPGM PGM(SOMELIBRARY/SOMEPGM)&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/dltpgm.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| WRKMBRPDM&lt;br /&gt;
| Work with source files using the Programming Development Manager&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/wrkmbrpdm.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| STRSEU&lt;br /&gt;
| Starts the source code editor.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/strseu.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| SEU&lt;br /&gt;
| Source code Edit Utility&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/rzasc/hseu.htm Details]&amp;lt;br/&amp;gt;&amp;amp;#x2026;and more useful&amp;amp;#x2026;&amp;lt;br/&amp;gt;[https://as400i.com/2013/03/13/using-the-source-entry-utility-seu-as400/ Usage]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| STRREXPRC&lt;br /&gt;
| Start a REXX procedure (aka: script), f.&amp;amp;thinsp;e.:&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;STRREXPRC SRCMBR(SOMEMEMBER) SRCFILE(SOMEPHYSICALSOURCEFILE)&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/cl/strrexprc.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTPGM&lt;br /&gt;
| Creates a program from source code&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/crtpgm.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| DSPUSRPRF&lt;br /&gt;
| Shows user profile, f.&amp;amp;thinsp;e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DSPUSRPRF HKRETSCHME&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/cl/dspusrprf.htm Details]&lt;br /&gt;
| Administration&lt;br /&gt;
|-&lt;br /&gt;
| DSPMSG&lt;br /&gt;
| Displays your messages, their origin might be another user or the compiler.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/dspmsg.htm Details]&lt;br /&gt;
| Administration&lt;br /&gt;
|-&lt;br /&gt;
| STRSQL&lt;br /&gt;
| Start interactive SQL session&amp;lt;br/&amp;gt;to view or change contents of your databases.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/strsql.htm Details] and [TBD about usage]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| STRDFU&lt;br /&gt;
| Start Data File Utility.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/strdfu.htm Details]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| DSPF&lt;br /&gt;
| Display the contents of a file, f.&amp;amp;thinsp;e.:&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DSPF FILE(SOMELIB/SOMEDBFILE)&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/cl/dspf.htm Details]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| CRTDSPF&lt;br /&gt;
| Create Display Files&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/cl/crtdspf.htm Details]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| RNMOBJ&lt;br /&gt;
| Rename Object&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/rnmobj.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| MOVOBJ&lt;br /&gt;
| Moves an object, like a physical file, to another library.&amp;lt;br/&amp;gt;Example: &amp;lt;code&amp;gt;MOVOBJ OBJ(HKRETSCHME/HELLO01) OBJTYPE(*FILE) TOLIB(HELLOWRLD)&amp;lt;/code&amp;gt; for physical files, or&amp;amp;#x2026;&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;MOVOBJ OBJ(HKRETSCHME/HELLO01) OBJTYPE(*PGM) TOLIB(HELLOWRLD)&amp;lt;/code&amp;gt; &amp;amp;#x2026;for programs.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/cl/movobj.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| FNDSTRPDM&lt;br /&gt;
| Find a string in a file&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/fndstrpdm.htm Details]&lt;br /&gt;
| Files, Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTCMOD&lt;br /&gt;
| Create a module&amp;lt;ref&amp;gt;In gcc-terms &amp;quot;object&amp;quot;&amp;lt;/ref&amp;gt; from C-Source. &amp;lt;br/&amp;gt; f.&amp;amp;thinsp;e. &amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG)&amp;lt;/code&amp;gt; &lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/crtcmod.htm Details] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/rzarf/clcommands.htm General C-Compiling] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzasc/bndmodpgm.htm About 2-Step-Compiling]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTPGM&lt;br /&gt;
| Links the modules&amp;lt;ref&amp;gt;In gcc-terms &amp;quot;objects&amp;quot;&amp;lt;/ref&amp;gt; into one program.&amp;lt;br/&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzasc/crtpgm9.htm Details] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/rzarf/clcommands.htm General C-Compiling] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzasc/bndmodpgm.htm About 2-Step-Compiling]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTBNDC&lt;br /&gt;
| Creates a program from C-Source (CRTCMOD and CRT in one step). &lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/crtbndc.htm Details] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/rzarf/clcommands.htm General C-Compiling]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| CHGCURLIB&lt;br /&gt;
| Changes current Library, f.&amp;amp;thinsp;e. &amp;lt;code&amp;gt;CHGCURLIB SPLAMGMT&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_72/cl/chgcurlib.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| DSPFD&lt;br /&gt;
| Displays informations about physical files, f.&amp;amp;thinsp;e. &amp;lt;code&amp;gt;DSPFD ARTIKELPF&amp;lt;/code&amp;gt;.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_72/cl/dspfd.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| CHGPF&lt;br /&gt;
| Change Physical File. Allows to set file-specific flags without recompile, and easy recompile of existing PFs with new or changed fields. Includes a pretty good copy routine, so data isn&#039;t lost and if it would, chgpf warns with an inquiry message.&lt;br /&gt;
| &amp;amp;thinsp;&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| DSPLIB&lt;br /&gt;
| Shows contents of a specific library.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_74/cl/dsplib.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[UNIX-User&#039;s Cheater Table]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Basic Knowledge]]&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=Basic_Commands&amp;diff=721</id>
		<title>Basic Commands</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=Basic_Commands&amp;diff=721"/>
		<updated>2020-01-21T10:12:19Z</updated>

		<summary type="html">&lt;p&gt;Heiko: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This article describes the basic commands for easy reference. Even more can be found at [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71 IBM&#039;s documentation].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Command&lt;br /&gt;
! Short description&lt;br /&gt;
! Link to detailed description&lt;br /&gt;
! Category&lt;br /&gt;
|-&lt;br /&gt;
| CRTSRCPF&lt;br /&gt;
| Creates a physical file for storing sources, f.&amp;amp;thinsp;e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;CRTSRCPF FILE(SOMELIBRARY/SOMEFILE) RCDLEN(112) TEXT(&#039;My file description&#039;)&amp;lt;/code &amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/ddp/rbae5crtsrcp.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| DLTF&lt;br /&gt;
| Deletes a file, f.&amp;amp;thinsp;e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DLTF FILE(SOMELIBRARY/SOMEFILE)&amp;lt;/code&amp;gt;&amp;lt;br/&amp;gt;Please note that this only deletes files like databases. Programs must be deleted using &amp;lt;code&amp;gt;DLTPGM&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/dltf.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| DLTPGM&lt;br /&gt;
| Deletes a program, f.&amp;amp;thinsp;e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DLTPGM PGM(SOMELIBRARY/SOMEPGM)&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/dltpgm.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| WRKMBRPDM&lt;br /&gt;
| Work with source files using the Programming Development Manager&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/wrkmbrpdm.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| STRSEU&lt;br /&gt;
| Starts the source code editor.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/strseu.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| SEU&lt;br /&gt;
| Source code Edit Utility&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/rzasc/hseu.htm Details]&amp;lt;br/&amp;gt;&amp;amp;#x2026;and more useful&amp;amp;#x2026;&amp;lt;br/&amp;gt;[https://as400i.com/2013/03/13/using-the-source-entry-utility-seu-as400/ Usage]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| STRREXPRC&lt;br /&gt;
| Start a REXX procedure (aka: script), f.&amp;amp;thinsp;e.:&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;STRREXPRC SRCMBR(SOMEMEMBER) SRCFILE(SOMEPHYSICALSOURCEFILE)&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/cl/strrexprc.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTPGM&lt;br /&gt;
| Creates a program from source code&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/crtpgm.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| DSPUSRPRF&lt;br /&gt;
| Shows user profile, f.&amp;amp;thinsp;e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DSPUSRPRF HKRETSCHME&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/cl/dspusrprf.htm Details]&lt;br /&gt;
| Administration&lt;br /&gt;
|-&lt;br /&gt;
| DSPMSG&lt;br /&gt;
| Displays your messages, their origin might be another user or the compiler.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/dspmsg.htm Details]&lt;br /&gt;
| Administration&lt;br /&gt;
|-&lt;br /&gt;
| STRSQL&lt;br /&gt;
| Start interactive SQL session&amp;lt;br/&amp;gt;to view or change contents of your databases.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/strsql.htm Details] and [TBD about usage]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| STRDFU&lt;br /&gt;
| Start Data File Utility.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/strdfu.htm Details]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| DSPF&lt;br /&gt;
| Display the contents of a file, f.&amp;amp;thinsp;e.:&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DSPF FILE(SOMELIB/SOMEDBFILE)&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/cl/dspf.htm Details]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| CRTDSPF&lt;br /&gt;
| Create Display Files&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/cl/crtdspf.htm Details]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| RNMOBJ&lt;br /&gt;
| Rename Object&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/rnmobj.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| MOVOBJ&lt;br /&gt;
| Moves an object, like a physical file, to another library.&amp;lt;br/&amp;gt;Example: &amp;lt;code&amp;gt;MOVOBJ OBJ(HKRETSCHME/HELLO01) OBJTYPE(*FILE) TOLIB(HELLOWRLD)&amp;lt;/code&amp;gt; for physical files, or&amp;amp;#x2026;&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;MOVOBJ OBJ(HKRETSCHME/HELLO01) OBJTYPE(*PGM) TOLIB(HELLOWRLD)&amp;lt;/code&amp;gt; &amp;amp;#x2026;for programs.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/cl/movobj.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| FNDSTRPDM&lt;br /&gt;
| Find a string in a file&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/fndstrpdm.htm Details]&lt;br /&gt;
| Files, Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTCMOD&lt;br /&gt;
| Create a module&amp;lt;ref&amp;gt;In gcc-terms &amp;quot;object&amp;quot;&amp;lt;/ref&amp;gt; from C-Source. &amp;lt;br/&amp;gt; f.&amp;amp;thinsp;e. &amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG)&amp;lt;/code&amp;gt; &lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/crtcmod.htm Details] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/rzarf/clcommands.htm General C-Compiling] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzasc/bndmodpgm.htm About 2-Step-Compiling]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTPGM&lt;br /&gt;
| Links the modules&amp;lt;ref&amp;gt;In gcc-terms &amp;quot;objects&amp;quot;&amp;lt;/ref&amp;gt; into one program.&amp;lt;br/&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzasc/crtpgm9.htm Details] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/rzarf/clcommands.htm General C-Compiling] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzasc/bndmodpgm.htm About 2-Step-Compiling]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTBNDC&lt;br /&gt;
| Creates a program from C-Source (CRTCMOD and CRT in one step). &lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/crtbndc.htm Details] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/rzarf/clcommands.htm General C-Compiling]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| CHGCURLIB&lt;br /&gt;
| Changes current Library, f.&amp;amp;thinsp;e. &amp;lt;code&amp;gt;CHGCURLIB SPLAMGMT&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_72/cl/chgcurlib.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| DSPFD&lt;br /&gt;
| Displays informations about physical files, f.&amp;amp;thinsp;e. &amp;lt;code&amp;gt;DSPFD ARTIKELPF&amp;lt;/code&amp;gt;.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_72/cl/dspfd.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| CHGPF&lt;br /&gt;
| Change Physical File. Allows to set file-specific flags without recompile, and easy recompile of existing PFs with new or changed fields. Includes a pretty good copy routine, so data isn&#039;t lost and if it would, chgpf warns with an inquiry message.&lt;br /&gt;
| &amp;amp;thinsp;&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| DSPLIB&lt;br /&gt;
| Shows contents of a specific library.&lt;br /&gt;
| https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_74/cl/dsplib.htm&lt;br /&gt;
| Files&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[UNIX-User&#039;s Cheater Table]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Basic Knowledge]]&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=Editing_Source_Files_using_Eclipse_and_FTP&amp;diff=720</id>
		<title>Editing Source Files using Eclipse and FTP</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=Editing_Source_Files_using_Eclipse_and_FTP&amp;diff=720"/>
		<updated>2020-01-09T13:40:32Z</updated>

		<summary type="html">&lt;p&gt;Heiko: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can access all your files using FTP. This article will show you how to Edit-In-Place with Eclipse Neon.3 and Remote Systems Extension.&lt;br /&gt;
&lt;br /&gt;
== Setting up the connection ==&lt;br /&gt;
* Add a new connection:&amp;lt;br/&amp;gt;[[Image:FTPEclipse01.png]] &lt;br /&gt;
* Choose &amp;lt;tt&amp;gt;FTP&amp;lt;/tt&amp;gt;:&amp;lt;br/&amp;gt;[[Image:FTPEclipse02.png]]&amp;lt;br/&amp;gt;Input your hostname, username and so on.&lt;br /&gt;
* Open Preferences and set transfer mode for files to ASCII:&amp;lt;br/&amp;gt;[[Image:FTPEclipse03.png]]&lt;br /&gt;
&lt;br /&gt;
== Setting up a filter to access files ==&lt;br /&gt;
You can access your files by browsing the filesystem&#039;s root, but this is much more handy:&lt;br /&gt;
* Create a new filter:&amp;lt;br/&amp;gt;[[Image:FTPEclipse04.png]]&lt;br /&gt;
* Input folder with this format: &amp;lt;code&amp;gt;/QSYS.LIB/YOURLIBRARY.LIB/YOURPHYSICALSOURCEFILE.FILE&amp;lt;/code&amp;gt;, for example: &amp;lt;code&amp;gt;/QSYS.LIB/SNDBX.LIB/SNDBX.FILE&amp;lt;/code&amp;gt;&lt;br /&gt;
* You can now access the members of this file:&amp;lt;br/&amp;gt;[[Image:FTPEclipse05.png]]&amp;lt;br/&amp;gt;[[Image:FTPEclipse06.png]] &amp;lt;br/&amp;gt;(see also: [[Beginners Project: Hello World (using C)]])&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
*Links&lt;br /&gt;
** In case you like vi (or vim) better: https://stackoverflow.com/questions/58937739/edit-sqlrpgle-file-over-ftp-with-vim&lt;br /&gt;
*Footnotes&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category: Basic Knowledge]]&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=File:F-Tasten_F13-F24_v2.pdf&amp;diff=717</id>
		<title>File:F-Tasten F13-F24 v2.pdf</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=File:F-Tasten_F13-F24_v2.pdf&amp;diff=717"/>
		<updated>2020-01-07T10:49:36Z</updated>

		<summary type="html">&lt;p&gt;Heiko: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=File:F-Tasten_F13-F24_v2_Photo.jpg&amp;diff=715</id>
		<title>File:F-Tasten F13-F24 v2 Photo.jpg</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=File:F-Tasten_F13-F24_v2_Photo.jpg&amp;diff=715"/>
		<updated>2020-01-07T10:47:58Z</updated>

		<summary type="html">&lt;p&gt;Heiko: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=Basic_Commands&amp;diff=710</id>
		<title>Basic Commands</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=Basic_Commands&amp;diff=710"/>
		<updated>2019-11-29T13:08:48Z</updated>

		<summary type="html">&lt;p&gt;Heiko: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This article describes the basic commands for easy reference. Even more can be found at [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71 IBM&#039;s documentation].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Command&lt;br /&gt;
! Short description&lt;br /&gt;
! Link to detailed description&lt;br /&gt;
! Category&lt;br /&gt;
|-&lt;br /&gt;
| CRTSRCPF&lt;br /&gt;
| Creates a physical file for storing sources, f.e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;CRTSRCPF FILE(SOMELIBRARY/SOMEFILE) RCDLEN(112) TEXT(&#039;My file description&#039;)&amp;lt;/code &amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/ddp/rbae5crtsrcp.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| DLTF&lt;br /&gt;
| Deletes a file, f.e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DLTF FILE(SOMELIBRARY/SOMEFILE)&amp;lt;/code&amp;gt;&amp;lt;br/&amp;gt;Please note that this only deletes files like databases. Programs must be deleted using &amp;lt;code&amp;gt;DLTPGM&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/dltf.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| DLTPGM&lt;br /&gt;
| Deletes a program, f.e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DLTPGM PGM(SOMELIBRARY/SOMEPGM)&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/dltpgm.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| WRKMBRPDM&lt;br /&gt;
| Work with source files using the Programming Development Manager&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/wrkmbrpdm.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| STRSEU&lt;br /&gt;
| Starts the source code editor.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/strseu.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| SEU&lt;br /&gt;
| Source code Edit Utility&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/rzasc/hseu.htm Details]&amp;lt;br/&amp;gt;&amp;amp;#x2026;and more useful&amp;amp;#x2026;&amp;lt;br/&amp;gt;[https://as400i.com/2013/03/13/using-the-source-entry-utility-seu-as400/ Usage]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| STRREXPRC&lt;br /&gt;
| Start a REXX script, f.e.:&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;STRREXPRC SRCMBR(SOMEMEMBER) SRCFILE(SOMEPHYSICALSOURCEFILE)&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/cl/strrexprc.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTPGM&lt;br /&gt;
| Creates a program from source code&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/crtpgm.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| DSPUSRPRF&lt;br /&gt;
| Shows user profile, f.e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DSPUSRPRF HKRETSCHME&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/cl/dspusrprf.htm Details]&lt;br /&gt;
| Administration&lt;br /&gt;
|-&lt;br /&gt;
| DSPMSG&lt;br /&gt;
| Displays your messages, their origin might be another user or the compiler.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/dspmsg.htm Details]&lt;br /&gt;
| Administration&lt;br /&gt;
|-&lt;br /&gt;
| STRSQL&lt;br /&gt;
| Start interactive SQL session&amp;lt;br/&amp;gt;to view or change contents of your databases.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/strsql.htm Details] and [TBD about usage]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| STRDFU&lt;br /&gt;
| Start Data File Utility.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/strdfu.htm Details]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| DSPF&lt;br /&gt;
| Display the contents of a file, f.e.:&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DSPF FILE(SOMELIB/SOMEDBFILE)&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/cl/dspf.htm Details]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| CRTDSPF&lt;br /&gt;
| Create Display Files&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/cl/crtdspf.htm Details]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| RNMOBJ&lt;br /&gt;
| Rename Object&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/rnmobj.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| MOVOBJ&lt;br /&gt;
| Moves an object, like a physical file, to another library.&amp;lt;br/&amp;gt;Example: &amp;lt;code&amp;gt;MOVOBJ OBJ(HKRETSCHME/HELLO01) OBJTYPE(*FILE) TOLIB(HELLOWRLD)&amp;lt;/code&amp;gt; for physical files, or&amp;amp;#x2026;&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;MOVOBJ OBJ(HKRETSCHME/HELLO01) OBJTYPE(*PGM) TOLIB(HELLOWRLD)&amp;lt;/code&amp;gt; &amp;amp;#x2026;for programs.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/cl/movobj.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| FNDSTRPDM&lt;br /&gt;
| Find a string in a file&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/fndstrpdm.htm Details]&lt;br /&gt;
| Files, Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTCMOD&lt;br /&gt;
| Create a module&amp;lt;ref&amp;gt;In gcc-terms &amp;quot;object&amp;quot;&amp;lt;/ref&amp;gt; from C-Source. &amp;lt;br/&amp;gt; F.e. &amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG)&amp;lt;/code&amp;gt; &lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/crtcmod.htm Details] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/rzarf/clcommands.htm General C-Compiling] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzasc/bndmodpgm.htm About 2-Step-Compiling]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTPGM&lt;br /&gt;
| Links the modules&amp;lt;ref&amp;gt;In gcc-terms &amp;quot;objects&amp;quot;&amp;lt;/ref&amp;gt; into one program.&amp;lt;br/&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzasc/crtpgm9.htm Details] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/rzarf/clcommands.htm General C-Compiling] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzasc/bndmodpgm.htm About 2-Step-Compiling]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTBNDC&lt;br /&gt;
| Creates a program from C-Source (CRTCMOD and CRT in one step). &lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/crtbndc.htm Details] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/rzarf/clcommands.htm General C-Compiling]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| CHGCURLIB&lt;br /&gt;
| Changes current Library, f.e. &amp;lt;code&amp;gt;CHGCURLIB SPLAMGMT&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_72/cl/chgcurlib.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| DSPFD&lt;br /&gt;
| Displays informations about physical files, f.e. &amp;lt;code&amp;gt;DSPFD ARTIKELPF&amp;lt;/code&amp;gt;.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_72/cl/dspfd.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[UNIX-User&#039;s Cheater Table]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Basic Knowledge]]&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=Basic_Commands&amp;diff=709</id>
		<title>Basic Commands</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=Basic_Commands&amp;diff=709"/>
		<updated>2019-11-29T13:05:26Z</updated>

		<summary type="html">&lt;p&gt;Heiko: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This article describes the basic commands for easy reference. Even more can be found at [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71 IBM&#039;s documentation].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Command&lt;br /&gt;
! Short description&lt;br /&gt;
! Link to detailed description&lt;br /&gt;
! Category&lt;br /&gt;
|-&lt;br /&gt;
| CRTSRCPF&lt;br /&gt;
| Creates a physical file for storing sources, f.e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;CRTSRCPF FILE(SOMELIBRARY/SOMEFILE) RCDLEN(112) TEXT(&#039;My file description&#039;)&amp;lt;/code &amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/ddp/rbae5crtsrcp.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| DLTF&lt;br /&gt;
| Deletes a file, f.e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DLTF FILE(SOMELIBRARY/SOMEFILE)&amp;lt;/code&amp;gt;&amp;lt;br/&amp;gt;Please note that this only deletes files like databases. Programs must be deleted using &amp;lt;code&amp;gt;DLTPGM&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/dltf.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| DLTPGM&lt;br /&gt;
| Deletes a program, f.e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DLTPGM PGM(SOMELIBRARY/SOMEPGM)&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/dltpgm.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| WRKMBRPDM&lt;br /&gt;
| Work with source files using the Programming Development Manager&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/wrkmbrpdm.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| STRSEU&lt;br /&gt;
| Starts the source code editor.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/strseu.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| SEU&lt;br /&gt;
| Source code Edit Utility&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/rzasc/hseu.htm Details]&amp;lt;br/&amp;gt;&amp;amp;#x2026;and more useful&amp;amp;#x2026;&amp;lt;br/&amp;gt;[https://as400i.com/2013/03/13/using-the-source-entry-utility-seu-as400/ Usage]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| STRREXPRC&lt;br /&gt;
| Start a REXX script, f.e.:&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;STRREXPRC SRCMBR(SOMEMEMBER) SRCFILE(SOMEPHYSICALSOURCEFILE)&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/cl/strrexprc.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTPGM&lt;br /&gt;
| Creates a program from source code&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/crtpgm.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| DSPUSRPRF&lt;br /&gt;
| Shows user profile, f.e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DSPUSRPRF HKRETSCHME&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/cl/dspusrprf.htm Details]&lt;br /&gt;
| Administration&lt;br /&gt;
|-&lt;br /&gt;
| DSPMSG&lt;br /&gt;
| Displays your messages, their origin might be another user or the compiler.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/dspmsg.htm Details]&lt;br /&gt;
| Administration&lt;br /&gt;
|-&lt;br /&gt;
| STRSQL&lt;br /&gt;
| Start interactive SQL session&amp;lt;br/&amp;gt;to view or change contents of your databases.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/strsql.htm Details] and [TBD about usage]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| STRDFU&lt;br /&gt;
| Start Data File Utility.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/strdfu.htm Details]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| DSPF&lt;br /&gt;
| Display the contents of a file, f.e.:&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DSPF FILE(SOMELIB/SOMEDBFILE)&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/cl/dspf.htm Details]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| CRTDSPF&lt;br /&gt;
| Create Display Files&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/cl/crtdspf.htm Details]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| RNMOBJ&lt;br /&gt;
| Rename Object&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/rnmobj.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| MOVOBJ&lt;br /&gt;
| Moves an object, like a physical file, to another library.&amp;lt;br/&amp;gt;Example: &amp;lt;code&amp;gt;MOVOBJ OBJ(HKRETSCHME/HELLO01) OBJTYPE(*FILE) TOLIB(HELLOWRLD)&amp;lt;/code&amp;gt; for physical files, or&amp;amp;#x2026;&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;MOVOBJ OBJ(HKRETSCHME/HELLO01) OBJTYPE(*PGM) TOLIB(HELLOWRLD)&amp;lt;/code&amp;gt; &amp;amp;#x2026;for programs.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/cl/movobj.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| FNDSTRPDM&lt;br /&gt;
| Find a string in a file&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/fndstrpdm.htm Details]&lt;br /&gt;
| Files, Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTCMOD&lt;br /&gt;
| Create a module&amp;lt;ref&amp;gt;In gcc-terms &amp;quot;object&amp;quot;&amp;lt;/ref&amp;gt; from C-Source. &amp;lt;br/&amp;gt; F.e. &amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG)&amp;lt;/code&amp;gt; &lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/crtcmod.htm Details] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/rzarf/clcommands.htm General C-Compiling] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzasc/bndmodpgm.htm About 2-Step-Compiling]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTPGM&lt;br /&gt;
| Links the modules&amp;lt;ref&amp;gt;In gcc-terms &amp;quot;objects&amp;quot;&amp;lt;/ref&amp;gt; into one program.&amp;lt;br/&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzasc/crtpgm9.htm Details] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/rzarf/clcommands.htm General C-Compiling] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzasc/bndmodpgm.htm About 2-Step-Compiling]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTBNDC&lt;br /&gt;
| Creates a program from C-Source (CRTCMOD and CRT in one step). &lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/crtbndc.htm Details] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/rzarf/clcommands.htm General C-Compiling]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[UNIX-User&#039;s Cheater Table]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Basic Knowledge]]&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=Basic_Commands&amp;diff=708</id>
		<title>Basic Commands</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=Basic_Commands&amp;diff=708"/>
		<updated>2019-11-29T13:05:15Z</updated>

		<summary type="html">&lt;p&gt;Heiko: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This article describes the basic commands for easy reference. Even more can be found at [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71 IBM&#039;s documentation].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Command&lt;br /&gt;
! Short description&lt;br /&gt;
! Link to detailed description&lt;br /&gt;
! Category&lt;br /&gt;
|-&lt;br /&gt;
| CRTSRCPF&lt;br /&gt;
| Creates a physical file for storing sources, f.e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;CRTSRCPF FILE(SOMELIBRARY/SOMEFILE) RCDLEN(112) TEXT(&#039;My file description&#039;)&amp;lt;/code &amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/ddp/rbae5crtsrcp.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| DLTF&lt;br /&gt;
| Deletes a file, f.e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DLTF FILE(SOMELIBRARY/SOMEFILE)&amp;lt;/code&amp;gt;&amp;lt;br/&amp;gt;Please note that this only deletes files like databases. Programs must be deleted using &amp;lt;code&amp;gt;DLTPGM&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/dltf.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| DLTPGM&lt;br /&gt;
| Deletes a program, f.e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DLTPGM PGM(SOMELIBRARY/SOMEPGM)&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/dltpgm.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| WRKMBRPDM&lt;br /&gt;
| Work with source files using the Programming Development Manager&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/wrkmbrpdm.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| STRSEU&lt;br /&gt;
| Starts the source code editor.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/strseu.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| SEU&lt;br /&gt;
| Source code Edit Utility&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/rzasc/hseu.htm Details]&amp;lt;br/&amp;gt;&amp;amp;#x2026;and more useful&amp;amp;#x2026;&amp;lt;br/&amp;gt;[https://as400i.com/2013/03/13/using-the-source-entry-utility-seu-as400/ Usage]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| STRREXPRC&lt;br /&gt;
| Start a REXX script, f.e.:&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;STRREXPRC SRCMBR(SOMEMEMBER) SRCFILE(SOMEPHYSICALSOURCEFILE)&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/cl/strrexprc.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTPGM&lt;br /&gt;
| Creates a program from source code&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/crtpgm.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| DSPUSRPRF&lt;br /&gt;
| Shows user profile, f.e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DSPUSRPRF HKRETSCHME&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/cl/dspusrprf.htm Details]&lt;br /&gt;
| Administration&lt;br /&gt;
|-&lt;br /&gt;
| DSPMSG&lt;br /&gt;
| Displays your messages, their origin might be another user or the compiler.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/dspmsg.htm Details]&lt;br /&gt;
| Administration&lt;br /&gt;
|-&lt;br /&gt;
| STRSQL&lt;br /&gt;
| Start interactive SQL session&amp;lt;br/&amp;gt;to view or change contents of your databases.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/strsql.htm Details] and [TBD about usage]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| STRDFU&lt;br /&gt;
| Start Data File Utility.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/strdfu.htm Details]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| DSPF&lt;br /&gt;
| Display the contents of a file, f.e.:&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DSPF FILE(SOMELIB/SOMEDBFILE)&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/cl/dspf.htm Details]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| CRTDSPF&lt;br /&gt;
| Create Display Files&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/cl/crtdspf.htm Details]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| RNMOBJ&lt;br /&gt;
| Rename Object&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/rnmobj.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| MOVOBJ&lt;br /&gt;
| Moves an object, like a physical file, to another library.&amp;lt;br/&amp;gt;Example: &amp;lt;code&amp;gt;MOVOBJ OBJ(HKRETSCHME/HELLO01) OBJTYPE(*FILE) TOLIB(HELLOWRLD)&amp;lt;/code&amp;gt; for physical files, or&amp;amp;#x2026;&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;MOVOBJ OBJ(HKRETSCHME/HELLO01) OBJTYPE(*PGM) TOLIB(HELLOWRLD)&amp;lt;/code&amp;gt; &amp;amp;#x2026;for programs.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/cl/movobj.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| FNDSTRPDM&lt;br /&gt;
| Find a string in a file&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/fndstrpdm.htm Details]&lt;br /&gt;
| Files, Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTCMOD&lt;br /&gt;
| Create a module&amp;lt;ref&amp;gt;In gcc-terms &amp;quot;object&amp;quot;&amp;lt;/ref&amp;gt; from C-Source. &amp;lt;br/&amp;gt; F.e. &amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG)&amp;lt;/code&amp;gt; &lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/crtcmod.htm Details] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/rzarf/clcommands.htm General C-Compiling] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzasc/bndmodpgm.htm About 2-Step-Compiling]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTPGM?&lt;br /&gt;
| Links the modules&amp;lt;ref&amp;gt;In gcc-terms &amp;quot;objects&amp;quot;&amp;lt;/ref&amp;gt; into one program.&amp;lt;br/&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzasc/crtpgm9.htm Details] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/rzarf/clcommands.htm General C-Compiling] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzasc/bndmodpgm.htm About 2-Step-Compiling]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTBNDC&lt;br /&gt;
| Creates a program from C-Source (CRTCMOD and CRT in one step). &lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/crtbndc.htm Details] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/rzarf/clcommands.htm General C-Compiling]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[UNIX-User&#039;s Cheater Table]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Basic Knowledge]]&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=Basic_Commands&amp;diff=707</id>
		<title>Basic Commands</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=Basic_Commands&amp;diff=707"/>
		<updated>2019-11-29T13:05:03Z</updated>

		<summary type="html">&lt;p&gt;Heiko: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This article describes the basic commands for easy reference. Even more can be found at [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71 IBM&#039;s documentation].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Command&lt;br /&gt;
! Short description&lt;br /&gt;
! Link to detailed description&lt;br /&gt;
! Category&lt;br /&gt;
|-&lt;br /&gt;
| CRTSRCPF&lt;br /&gt;
| Creates a physical file for storing sources, f.e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;CRTSRCPF FILE(SOMELIBRARY/SOMEFILE) RCDLEN(112) TEXT(&#039;My file description&#039;)&amp;lt;/code &amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/ddp/rbae5crtsrcp.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| DLTF&lt;br /&gt;
| Deletes a file, f.e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DLTF FILE(SOMELIBRARY/SOMEFILE)&amp;lt;/code&amp;gt;&amp;lt;br/&amp;gt;Please note that this only deletes files like databases. Programs must be deleted using &amp;lt;code&amp;gt;DLTPGM&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/dltf.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| DLTPGM&lt;br /&gt;
| Deletes a program, f.e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DLTPGM PGM(SOMELIBRARY/SOMEPGM)&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/dltpgm.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| WRKMBRPDM&lt;br /&gt;
| Work with source files using the Programming Development Manager&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/wrkmbrpdm.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| STRSEU&lt;br /&gt;
| Starts the source code editor.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/strseu.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| SEU&lt;br /&gt;
| Source code Edit Utility&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/rzasc/hseu.htm Details]&amp;lt;br/&amp;gt;&amp;amp;#x2026;and more useful&amp;amp;#x2026;&amp;lt;br/&amp;gt;[https://as400i.com/2013/03/13/using-the-source-entry-utility-seu-as400/ Usage]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| STRREXPRC&lt;br /&gt;
| Start a REXX script, f.e.:&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;STRREXPRC SRCMBR(SOMEMEMBER) SRCFILE(SOMEPHYSICALSOURCEFILE)&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/cl/strrexprc.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTPGM&lt;br /&gt;
| Creates a program from source code&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/crtpgm.htm Details]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| DSPUSRPRF&lt;br /&gt;
| Shows user profile, f.e.&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DSPUSRPRF HKRETSCHME&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/cl/dspusrprf.htm Details]&lt;br /&gt;
| Administration&lt;br /&gt;
|-&lt;br /&gt;
| DSPMSG&lt;br /&gt;
| Displays your messages, their origin might be another user or the compiler.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/dspmsg.htm Details]&lt;br /&gt;
| Administration&lt;br /&gt;
|-&lt;br /&gt;
| STRSQL&lt;br /&gt;
| Start interactive SQL session&amp;lt;br/&amp;gt;to view or change contents of your databases.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/strsql.htm Details] and [TBD about usage]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| STRDFU&lt;br /&gt;
| Start Data File Utility.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/strdfu.htm Details]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| DSPF&lt;br /&gt;
| Display the contents of a file, f.e.:&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;DSPF FILE(SOMELIB/SOMEDBFILE)&amp;lt;/code&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/cl/dspf.htm Details]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| CRTDSPF&lt;br /&gt;
| Create Display Files&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/cl/crtdspf.htm Details]&lt;br /&gt;
| Databases&lt;br /&gt;
|-&lt;br /&gt;
| RNMOBJ&lt;br /&gt;
| Rename Object&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/rnmobj.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| MOVOBJ&lt;br /&gt;
| Moves an object, like a physical file, to another library.&amp;lt;br/&amp;gt;Example: &amp;lt;code&amp;gt;MOVOBJ OBJ(HKRETSCHME/HELLO01) OBJTYPE(*FILE) TOLIB(HELLOWRLD)&amp;lt;/code&amp;gt; for physical files, or&amp;amp;#x2026;&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;MOVOBJ OBJ(HKRETSCHME/HELLO01) OBJTYPE(*PGM) TOLIB(HELLOWRLD)&amp;lt;/code&amp;gt; &amp;amp;#x2026;for programs.&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/cl/movobj.htm Details]&lt;br /&gt;
| Files&lt;br /&gt;
|-&lt;br /&gt;
| FNDSTRPDM&lt;br /&gt;
| Find a string in a file&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/fndstrpdm.htm Details]&lt;br /&gt;
| Files, Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTCMOD&lt;br /&gt;
| Create a module&amp;lt;ref&amp;gt;In gcc-terms &amp;quot;object&amp;quot;&amp;lt;/ref&amp;gt; from C-Source. &amp;lt;br/&amp;gt; F.e. &amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG)&amp;lt;/code&amp;gt; &lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/cl/crtcmod.htm Details] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/rzarf/clcommands.htm General C-Compiling] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzasc/bndmodpgm.htm About 2-Step-Compiling]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTPGM?&lt;br /&gt;
| Links the modules&amp;lt;ref&amp;gt;In gcc-terms &amp;quot;objects&amp;quot;&amp;lt;/ref&amp;gt; into one program.&amp;lt;br/&amp;gt;&lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzasc/crtpgm9.htm Details] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/rzarf/clcommands.htm General C-Compiling] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzasc/bndmodpgm.htm About 2-Step-Compiling]&lt;br /&gt;
| Development&lt;br /&gt;
|-&lt;br /&gt;
| CRTBNDC&lt;br /&gt;
| Creates a program from C-Source (CRTCMOD and CRT in one step). &lt;br /&gt;
| [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/cl/crtbndc.htm Details] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/rzarf/clcommands.htm General C-Compiling]&lt;br /&gt;
| Development&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[UNIX-User&#039;s Cheater Table]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Basic Knowledge]]&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=706</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=706"/>
		<updated>2019-11-28T10:38:55Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* The code used */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
=== The code used ===&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 // TEST W/ ADDITIONAL variadic arguments&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
 // EMPTY variadic arguments&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); &lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and ran into these error messages:&lt;br /&gt;
 35 ! // TEST W/ ADDITIONAL variadic arguments ! &lt;br /&gt;
 36 ! Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;);&lt;br /&gt;
 36 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 36, 0, (paramete;                   &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; a - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously, this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0045 Undeclared identifier paramete.            &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously, this truncated identifier won&#039;t work...&amp;lt;/font&amp;gt;&lt;br /&gt;
 37 !&lt;br /&gt;
 38 ! // EMPTY variadic arguments&lt;br /&gt;
 39 ! Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); &lt;br /&gt;
 39 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 39, 0, (paramete;                   &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 ERROR===========&amp;gt; a - CZM0041 The invocation of macro Say contains fewer arguments than are required by the macro definition. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- What? It seems there HAS to be a variadic argument. Giving none won&#039;t work with this compiler&amp;lt;ref&amp;gt;I tried several compiler settings (f.e. LANGLVL), and even using __VA_OPT__.&amp;lt;/ref&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously, this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So what next? I couldn&#039;t explain why and how the truncation happened (even after many attempts of understanding/solving this issue) and started to follow the only other lead: The CZM0041 error, even though was only thrown by one of the two lines.&lt;br /&gt;
&lt;br /&gt;
[https://en.wikipedia.org/wiki/Variadic_macro Wikipedia] states: &#039;&#039;Both the [C99] and [C++11] standards &#039;&#039;&#039;require at least one argument&#039;&#039;&#039;, but since [C++20] this limitation has been lifted through the __VA_OPT__ functional macro. The __VA_OPT__ macro is replaced by its argument when arguments are present, and omitted otherwise. &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;Common compilers also permit passing zero arguments before this addition, however.&amp;lt;/font&amp;gt;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;green sentence&amp;lt;/font&amp;gt; meant, that all previously used compilers permitted zero arguments, but the AS/400&#039;s compiler didn&#039;t.&lt;br /&gt;
&lt;br /&gt;
So I changed my define from...&lt;br /&gt;
 #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
...to...&lt;br /&gt;
 #define Say(logLevel, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, __VA_ARGS__);&lt;br /&gt;
Meaning, only the logLevel (severity) argument was defined, everything else, including the always following text message, was part of the VA. This way, VA would always include at least one argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=705</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=705"/>
		<updated>2019-11-28T10:37:40Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* The Solution */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
=== The code used ===&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;); // With additional arguments&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); // just a plain message&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and ran into these error messages:&lt;br /&gt;
 35 ! // TEST W/ ADDITIONAL variadic arguments ! &lt;br /&gt;
 36 ! Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;);&lt;br /&gt;
 36 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 36, 0, (paramete;                   &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; a - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously, this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0045 Undeclared identifier paramete.            &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously, this truncated identifier won&#039;t work...&amp;lt;/font&amp;gt;&lt;br /&gt;
 37 !&lt;br /&gt;
 38 ! // EMPTY variadic arguments&lt;br /&gt;
 39 ! Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); &lt;br /&gt;
 39 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 39, 0, (paramete;                   &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 ERROR===========&amp;gt; a - CZM0041 The invocation of macro Say contains fewer arguments than are required by the macro definition. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- What? It seems there HAS to be a variadic argument. Giving none won&#039;t work with this compiler&amp;lt;ref&amp;gt;I tried several compiler settings (f.e. LANGLVL), and even using __VA_OPT__.&amp;lt;/ref&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously, this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So what next? I couldn&#039;t explain why and how the truncation happened (even after many attempts of understanding/solving this issue) and started to follow the only other lead: The CZM0041 error, even though was only thrown by one of the two lines.&lt;br /&gt;
&lt;br /&gt;
[https://en.wikipedia.org/wiki/Variadic_macro Wikipedia] states: &#039;&#039;Both the [C99] and [C++11] standards &#039;&#039;&#039;require at least one argument&#039;&#039;&#039;, but since [C++20] this limitation has been lifted through the __VA_OPT__ functional macro. The __VA_OPT__ macro is replaced by its argument when arguments are present, and omitted otherwise. &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;Common compilers also permit passing zero arguments before this addition, however.&amp;lt;/font&amp;gt;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;green sentence&amp;lt;/font&amp;gt; meant, that all previously used compilers permitted zero arguments, but the AS/400&#039;s compiler didn&#039;t.&lt;br /&gt;
&lt;br /&gt;
So I changed my define from...&lt;br /&gt;
 #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
...to...&lt;br /&gt;
 #define Say(logLevel, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, __VA_ARGS__);&lt;br /&gt;
Meaning, only the logLevel (severity) argument was defined, everything else, including the always following text message, was part of the VA. This way, VA would always include at least one argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=704</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=704"/>
		<updated>2019-11-28T10:36:36Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* The Solution */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
=== The code used ===&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;); // With additional arguments&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); // just a plain message&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and ran into these error messages:&lt;br /&gt;
 35 ! // TEST W/ ADDITIONAL variadic arguments ! &lt;br /&gt;
 36 ! Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;);&lt;br /&gt;
 36 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 36, 0, (paramete;                   &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; a - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously, this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0045 Undeclared identifier paramete.            &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously, this truncated identifier won&#039;t work...&amp;lt;/font&amp;gt;&lt;br /&gt;
 37 !&lt;br /&gt;
 38 ! // EMPTY variadic arguments&lt;br /&gt;
 39 ! Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); &lt;br /&gt;
 39 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 39, 0, (paramete;                   &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 ERROR===========&amp;gt; a - CZM0041 The invocation of macro Say contains fewer arguments than are required by the macro definition. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- What? It seems there HAS to be a variadic argument. Giving none won&#039;t work with this compiler&amp;lt;ref&amp;gt;I tried several compiler settings (f.e. LANGLVL), and even using __VA_OPT__.&amp;lt;/ref&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously, this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So what next? I couldn&#039;t explain why and how the truncation happened (even after many attempts of understanding/solving this issue) and started to follow the only other lead: The CZM0041 error, even though was only thrown by one of the two lines.&lt;br /&gt;
&lt;br /&gt;
[https://en.wikipedia.org/wiki/Variadic_macro Wikipedia] states: &#039;&#039;Both the [C99] and [C++11] standards &#039;&#039;&#039;require at least one argument&#039;&#039;&#039;, but since [C++20] this limitation has been lifted through the __VA_OPT__ functional macro. The __VA_OPT__ macro is replaced by its argument when arguments are present, and omitted otherwise. &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;Common compilers also permit passing zero arguments before this addition, however.&amp;lt;/font&amp;gt;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;green sentence&amp;lt;/font&amp;gt; meant, that all previously used compilers permitted zero arguments, but the AS/400&#039;s compiler didn&#039;t.&lt;br /&gt;
&lt;br /&gt;
So I changed my define from...&lt;br /&gt;
 #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
...to...&lt;br /&gt;
 #define Say(logLevel, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, __VA_ARGS__);&lt;br /&gt;
Meaning, only the logLevel (severity) argument was defined, everything else, including the always following text message, was part of the VA. This way, VA would always include at least one argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=703</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=703"/>
		<updated>2019-11-28T10:35:38Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* The Solution */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
=== The code used ===&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;); // With additional arguments&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); // just a plain message&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and ran into these error messages:&lt;br /&gt;
 35 ! // TEST W/ ADDITIONAL variadic arguments ! &lt;br /&gt;
 36 ! Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;);&lt;br /&gt;
 36 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 36, 0, (paramete;                   &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; a - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously, this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0045 Undeclared identifier paramete.            &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously, this truncated identifier won&#039;t work...&amp;lt;/font&amp;gt;&lt;br /&gt;
 37 !&lt;br /&gt;
 38 ! // EMPTY variadic arguments&lt;br /&gt;
 39 ! Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); &lt;br /&gt;
 39 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 39, 0, (paramete;                   &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 ERROR===========&amp;gt; a - CZM0041 The invocation of macro Say contains fewer arguments than are required by the macro definition. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- What? It seems there HAS to be a variadic argument. Giving none won&#039;t work with this compiler&amp;lt;ref&amp;gt;I tried several compiler settings (f.e. LANGLVL), and even using __VA_OPT__.&amp;lt;/ref&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously, this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So what next? I couldn&#039;t explain why and how the truncation happened (even after many attempts of understanding/solving this issue) and started to follow the only valid lead: The CZM0041 error, even though was only thrown by one of the two lines.&lt;br /&gt;
&lt;br /&gt;
[https://en.wikipedia.org/wiki/Variadic_macro Wikipedia] states: &#039;&#039;Both the [C99] and [C++11] standards &#039;&#039;&#039;require at least one argument&#039;&#039;&#039;, but since [C++20] this limitation has been lifted through the __VA_OPT__ functional macro. The __VA_OPT__ macro is replaced by its argument when arguments are present, and omitted otherwise. &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;Common compilers also permit passing zero arguments before this addition, however.&amp;lt;/font&amp;gt;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;green sentence&amp;lt;/font&amp;gt; meant, that all previously used compilers permitted zero arguments, but the AS/400&#039;s compiler didn&#039;t.&lt;br /&gt;
&lt;br /&gt;
So I changed my define from...&lt;br /&gt;
 #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
...to...&lt;br /&gt;
 #define Say(logLevel, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, __VA_ARGS__);&lt;br /&gt;
Meaning, only the logLevel (severity) argument was defined, everything else, including the always following text message, was part of the VA. This way, VA would always include at least one argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=702</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=702"/>
		<updated>2019-11-28T10:35:02Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* The Solution */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
=== The code used ===&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;); // With additional arguments&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); // just a plain message&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and ran into these error messages:&lt;br /&gt;
 35 ! // TEST W/ ADDITIONAL variadic arguments ! &lt;br /&gt;
 36 ! Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;);&lt;br /&gt;
 36 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 36, 0, (paramete;                   &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; a - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0045 Undeclared identifier paramete.            &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated identifier won&#039;t work...&amp;lt;/font&amp;gt;&lt;br /&gt;
 37 !&lt;br /&gt;
 38 ! // EMPTY variadic arguments&lt;br /&gt;
 39 ! Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); &lt;br /&gt;
 39 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 39, 0, (paramete;                   &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 ERROR===========&amp;gt; a - CZM0041 The invocation of macro Say contains fewer arguments than are required by the macro definition. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- What? It seems there HAS to be a variadic argument. Giving none won&#039;t work with this compiler&amp;lt;ref&amp;gt;I tried several compiler settings (f.e. LANGLVL), and even using __VA_OPT__.&amp;lt;/ref&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So what next? I couldn&#039;t explain why and how the truncation happened (even after many attempts of understanding/solving this issue) and started to follow the only valid lead: The CZM0041 error, even though was only thrown by one of the two lines.&lt;br /&gt;
&lt;br /&gt;
[https://en.wikipedia.org/wiki/Variadic_macro Wikipedia] states: &#039;&#039;Both the [C99] and [C++11] standards &#039;&#039;&#039;require at least one argument&#039;&#039;&#039;, but since [C++20] this limitation has been lifted through the __VA_OPT__ functional macro. The __VA_OPT__ macro is replaced by its argument when arguments are present, and omitted otherwise. &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;Common compilers also permit passing zero arguments before this addition, however.&amp;lt;/font&amp;gt;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;green sentence&amp;lt;/font&amp;gt; meant, that all previously used compilers permitted zero arguments, but the AS/400&#039;s compiler didn&#039;t.&lt;br /&gt;
&lt;br /&gt;
So I changed my define from...&lt;br /&gt;
 #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
...to...&lt;br /&gt;
 #define Say(logLevel, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, __VA_ARGS__);&lt;br /&gt;
Meaning, only the logLevel (severity) argument was defined, everything else, including the always following text message, was part of the VA. This way, VA would always include at least one argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=701</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=701"/>
		<updated>2019-11-28T10:32:45Z</updated>

		<summary type="html">&lt;p&gt;Heiko: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
=== The code used ===&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;); // With additional arguments&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); // just a plain message&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and ran into these error messages:&lt;br /&gt;
 35 ! // TEST W/ ADDITIONAL variadic arguments ! &lt;br /&gt;
 36 ! Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;);&lt;br /&gt;
 36 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 36, 0, (paramete; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; a - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0045 Undeclared identifier paramete. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated identifier won&#039;t work...&amp;lt;/font&amp;gt;&lt;br /&gt;
 37 !&lt;br /&gt;
 38 ! // EMPTY variadic arguments&lt;br /&gt;
 39 ! Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); &lt;br /&gt;
 39 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 39, 0, (paramete; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 ERROR===========&amp;gt; a - CZM0041 The invocation of macro Say contains fewer arguments than are required by the macro definition. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- What? It seems there HAS to be a variadic argument. Giving none won&#039;t work with this compiler&amp;lt;ref&amp;gt;I tried several compiler settings (f.e. LANGLVL), and even using __VA_OPT__.&amp;lt;/ref&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So what next? I couldn&#039;t explain why and how the truncation happened (even after many attempts of understanding/solving this issue) and started to follow the only valid lead: The CZM0041 error, even though was only thrown by one of the two lines.&lt;br /&gt;
&lt;br /&gt;
[https://en.wikipedia.org/wiki/Variadic_macro Wikipedia] states: &#039;&#039;Both the [C99] and [C++11] standards &#039;&#039;&#039;require at least one argument&#039;&#039;&#039;, but since [C++20] this limitation has been lifted through the __VA_OPT__ functional macro. The __VA_OPT__ macro is replaced by its argument when arguments are present, and omitted otherwise. &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;Common compilers also permit passing zero arguments before this addition, however.&amp;lt;/font&amp;gt;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;green sentence&amp;lt;/font&amp;gt; meant, that all previously used compilers permitted zero arguments, but the AS/400&#039;s compiler didn&#039;t.&lt;br /&gt;
&lt;br /&gt;
So I changed my define from...&lt;br /&gt;
 #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
...to...&lt;br /&gt;
 #define Say(logLevel, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, __VA_ARGS__);&lt;br /&gt;
Meaning, only the logLevel (severity) argument was defined, everything else, including the always following text message, was part of the VA. This way, VA would always include at least one argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=700</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=700"/>
		<updated>2019-11-28T10:32:01Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* What happened */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
=== The code used ===&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;); // With additional arguments&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); // just a plain message&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== What happened ===&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and ran into these error messages:&lt;br /&gt;
 35 ! // TEST W/ ADDITIONAL variadic arguments ! &lt;br /&gt;
 36 ! Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;);&lt;br /&gt;
 36 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 36, 0, (paramete; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; a - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0045 Undeclared identifier paramete. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated identifier won&#039;t work...&amp;lt;/font&amp;gt;&lt;br /&gt;
 37 !&lt;br /&gt;
 38 ! // EMPTY variadic arguments&lt;br /&gt;
 39 ! Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); &lt;br /&gt;
 39 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 39, 0, (paramete; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 ERROR===========&amp;gt; a - CZM0041 The invocation of macro Say contains fewer arguments than are required by the macro definition. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- What? It seems there HAS to be a variadic argument. Giving none won&#039;t work with this compiler&amp;lt;ref&amp;gt;I tried several compiler settings (f.e. LANGLVL), and even using __VA_OPT__.&amp;lt;/ref&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So what next? I couldn&#039;t explain why and how the truncation happened (even after many attempts of understanding/solving this issue) and started to follow the only valid lead: The CZM0041 error, even though was only thrown by one of the two lines.&lt;br /&gt;
&lt;br /&gt;
[https://en.wikipedia.org/wiki/Variadic_macro Wikipedia] states: &#039;&#039;Both the [C99] and [C++11] standards &#039;&#039;&#039;require at least one argument&#039;&#039;&#039;, but since [C++20] this limitation has been lifted through the __VA_OPT__ functional macro. The __VA_OPT__ macro is replaced by its argument when arguments are present, and omitted otherwise. &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;Common compilers also permit passing zero arguments before this addition, however.&amp;lt;/font&amp;gt;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;green sentence&amp;lt;/font&amp;gt; meant, that all previously used compilers permitted zero arguments, but the AS/400&#039;s compiler didn&#039;t.&lt;br /&gt;
&lt;br /&gt;
So I changed my define from...&lt;br /&gt;
 #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
...to...&lt;br /&gt;
 #define Say(logLevel, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, __VA_ARGS__);&lt;br /&gt;
Meaning, only the logLevel (severity) argument was defined, everything else, including the always following text message, was part of the VA. This way, VA would always include at least one argument.&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=699</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=699"/>
		<updated>2019-11-28T10:30:19Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* The code used */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
=== The code used ===&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;); // With additional arguments&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); // just a plain message&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== What happened ===&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and ran into these error messages:&lt;br /&gt;
 35 ! // TEST W/ ADDITIONAL variadic arguments ! &lt;br /&gt;
 36 ! Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;);&lt;br /&gt;
 36 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 36, 0, (paramete; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; a - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0045 Undeclared identifier paramete. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated identifier won&#039;t work...&amp;lt;/font&amp;gt;&lt;br /&gt;
 37 !&lt;br /&gt;
 38 ! // EMPTY variadic arguments&lt;br /&gt;
 39 ! Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); &lt;br /&gt;
 39 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 39, 0, (paramete; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 ERROR===========&amp;gt; a - CZM0041 The invocation of macro Say contains fewer arguments than are required by the macro definition. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- What? It seems there HAS to be a variadic argument. Giving none won&#039;t work with this compiler&amp;lt;ref&amp;gt;I tried several compiler settings (f.e. LANGLVL), and even using __VA_OPT__.&amp;lt;/ref&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So what next? I couldn&#039;t explain why and how the truncation happened (even after many attempts of understanding/solving this issue) and started to follow the only valid lead: The CZM0041 error, even though was only thrown by one of the two lines.&lt;br /&gt;
&lt;br /&gt;
[https://en.wikipedia.org/wiki/Variadic_macro Wikipedia] states: &#039;&#039;Both the [C99] and [C++11] standards &#039;&#039;&#039;require at least one argument&#039;&#039;&#039;, but since [C++20] this limitation has been lifted through the __VA_OPT__ functional macro. The __VA_OPT__ macro is replaced by its argument when arguments are present, and omitted otherwise. &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;Common compilers also permit passing zero arguments before this addition, however.&amp;lt;/font&amp;gt;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;green sentence&amp;lt;/font&amp;gt; meant, that all previously used compilers permitted zero arguments, but the AS/400&#039;s compiler didn&#039;t.&lt;br /&gt;
&lt;br /&gt;
So I changed my define from...&lt;br /&gt;
...to...&lt;br /&gt;
 #define Say(logLevel, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, __VA_ARGS__);&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=698</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=698"/>
		<updated>2019-11-28T10:30:06Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* What happened */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
=== The code used ===&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;); // With additional arguments&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); // just a plain message&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #if (kDebug)&lt;br /&gt;
    #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
 #else&lt;br /&gt;
    #define Say(logLevel, parameter, ...) //#define KeinLoggingHeute&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== What happened ===&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and ran into these error messages:&lt;br /&gt;
 35 ! // TEST W/ ADDITIONAL variadic arguments ! &lt;br /&gt;
 36 ! Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;);&lt;br /&gt;
 36 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 36, 0, (paramete; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; a - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0045 Undeclared identifier paramete. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated identifier won&#039;t work...&amp;lt;/font&amp;gt;&lt;br /&gt;
 37 !&lt;br /&gt;
 38 ! // EMPTY variadic arguments&lt;br /&gt;
 39 ! Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); &lt;br /&gt;
 39 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 39, 0, (paramete; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 ERROR===========&amp;gt; a - CZM0041 The invocation of macro Say contains fewer arguments than are required by the macro definition. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- What? It seems there HAS to be a variadic argument. Giving none won&#039;t work with this compiler&amp;lt;ref&amp;gt;I tried several compiler settings (f.e. LANGLVL), and even using __VA_OPT__.&amp;lt;/ref&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So what next? I couldn&#039;t explain why and how the truncation happened (even after many attempts of understanding/solving this issue) and started to follow the only valid lead: The CZM0041 error, even though was only thrown by one of the two lines.&lt;br /&gt;
&lt;br /&gt;
[https://en.wikipedia.org/wiki/Variadic_macro Wikipedia] states: &#039;&#039;Both the [C99] and [C++11] standards &#039;&#039;&#039;require at least one argument&#039;&#039;&#039;, but since [C++20] this limitation has been lifted through the __VA_OPT__ functional macro. The __VA_OPT__ macro is replaced by its argument when arguments are present, and omitted otherwise. &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;Common compilers also permit passing zero arguments before this addition, however.&amp;lt;/font&amp;gt;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;green sentence&amp;lt;/font&amp;gt; meant, that all previously used compilers permitted zero arguments, but the AS/400&#039;s compiler didn&#039;t.&lt;br /&gt;
&lt;br /&gt;
So I changed my define from...&lt;br /&gt;
...to...&lt;br /&gt;
 #define Say(logLevel, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, __VA_ARGS__);&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=697</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=697"/>
		<updated>2019-11-28T10:28:04Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* What happened */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
=== The code used ===&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;); // With additional arguments&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); // just a plain message&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #if (kDebug)&lt;br /&gt;
    #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
 #else&lt;br /&gt;
    #define Say(logLevel, parameter, ...) //#define KeinLoggingHeute&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== What happened ===&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and ran into these error messages:&lt;br /&gt;
 35 ! // TEST W/ ADDITIONAL variadic arguments ! &lt;br /&gt;
 36 ! Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;);&lt;br /&gt;
 36 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 36, 0, (paramete; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; a - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0045 Undeclared identifier paramete. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated identifier won&#039;t work...&amp;lt;/font&amp;gt;&lt;br /&gt;
 37 !&lt;br /&gt;
 38 ! // EMPTY variadic arguments&lt;br /&gt;
 39 ! Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); &lt;br /&gt;
 39 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 39, 0, (paramete; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 ERROR===========&amp;gt; a - CZM0041 The invocation of macro Say contains fewer arguments than are required by the macro definition. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- What? It seems there HAS to be a variadic argument. Giving none won&#039;t work with this compiler&amp;lt;ref&amp;gt;I tried several compiler settings (f.e. LANGLVL), and even using __VA_OPT__.&amp;lt;/ref&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So what next? I couldn&#039;t explain why and how the truncation happened (even after many attempts of understanding/solving this issue) and started to follow the only valid lead: The CZM0041 error.&lt;br /&gt;
&lt;br /&gt;
[https://en.wikipedia.org/wiki/Variadic_macro Wikipedia] states: &#039;&#039;Both the [C99] and [C++11] standards &#039;&#039;&#039;require at least one argument&#039;&#039;&#039;, but since [C++20] this limitation has been lifted through the __VA_OPT__ functional macro. The __VA_OPT__ macro is replaced by its argument when arguments are present, and omitted otherwise. &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;Common compilers also permit passing zero arguments before this addition, however.&amp;lt;/font&amp;gt;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;green sentence&amp;lt;/font&amp;gt; meant, that all previously used compilers permitted zero arguments, but the AS/400&#039;s compiler didn&#039;t.&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=696</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=696"/>
		<updated>2019-11-28T10:27:38Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* What happened */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
=== The code used ===&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;); // With additional arguments&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); // just a plain message&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #if (kDebug)&lt;br /&gt;
    #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
 #else&lt;br /&gt;
    #define Say(logLevel, parameter, ...) //#define KeinLoggingHeute&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== What happened ===&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and ran into these error messages:&lt;br /&gt;
 35 ! // TEST W/ ADDITIONAL variadic arguments ! &lt;br /&gt;
 36 ! Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;);&lt;br /&gt;
 36 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 36, 0, (paramete; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; a - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0045 Undeclared identifier paramete. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated identifier won&#039;t work...&amp;lt;/font&amp;gt;&lt;br /&gt;
 37 !&lt;br /&gt;
 38 ! // EMPTY variadic arguments&lt;br /&gt;
 39 ! Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); &lt;br /&gt;
 39 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 39, 0, (paramete; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 ERROR===========&amp;gt; a - CZM0041 The invocation of macro Say contains fewer arguments than are required by the macro definition. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- What? It seems there HAS to be a variadic argument. Giving none won&#039;t work with this compiler&amp;lt;ref&amp;gt;I tried several compiler settings (f.e. LANGLVL), and even using __VA_OPT__.&amp;lt;/ref&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So what next? I couldn&#039;t explain why and how the truncation happened (even after many attempts of understanding/solving this issue) and started to follow the only valid lead: The CZM0041 error.&lt;br /&gt;
&lt;br /&gt;
[https://en.wikipedia.org/wiki/Variadic_macro Wikipedia] states: &amp;quot;Both the [C99] and [C++11] standards &#039;&#039;&#039;require at least one argument&#039;&#039;&#039;, but since [C++20] this limitation has been lifted through the __VA_OPT__ functional macro. The __VA_OPT__ macro is replaced by its argument when arguments are present, and omitted otherwise. &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;Common compilers also permit passing zero arguments before this addition, however.&amp;lt;/font&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;green sentence&amp;lt;/font&amp;gt; meant, that all previously used compilers permitted zero arguments, but the AS/400&#039;s compiler didn&#039;t.&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=695</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=695"/>
		<updated>2019-11-28T10:27:20Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* What happened */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
=== The code used ===&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;); // With additional arguments&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); // just a plain message&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #if (kDebug)&lt;br /&gt;
    #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
 #else&lt;br /&gt;
    #define Say(logLevel, parameter, ...) //#define KeinLoggingHeute&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== What happened ===&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and ran into these error messages:&lt;br /&gt;
 35 ! // TEST W/ ADDITIONAL variadic arguments ! &lt;br /&gt;
 36 ! Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;);&lt;br /&gt;
 36 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 36, 0, (paramete; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; a - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0045 Undeclared identifier paramete. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated identifier won&#039;t work...&amp;lt;/font&amp;gt;&lt;br /&gt;
 37 !&lt;br /&gt;
 38 ! // EMPTY variadic arguments&lt;br /&gt;
 39 ! Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); &lt;br /&gt;
 39 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 39, 0, (paramete; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 ERROR===========&amp;gt; a - CZM0041 The invocation of macro Say contains fewer arguments than are required by the macro definition. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- What? It seems there HAS to be a variadic argument. Giving none won&#039;t work with this compiler&amp;lt;ref&amp;gt;I tried several compiler settings (f.e. LANGLVL), and even using __VA_OPT__.&amp;lt;/ref&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So what next? I couldn&#039;t explain why and how the truncation happened (even after many attempts of understanding/solving this issue) and started to follow the only valid lead: The CZM0041 error.&lt;br /&gt;
&lt;br /&gt;
[https://en.wikipedia.org/wiki/Variadic_macro Wikipedia] states: &amp;quot;Both the [C99] and [C++11] standards &#039;&#039;&#039;require at least one argument&#039;&#039;&#039;, but since [C++20] this limitation has been lifted through the __VA_OPT__ functional macro. The __VA_OPT__ macro is replaced by its argument when arguments are present, and omitted otherwise. &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;&#039;&#039;&#039;Common compilers also permit passing zero arguments before this addition, however.&#039;&#039;&#039;&amp;lt;/font&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;green sentence&amp;lt;/font&amp;gt; meant, that all previously used compilers permitted zero arguments, but the AS/400&#039;s compiler didn&#039;t.&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=694</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=694"/>
		<updated>2019-11-28T10:09:01Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* What happened */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
=== The code used ===&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;); // With additional arguments&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); // just a plain message&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #if (kDebug)&lt;br /&gt;
    #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
 #else&lt;br /&gt;
    #define Say(logLevel, parameter, ...) //#define KeinLoggingHeute&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== What happened ===&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and ran into these error messages:&lt;br /&gt;
 35 ! // TEST W/ ADDITIONAL variadic arguments ! &lt;br /&gt;
 36 ! Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;);&lt;br /&gt;
 36 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 36, 0, (paramete; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; a - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0045 Undeclared identifier paramete. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated identifier won&#039;t work...&amp;lt;/font&amp;gt;&lt;br /&gt;
 37 !&lt;br /&gt;
 38 ! // EMPTY variadic arguments&lt;br /&gt;
 39 ! Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); &lt;br /&gt;
 39 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 39, 0, (paramete; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 ERROR===========&amp;gt; a - CZM0041 The invocation of macro Say contains fewer arguments than are required by the macro definition. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- What? It seems there HAS to be a variadic argument. Giving none won&#039;t work with this compiler&amp;lt;ref&amp;gt;I tried several compiler settings (f.e. LANGLVL), and even using __VA_OPT__.&amp;lt;/ref&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So what next? I couldn&#039;t explain why and how the truncation happened and started to follow the only valid lead: The CZM0041 error.&lt;br /&gt;
&lt;br /&gt;
You can find more here: https://en.wikipedia.org/wiki/Variadic_macro (including this very interesting sentence: Both the [C99] and [C++11] standards &#039;&#039;&#039;require at least one argument&#039;&#039;&#039;, but since [C++20] this limitation has been lifted through the __VA_OPT__ functional macro. The __VA_OPT__ macro is replaced by its argument when arguments are present, and omitted otherwise. Common compilers also permit passing zero arguments before this addition, however.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=693</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=693"/>
		<updated>2019-11-28T10:08:28Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* What happened */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
=== The code used ===&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;); // With additional arguments&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); // just a plain message&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #if (kDebug)&lt;br /&gt;
    #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
 #else&lt;br /&gt;
    #define Say(logLevel, parameter, ...) //#define KeinLoggingHeute&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== What happened ===&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and ran into these error messages:&lt;br /&gt;
 35 ! // TEST W/ ADDITIONAL variadic arguments ! &lt;br /&gt;
 36 ! Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;);&lt;br /&gt;
 36 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 36, 0, (paramete; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; a - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0045 Undeclared identifier paramete. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated identifier won&#039;t work...&amp;lt;/font&amp;gt;&lt;br /&gt;
 37 !&lt;br /&gt;
 38 ! // EMPTY variadic arguments&lt;br /&gt;
 39 ! Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); &lt;br /&gt;
 39 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 39, 0, (paramete; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 ERROR===========&amp;gt; a - CZM0041 The invocation of macro Say contains fewer arguments than are required by the macro definition. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- What? It seems there HAS to be a variadic argument. Giving none won&#039;t work with this compiler&amp;lt;ref&amp;gt;I tried several compiler settings (f.e. LANGLVL), and even using __VA_OPT__.&amp;lt;/ref&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So what next? I couldn&#039;t explain the truncation and started to follow the only valid lead: The CZM0041 error.&lt;br /&gt;
&lt;br /&gt;
You can find more here: https://en.wikipedia.org/wiki/Variadic_macro (including this very interesting sentence: Both the [C99] and [C++11] standards &#039;&#039;&#039;require at least one argument&#039;&#039;&#039;, but since [C++20] this limitation has been lifted through the __VA_OPT__ functional macro. The __VA_OPT__ macro is replaced by its argument when arguments are present, and omitted otherwise. Common compilers also permit passing zero arguments before this addition, however.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=692</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=692"/>
		<updated>2019-11-28T10:06:23Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* What happened */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
=== The code used ===&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;); // With additional arguments&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); // just a plain message&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #if (kDebug)&lt;br /&gt;
    #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
 #else&lt;br /&gt;
    #define Say(logLevel, parameter, ...) //#define KeinLoggingHeute&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== What happened ===&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and ran into these error messages:&lt;br /&gt;
 35 ! // TEST W/ ADDITIONAL variadic arguments ! &lt;br /&gt;
 36 ! Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;);&lt;br /&gt;
 36 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 36, 0, (paramete; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; a - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0045 Undeclared identifier paramete. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated identifier won&#039;t work...&amp;lt;/font&amp;gt;&lt;br /&gt;
 37 !&lt;br /&gt;
 38 ! // EMPTY variadic arguments&lt;br /&gt;
 39 ! Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); &lt;br /&gt;
 39 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 39, 0, (paramete; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 ERROR===========&amp;gt; a - CZM0041 The invocation of macro Say contains fewer arguments than are required by the macro definition. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- What? It seems there HAS to be a variadic argument. Giving none won&#039;t work with this compiler&amp;lt;ref&amp;gt;I tried several compiler settings (f.e. LANGLVL), and even using __VA_OPT__. You can find more here: https://en.wikipedia.org/wiki/Variadic_macro (including this very interesting sentence: Both the [C99] and [C++11] standards &#039;&#039;&#039;require at least one argument&#039;&#039;&#039;, but since [C++20] this limitation has been lifted through the __VA_OPT__ functional macro. The __VA_OPT__ macro is replaced by its argument when arguments are present, and omitted otherwise. Common compilers also permit passing zero arguments before this addition, however.&amp;quot;&amp;lt;/ref&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=691</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=691"/>
		<updated>2019-11-28T10:06:05Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* What happened */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
=== The code used ===&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;); // With additional arguments&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); // just a plain message&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #if (kDebug)&lt;br /&gt;
    #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
 #else&lt;br /&gt;
    #define Say(logLevel, parameter, ...) //#define KeinLoggingHeute&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== What happened ===&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and ran into these error messages:&lt;br /&gt;
 35 ! // TEST W/ ADDITIONAL variadic arguments ! &lt;br /&gt;
 36 ! Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;);&lt;br /&gt;
 36 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 36, 0, (paramete; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; a - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0045 Undeclared identifier paramete. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated identifier won&#039;t work...&amp;lt;/font&amp;gt;&lt;br /&gt;
 37 !&lt;br /&gt;
 38 ! // EMPTY variadic arguments&lt;br /&gt;
 39 ! Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); &lt;br /&gt;
 39 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 39, 0, (paramete; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Note the truncated line! (but the ; is there!)&amp;lt;/font&amp;gt;&lt;br /&gt;
 ERROR===========&amp;gt; a - CZM0041 The invocation of macro Say contains fewer arguments than are required by the macro definition. &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- What? It seems there HAS to be a variadic argument. Giving none won&#039;t work with this compiler&amp;lt;ref&amp;gt;I tried several compiler settings (LANGLVL), and even using __VA_OPT__. You can find more here: https://en.wikipedia.org/wiki/Variadic_macro (including this very interesting sentence: Both the [C99] and [C++11] standards &#039;&#039;&#039;require at least one argument&#039;&#039;&#039;, but since [C++20] this limitation has been lifted through the __VA_OPT__ functional macro. The __VA_OPT__ macro is replaced by its argument when arguments are present, and omitted otherwise. Common compilers also permit passing zero arguments before this addition, however.&amp;quot;&amp;lt;/ref&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;? &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;--- Obviously this truncated line misses some characters...&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=690</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=690"/>
		<updated>2019-11-28T10:00:02Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* What happened */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
=== The code used ===&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;); // With additional arguments&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); // just a plain message&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #if (kDebug)&lt;br /&gt;
    #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
 #else&lt;br /&gt;
    #define Say(logLevel, parameter, ...) //#define KeinLoggingHeute&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== What happened ===&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and ran into these error messages:&lt;br /&gt;
 35 ! // TEST W/ ADDITIONAL variadic arguments ! &lt;br /&gt;
 36 ! Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;);&lt;br /&gt;
 36 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 36, 0, (paramete; &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;Note the truncated line!&amp;lt;/font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; a - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;?&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0045 Undeclared identifier paramete.&lt;br /&gt;
 37 !&lt;br /&gt;
 38 ! // EMPTY variadic arguments&lt;br /&gt;
 39 ! Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); &lt;br /&gt;
 39 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 39, 0, (paramete; + 39&lt;br /&gt;
 ERROR===========&amp;gt; a - CZM0041 The invocation of macro Say contains fewer arguments than are required by the macro definition.&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;?&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=689</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=689"/>
		<updated>2019-11-28T09:59:46Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* What happened */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
=== The code used ===&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;); // With additional arguments&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); // just a plain message&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #if (kDebug)&lt;br /&gt;
    #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
 #else&lt;br /&gt;
    #define Say(logLevel, parameter, ...) //#define KeinLoggingHeute&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== What happened ===&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and ran into these error messages:&lt;br /&gt;
 35 ! // TEST W/ ADDITIONAL variadic arguments ! &lt;br /&gt;
 36 ! Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;);&lt;br /&gt;
 36 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 36, 0, (paramete; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;Note the truncated line!&amp;lt;font&amp;gt;&lt;br /&gt;
 SEVERE==========&amp;gt; a - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;?&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0045 Undeclared identifier paramete.&lt;br /&gt;
 37 !&lt;br /&gt;
 38 ! // EMPTY variadic arguments&lt;br /&gt;
 39 ! Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); &lt;br /&gt;
 39 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 39, 0, (paramete; + 39&lt;br /&gt;
 ERROR===========&amp;gt; a - CZM0041 The invocation of macro Say contains fewer arguments than are required by the macro definition.&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;?&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=688</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=688"/>
		<updated>2019-11-28T09:58:04Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* What happened */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
=== The code used ===&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;); // With additional arguments&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); // just a plain message&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #if (kDebug)&lt;br /&gt;
    #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
 #else&lt;br /&gt;
    #define Say(logLevel, parameter, ...) //#define KeinLoggingHeute&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== What happened ===&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and ran into these error messages:&lt;br /&gt;
 35 ! // TEST W/ ADDITIONAL variadic arguments ! &lt;br /&gt;
 36 ! Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;);&lt;br /&gt;
 36 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 36, 0, (paramete;&lt;br /&gt;
 SEVERE==========&amp;gt; a - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;?&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0045 Undeclared identifier paramete.&lt;br /&gt;
 37 !&lt;br /&gt;
 38 ! // EMPTY variadic arguments&lt;br /&gt;
 39 ! Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); &lt;br /&gt;
 39 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 39, 0, (paramete; + 39&lt;br /&gt;
 ERROR===========&amp;gt; a - CZM0041 The invocation of macro Say contains fewer arguments than are required by the macro definition.&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;?&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=687</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=687"/>
		<updated>2019-11-28T09:57:53Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* What happened */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
=== The code used ===&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;); // With additional arguments&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); // just a plain message&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #if (kDebug)&lt;br /&gt;
    #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
 #else&lt;br /&gt;
    #define Say(logLevel, parameter, ...) //#define KeinLoggingHeute&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== What happened ===&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and ran into these error messages:&lt;br /&gt;
 35 ! // TEST W/ ADDITIONAL variadic arguments ! &lt;br /&gt;
 36 ! Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;);&lt;br /&gt;
 36 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 36, 0, (paramete;&lt;br /&gt;
 SEVERE==========&amp;gt; a - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;?&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0045 Undeclared identifier paramete.&lt;br /&gt;
 38 ! // EMPTY variadic arguments&lt;br /&gt;
 39 ! Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); &lt;br /&gt;
 39 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 39, 0, (paramete; + 39&lt;br /&gt;
 ERROR===========&amp;gt; a - CZM0041 The invocation of macro Say contains fewer arguments than are required by the macro definition.&lt;br /&gt;
 SEVERE==========&amp;gt; b - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;?&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=686</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=686"/>
		<updated>2019-11-28T09:55:51Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* The code used */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
=== The code used ===&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;); // With additional arguments&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); // just a plain message&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #if (kDebug)&lt;br /&gt;
    #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
 #else&lt;br /&gt;
    #define Say(logLevel, parameter, ...) //#define KeinLoggingHeute&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== What happened ===&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and ran into these error messages:&lt;br /&gt;
35 36 36&lt;br /&gt;
&lt;br /&gt;
! // TEST W/ ADDITIONAL variadic arguments ! 35 ! Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;); ! 36 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 36, 0, (paramete; + 36&lt;br /&gt;
===========&amp;gt; ........................................................b.......a................................. *=SEVERE==========&amp;gt; a - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;?&lt;br /&gt;
*=SEVERE==========&amp;gt; b - CZM0045 Undeclared identifier paramete.&lt;br /&gt;
37 ! ! 37 38 ! // EMPTY variadic arguments ! 38 39 ! Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); ! 39 39 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 39, 0, (paramete; + 39&lt;br /&gt;
===========&amp;gt; ...........................................................a....b................................. *=ERROR===========&amp;gt; a - CZM0041 The invocation of macro Say contains fewer arguments than are required by the macro definition. *=SEVERE==========&amp;gt; b - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;?&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=685</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=685"/>
		<updated>2019-11-28T09:55:21Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* What happened */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
=== The code used ===&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #if (kDebug)&lt;br /&gt;
    #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
 #else&lt;br /&gt;
    #define Say(logLevel, parameter, ...) //#define KeinLoggingHeute&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== What happened ===&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and ran into these error messages:&lt;br /&gt;
35 36 36&lt;br /&gt;
&lt;br /&gt;
! // TEST W/ ADDITIONAL variadic arguments ! 35 ! Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;); ! 36 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 36, 0, (paramete; + 36&lt;br /&gt;
===========&amp;gt; ........................................................b.......a................................. *=SEVERE==========&amp;gt; a - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;?&lt;br /&gt;
*=SEVERE==========&amp;gt; b - CZM0045 Undeclared identifier paramete.&lt;br /&gt;
37 ! ! 37 38 ! // EMPTY variadic arguments ! 38 39 ! Say(0, &amp;quot;Error: Socket creation failed...\n&amp;quot;); ! 39 39 + logWithMethodName(&amp;quot;connectAMI&amp;quot;, 39, 0, (paramete; + 39&lt;br /&gt;
===========&amp;gt; ...........................................................a....b................................. *=ERROR===========&amp;gt; a - CZM0041 The invocation of macro Say contains fewer arguments than are required by the macro definition. *=SEVERE==========&amp;gt; b - CZM0277 Syntax error: possible missing &#039;)&#039; or &#039;,&#039;?&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=684</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=684"/>
		<updated>2019-11-28T09:54:10Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* The code used */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
=== The code used ===&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %s\n&amp;quot;, &amp;quot;just a random argument&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #if (kDebug)&lt;br /&gt;
    #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
 #else&lt;br /&gt;
    #define Say(logLevel, parameter, ...) //#define KeinLoggingHeute&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== What happened ===&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and ran into these error messages:&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=683</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=683"/>
		<updated>2019-11-28T09:53:23Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* What happened */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
=== The code used ===&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %d\n&amp;quot;, errNum);&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #if (kDebug)&lt;br /&gt;
    #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
 #else&lt;br /&gt;
    #define Say(logLevel, parameter, ...) //#define KeinLoggingHeute&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
=== What happened ===&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and ran into these error messages:&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=682</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=682"/>
		<updated>2019-11-28T09:53:10Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* The Issue */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
=== The code used ===&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %d\n&amp;quot;, errNum);&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #if (kDebug)&lt;br /&gt;
    #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
 #else&lt;br /&gt;
    #define Say(logLevel, parameter, ...) //#define KeinLoggingHeute&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
=== What happened ===&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and ran into these error messages:&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=681</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=681"/>
		<updated>2019-11-28T09:52:28Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* The Issue */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %d\n&amp;quot;, errNum);&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #if (kDebug)&lt;br /&gt;
    #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
 #else&lt;br /&gt;
    #define Say(logLevel, parameter, ...) //#define KeinLoggingHeute&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Looks fine, you say? I&#039;d agree. This code worked for me for years. Then I compiled it on our AS/400...&lt;br /&gt;
&amp;lt;code&amp;gt;CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Note the OUTPUT-Option! If not given, you will get only &amp;lt;code&amp;gt;Module NTWRKNG is not created because statement errors occurred.&amp;lt;/code&amp;gt; info, and no further indication of what went wrong. With &amp;lt;code&amp;gt;OUTPUT(*PRINT)&amp;lt;/code&amp;gt; given, you will receive detailed information in your print queue.&lt;br /&gt;
&lt;br /&gt;
and ran into these error messages:&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=680</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=680"/>
		<updated>2019-11-28T09:47:05Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* The Issue */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %d\n&amp;quot;, errNum);&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #if (kDebug)&lt;br /&gt;
    #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
 #else&lt;br /&gt;
    #define Say(logLevel, parameter, ...) //#define KeinLoggingHeute&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=679</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=679"/>
		<updated>2019-11-28T09:45:46Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* The Issue */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %d\n&amp;quot;, errNum);&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
 #if (kDebug)&lt;br /&gt;
    #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
 #else&lt;br /&gt;
    #define Say(logLevel, parameter, ...) //#define KeinLoggingHeute&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments: https://jameshfisher.com/2016/11/23/c-varargs/ &amp;amp; https://unixpapa.com/incnote/variadic.html (!) &amp;amp; https://github.com/mpaland/printf/blob/master/printf.c (!) &amp;amp; https://stackoverflow.com/questions/21540778/pass-varargs-to-printf (!) */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 #ifdef USEOWNIMPLEMENTATIONOFVSPRINTF&lt;br /&gt;
 			memset(msg2, &#039;\0&#039;, kMaxMsgLen);&lt;br /&gt;
 			int msg2i=0;&lt;br /&gt;
 			char tmp[kMaxMsgLen];&lt;br /&gt;
 			char *p=NULL; //format;&lt;br /&gt;
 			int	ci;&lt;br /&gt;
 			for (ci=0; ci&amp;lt;strlen(format) &amp;amp;&amp;amp; msg2i&amp;lt;kMaxMsgLen-1; ci++)&lt;br /&gt;
 			{&lt;br /&gt;
 				/* This works only for SOME formats, like %s or %d (NO PRECISION!)! Everything unknown will be treated as %d! */&lt;br /&gt;
 				char c=format[ci];&lt;br /&gt;
 				if (c==&#039;%&#039;)&lt;br /&gt;
 				{&lt;br /&gt;
 					/* Uh! It&#039;s a parameter-dingens */&lt;br /&gt;
 					char t=format[ci+1]; // get its type. NO SUPPORT FOR PRECISION YET!&lt;br /&gt;
 					if (t==&#039;s&#039;)&lt;br /&gt;
 					{	/* It&#039;s a string */&lt;br /&gt;
 						sprintf(tmp, &amp;quot;%s&amp;quot;, va_arg(argp, char*));&lt;br /&gt;
 						strcat(msg2, tmp);&lt;br /&gt;
 						msg2i=strlen(msg2);&lt;br /&gt;
 						ci++; // omit the &amp;quot;s&amp;quot;&lt;br /&gt;
 					}&lt;br /&gt;
 					else&lt;br /&gt;
 					{	/* It&#039;s something else. Hopefully some kind of number */&lt;br /&gt;
 						sprintf(tmp, &amp;quot;%d&amp;quot;, va_arg(argp, int));&lt;br /&gt;
 						strcat(msg2, tmp);&lt;br /&gt;
 						msg2i=strlen(msg2);&lt;br /&gt;
 						ci++; // omit the &amp;quot;s&amp;quot;&lt;br /&gt;
 					}&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					/* Add everything else to the buffer */&lt;br /&gt;
 					msg2[msg2i]=c;&lt;br /&gt;
 					msg2i++;&lt;br /&gt;
 				}&lt;br /&gt;
 			}&lt;br /&gt;
 #else&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=678</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=678"/>
		<updated>2019-11-28T09:45:22Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* The Issue */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message, depending on the severity/log level.&lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %d\n&amp;quot;, errNum);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
/* Debugging internals, don&#039;t change! */&lt;br /&gt;
 #if (kDebug)&lt;br /&gt;
    #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
 #else&lt;br /&gt;
    #define Say(logLevel, parameter, ...) //#define KeinLoggingHeute&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments: https://jameshfisher.com/2016/11/23/c-varargs/ &amp;amp; https://unixpapa.com/incnote/variadic.html (!) &amp;amp; https://github.com/mpaland/printf/blob/master/printf.c (!) &amp;amp; https://stackoverflow.com/questions/21540778/pass-varargs-to-printf (!) */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 #ifdef USEOWNIMPLEMENTATIONOFVSPRINTF&lt;br /&gt;
 			memset(msg2, &#039;\0&#039;, kMaxMsgLen);&lt;br /&gt;
 			int msg2i=0;&lt;br /&gt;
 			char tmp[kMaxMsgLen];&lt;br /&gt;
 			char *p=NULL; //format;&lt;br /&gt;
 			int	ci;&lt;br /&gt;
 			for (ci=0; ci&amp;lt;strlen(format) &amp;amp;&amp;amp; msg2i&amp;lt;kMaxMsgLen-1; ci++)&lt;br /&gt;
 			{&lt;br /&gt;
 				/* This works only for SOME formats, like %s or %d (NO PRECISION!)! Everything unknown will be treated as %d! */&lt;br /&gt;
 				char c=format[ci];&lt;br /&gt;
 				if (c==&#039;%&#039;)&lt;br /&gt;
 				{&lt;br /&gt;
 					/* Uh! It&#039;s a parameter-dingens */&lt;br /&gt;
 					char t=format[ci+1]; // get its type. NO SUPPORT FOR PRECISION YET!&lt;br /&gt;
 					if (t==&#039;s&#039;)&lt;br /&gt;
 					{	/* It&#039;s a string */&lt;br /&gt;
 						sprintf(tmp, &amp;quot;%s&amp;quot;, va_arg(argp, char*));&lt;br /&gt;
 						strcat(msg2, tmp);&lt;br /&gt;
 						msg2i=strlen(msg2);&lt;br /&gt;
 						ci++; // omit the &amp;quot;s&amp;quot;&lt;br /&gt;
 					}&lt;br /&gt;
 					else&lt;br /&gt;
 					{	/* It&#039;s something else. Hopefully some kind of number */&lt;br /&gt;
 						sprintf(tmp, &amp;quot;%d&amp;quot;, va_arg(argp, int));&lt;br /&gt;
 						strcat(msg2, tmp);&lt;br /&gt;
 						msg2i=strlen(msg2);&lt;br /&gt;
 						ci++; // omit the &amp;quot;s&amp;quot;&lt;br /&gt;
 					}&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					/* Add everything else to the buffer */&lt;br /&gt;
 					msg2[msg2i]=c;&lt;br /&gt;
 					msg2i++;&lt;br /&gt;
 				}&lt;br /&gt;
 			}&lt;br /&gt;
 #else&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=677</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=677"/>
		<updated>2019-11-28T09:44:23Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* The Issue */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message. &lt;br /&gt;
&lt;br /&gt;
This is how it&#039;s used in the code:&lt;br /&gt;
 Say(0, &amp;quot;Error: Socket creation failed with %d\n&amp;quot;, errNum);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
/* Debugging internals, don&#039;t change! */&lt;br /&gt;
 #if (kDebug)&lt;br /&gt;
    #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__);&lt;br /&gt;
 #else&lt;br /&gt;
    #define Say(logLevel, parameter, ...) //#define KeinLoggingHeute&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments: https://jameshfisher.com/2016/11/23/c-varargs/ &amp;amp; https://unixpapa.com/incnote/variadic.html (!) &amp;amp; https://github.com/mpaland/printf/blob/master/printf.c (!) &amp;amp; https://stackoverflow.com/questions/21540778/pass-varargs-to-printf (!) */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 #ifdef USEOWNIMPLEMENTATIONOFVSPRINTF&lt;br /&gt;
 			memset(msg2, &#039;\0&#039;, kMaxMsgLen);&lt;br /&gt;
 			int msg2i=0;&lt;br /&gt;
 			char tmp[kMaxMsgLen];&lt;br /&gt;
 			char *p=NULL; //format;&lt;br /&gt;
 			int	ci;&lt;br /&gt;
 			for (ci=0; ci&amp;lt;strlen(format) &amp;amp;&amp;amp; msg2i&amp;lt;kMaxMsgLen-1; ci++)&lt;br /&gt;
 			{&lt;br /&gt;
 				/* This works only for SOME formats, like %s or %d (NO PRECISION!)! Everything unknown will be treated as %d! */&lt;br /&gt;
 				char c=format[ci];&lt;br /&gt;
 				if (c==&#039;%&#039;)&lt;br /&gt;
 				{&lt;br /&gt;
 					/* Uh! It&#039;s a parameter-dingens */&lt;br /&gt;
 					char t=format[ci+1]; // get its type. NO SUPPORT FOR PRECISION YET!&lt;br /&gt;
 					if (t==&#039;s&#039;)&lt;br /&gt;
 					{	/* It&#039;s a string */&lt;br /&gt;
 						sprintf(tmp, &amp;quot;%s&amp;quot;, va_arg(argp, char*));&lt;br /&gt;
 						strcat(msg2, tmp);&lt;br /&gt;
 						msg2i=strlen(msg2);&lt;br /&gt;
 						ci++; // omit the &amp;quot;s&amp;quot;&lt;br /&gt;
 					}&lt;br /&gt;
 					else&lt;br /&gt;
 					{	/* It&#039;s something else. Hopefully some kind of number */&lt;br /&gt;
 						sprintf(tmp, &amp;quot;%d&amp;quot;, va_arg(argp, int));&lt;br /&gt;
 						strcat(msg2, tmp);&lt;br /&gt;
 						msg2i=strlen(msg2);&lt;br /&gt;
 						ci++; // omit the &amp;quot;s&amp;quot;&lt;br /&gt;
 					}&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					/* Add everything else to the buffer */&lt;br /&gt;
 					msg2[msg2i]=c;&lt;br /&gt;
 					msg2i++;&lt;br /&gt;
 				}&lt;br /&gt;
 			}&lt;br /&gt;
 #else&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=676</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=676"/>
		<updated>2019-11-28T09:38:03Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* The Issue */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that I have been using for years in macOS and Linux projects. It&#039;s purpose is to log messages with the source&#039;s filename, line number and some custom message. &lt;br /&gt;
&lt;br /&gt;
This how it&#039;s used in the code:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is how the define adds the filename and linenumber:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is the actual logging code (you can skip that, it&#039;s not relevant, except for the parameters):&lt;br /&gt;
&lt;br /&gt;
 void	logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...)&lt;br /&gt;
 {&lt;br /&gt;
 		if (gLogLevel&amp;gt;=logLevel)&lt;br /&gt;
 		{&lt;br /&gt;
 			/* Variables */&lt;br /&gt;
 			char msg1[kMaxMsgLen];&lt;br /&gt;
 			char msg2[kMaxMsgLen];&lt;br /&gt;
 			char lMethodName[kMaxMethodLen];&lt;br /&gt;
 			&lt;br /&gt;
 			/* Get the arguments: https://jameshfisher.com/2016/11/23/c-varargs/ &amp;amp; https://unixpapa.com/incnote/variadic.html (!) &amp;amp; https://github.com/mpaland/printf/blob/master/printf.c (!) &amp;amp; https://stackoverflow.com/questions/21540778/pass-varargs-to-printf (!) */&lt;br /&gt;
 			va_list argp;&lt;br /&gt;
 			va_start(argp, format); // format being the last argument before &#039;...&#039;&lt;br /&gt;
 &lt;br /&gt;
 			/* Combine format and arguments! */&lt;br /&gt;
 #ifdef USEOWNIMPLEMENTATIONOFVSPRINTF&lt;br /&gt;
 			memset(msg2, &#039;\0&#039;, kMaxMsgLen);&lt;br /&gt;
 			int msg2i=0;&lt;br /&gt;
 			char tmp[kMaxMsgLen];&lt;br /&gt;
 			char *p=NULL; //format;&lt;br /&gt;
 			int	ci;&lt;br /&gt;
 			for (ci=0; ci&amp;lt;strlen(format) &amp;amp;&amp;amp; msg2i&amp;lt;kMaxMsgLen-1; ci++)&lt;br /&gt;
 			{&lt;br /&gt;
 				/* This works only for SOME formats, like %s or %d (NO PRECISION!)! Everything unknown will be treated as %d! */&lt;br /&gt;
 				char c=format[ci];&lt;br /&gt;
 				if (c==&#039;%&#039;)&lt;br /&gt;
 				{&lt;br /&gt;
 					/* Uh! It&#039;s a parameter-dingens */&lt;br /&gt;
 					char t=format[ci+1]; // get its type. NO SUPPORT FOR PRECISION YET!&lt;br /&gt;
 					if (t==&#039;s&#039;)&lt;br /&gt;
 					{	/* It&#039;s a string */&lt;br /&gt;
 						sprintf(tmp, &amp;quot;%s&amp;quot;, va_arg(argp, char*));&lt;br /&gt;
 						strcat(msg2, tmp);&lt;br /&gt;
 						msg2i=strlen(msg2);&lt;br /&gt;
 						ci++; // omit the &amp;quot;s&amp;quot;&lt;br /&gt;
 					}&lt;br /&gt;
 					else&lt;br /&gt;
 					{	/* It&#039;s something else. Hopefully some kind of number */&lt;br /&gt;
 						sprintf(tmp, &amp;quot;%d&amp;quot;, va_arg(argp, int));&lt;br /&gt;
 						strcat(msg2, tmp);&lt;br /&gt;
 						msg2i=strlen(msg2);&lt;br /&gt;
 						ci++; // omit the &amp;quot;s&amp;quot;&lt;br /&gt;
 					}&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					/* Add everything else to the buffer */&lt;br /&gt;
 					msg2[msg2i]=c;&lt;br /&gt;
 					msg2i++;&lt;br /&gt;
 				}&lt;br /&gt;
 			}&lt;br /&gt;
 #else&lt;br /&gt;
 			vsprintf(msg2, format, argp);&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(methodName) &amp;gt; kMaxMethodLen)&lt;br /&gt;
 				{&lt;br /&gt;
 					memcpy(lMethodName, methodName, kMaxMethodLen-1);&lt;br /&gt;
 					lMethodName[kMaxMethodLen]=&#039;\0&#039;;&lt;br /&gt;
 				}&lt;br /&gt;
 				else&lt;br /&gt;
 				{&lt;br /&gt;
 					strcpy(lMethodName, methodName);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 				if (strlen(format) &amp;gt; kMaxFormatLen) format[kMaxFormatLen]=&#039;\0&#039;;&lt;br /&gt;
 				&lt;br /&gt;
 				sprintf(msg1, &amp;quot;%s (%d): &amp;quot;, lMethodName, lineNumber);&lt;br /&gt;
 				strcat(msg1, msg2);&lt;br /&gt;
 &lt;br /&gt;
 				/* Output to stdout */&lt;br /&gt;
 				if (1)&lt;br /&gt;
 				{&lt;br /&gt;
 					printf(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 				/* Write to syslog */&lt;br /&gt;
 				if (0)&lt;br /&gt;
 				{&lt;br /&gt;
 					//logger(msg1);&lt;br /&gt;
 				}&lt;br /&gt;
 			&lt;br /&gt;
 			va_end (argp);&lt;br /&gt;
 		}&lt;br /&gt;
 	&lt;br /&gt;
 	return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=675</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=675"/>
		<updated>2019-11-28T09:32:31Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* The Issue */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[User:Heiko]]&amp;lt;/ref&amp;gt; have some code that&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=674</id>
		<title>How to solve Variadic Arguments issue (using C)</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=How_to_solve_Variadic_Arguments_issue_(using_C)&amp;diff=674"/>
		<updated>2019-11-28T09:32:09Z</updated>

		<summary type="html">&lt;p&gt;Heiko: Created page with &amp;quot;First of all, what are Variadic Arguments (VA)? It&amp;#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &amp;#039;&amp;#039;&amp;#039;definitely&amp;#039;&amp;#039;&amp;#039; go...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First of all, what are Variadic Arguments (VA)?&lt;br /&gt;
It&#039;s a way to NOT define the number of arguments a function (or method) takes. You only define the args you &#039;&#039;&#039;definitely&#039;&#039;&#039; going to be given on &#039;&#039;&#039;every&#039;&#039;&#039; call. All additional arguments are then optional, but can be used if given.&lt;br /&gt;
&lt;br /&gt;
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.&lt;br /&gt;
&lt;br /&gt;
== The Issue ==&lt;br /&gt;
I&amp;lt;ref&amp;gt;[[Users:Heiko]]&amp;lt;/ref&amp;gt; have some code that&lt;br /&gt;
&lt;br /&gt;
== The Solution ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links&lt;br /&gt;
** https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=User:Heiko&amp;diff=673</id>
		<title>User:Heiko</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=User:Heiko&amp;diff=673"/>
		<updated>2019-11-28T09:27:14Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* Articles to maintain */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= About =&lt;br /&gt;
This is [[User:Heiko|Heiko]]s personal page, in which he maybe shares some private information or collects bits for new articles.&lt;br /&gt;
&lt;br /&gt;
== Personal information ==&lt;br /&gt;
[[User:Heiko|Heiko]] has been in IT since the 90s, but never worked with an AS/400&amp;amp;#x2026;until 2019. He&#039;ll document his first steps in the hope they will be useful to others.&lt;br /&gt;
&lt;br /&gt;
= Ideas for new articles =&lt;br /&gt;
tbd&lt;br /&gt;
&lt;br /&gt;
= Articles to maintain =&lt;br /&gt;
* [[Basic Software Development]]&lt;br /&gt;
** [[Beginners Project: 99 Bottles Of Beer (using REXX)]]&lt;br /&gt;
** [[Beginners Project: Hello World (using C)]]&lt;br /&gt;
** [[Beginners Project: Hello World (using database, display file and RPG)]]&lt;br /&gt;
** [[Beginners Project: Create a database and query it using ODBC from a linux machine]] &amp;lt;-- NEEDS A LOT OF WORK IN THE PHP DEPARTMENT!&lt;br /&gt;
* [[Editing Source Files using Eclipse and FTP]]&lt;br /&gt;
* [[Compile Sources Without Queuing]]&lt;br /&gt;
* [[How to solve Variadic Arguments issue (using C)]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Sandbox ==&lt;br /&gt;
=== Screen mit MW-Bordmitteln ===&lt;br /&gt;
&lt;br /&gt;
                                   Anmelden            &lt;br /&gt;
                                               System  . . . . . :   SLVRLAKE&lt;br /&gt;
                                               Subsystem . . . . :   QINTER&lt;br /&gt;
                                               Bildschirm  . . . :   QPADEV0004&lt;br /&gt;
 &lt;br /&gt;
                Benutzer  . . . . . . . . . . . .             &lt;br /&gt;
                Kennwort  . . . . . . . . . . . .&lt;br /&gt;
                Programm/Prozedur . . . . . . . .             &lt;br /&gt;
                Men}  . . . . . . . . . . . . . .             &lt;br /&gt;
                Aktuelle Bibliothek . . . . . . .             &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
                                        (C) COPYRIGHT IBM CORP. 1980, 2013.&lt;br /&gt;
&lt;br /&gt;
=== Und nun Screen mit Bordmitteln und etwas HTML-Foo ===&lt;br /&gt;
&amp;lt;p style=&amp;quot;color:green; background-color:black&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
                                   Anmelden                                       &amp;lt;br/&amp;gt;&lt;br /&gt;
                                               System  . . . . . :   SLVRLAKE     &amp;lt;br/&amp;gt;&lt;br /&gt;
                                               Subsystem . . . . :   QINTER       &amp;lt;br/&amp;gt;&lt;br /&gt;
                                               Bildschirm  . . . :   QPADEV0004   &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                Benutzer  . . . . . . . . . . . .                                 &amp;lt;br/&amp;gt;&lt;br /&gt;
                Kennwort  . . . . . . . . . . . .                                 &amp;lt;br/&amp;gt;&lt;br /&gt;
                Programm/Prozedur . . . . . . . .                                 &amp;lt;br/&amp;gt;&lt;br /&gt;
                Men}  . . . . . . . . . . . . . .                                 &amp;lt;br/&amp;gt;&lt;br /&gt;
                Aktuelle Bibliothek . . . . . . .                                 &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                        (C) COPYRIGHT IBM CORP. 1980, 2013.       &amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using (not-working) console-tag ===&lt;br /&gt;
&amp;lt;console&amp;gt;&lt;br /&gt;
Test&lt;br /&gt;
&amp;lt;/console&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;console&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                                   Anmelden            &lt;br /&gt;
                                               System  . . . . . :   SLVRLAKE&lt;br /&gt;
                                               Subsystem . . . . :   QINTER&lt;br /&gt;
                                               Bildschirm  . . . :   QPADEV0004&lt;br /&gt;
 &lt;br /&gt;
                Benutzer  . . . . . . . . . . . .             &lt;br /&gt;
                Kennwort  . . . . . . . . . . . .&lt;br /&gt;
                Programm/Prozedur . . . . . . . .             &lt;br /&gt;
                Men}  . . . . . . . . . . . . . .             &lt;br /&gt;
                Aktuelle Bibliothek . . . . . . .             &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
                                        (C) COPYRIGHT IBM CORP. 1980, 2013.&lt;br /&gt;
&amp;lt;/console&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links &lt;br /&gt;
** [[Basic Commands]]&lt;br /&gt;
* References:&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Basic Knowledge]]&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=User:Heiko&amp;diff=670</id>
		<title>User:Heiko</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=User:Heiko&amp;diff=670"/>
		<updated>2019-10-16T20:16:39Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* Articles to maintain */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= About =&lt;br /&gt;
This is [[User:Heiko|Heiko]]s personal page, in which he maybe shares some private information or collects bits for new articles.&lt;br /&gt;
&lt;br /&gt;
== Personal information ==&lt;br /&gt;
[[User:Heiko|Heiko]] has been in IT since the 90s, but never worked with an AS/400&amp;amp;#x2026;until 2019. He&#039;ll document his first steps in the hope they will be useful to others.&lt;br /&gt;
&lt;br /&gt;
= Ideas for new articles =&lt;br /&gt;
tbd&lt;br /&gt;
&lt;br /&gt;
= Articles to maintain =&lt;br /&gt;
* [[Basic Software Development]]&lt;br /&gt;
** [[Beginners Project: 99 Bottles Of Beer (using REXX)]]&lt;br /&gt;
** [[Beginners Project: Hello World (using C)]]&lt;br /&gt;
** [[Beginners Project: Hello World (using database, display file and RPG)]]&lt;br /&gt;
** [[Beginners Project: Create a database and query it using ODBC from a linux machine]] &amp;lt;-- NEEDS A LOT OF WORK IN THE PHP DEPARTMENT!&lt;br /&gt;
* [[Editing Source Files using Eclipse and FTP]]&lt;br /&gt;
* [[Compile Sources Without Queuing]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Sandbox ==&lt;br /&gt;
=== Screen mit MW-Bordmitteln ===&lt;br /&gt;
&lt;br /&gt;
                                   Anmelden            &lt;br /&gt;
                                               System  . . . . . :   SLVRLAKE&lt;br /&gt;
                                               Subsystem . . . . :   QINTER&lt;br /&gt;
                                               Bildschirm  . . . :   QPADEV0004&lt;br /&gt;
 &lt;br /&gt;
                Benutzer  . . . . . . . . . . . .             &lt;br /&gt;
                Kennwort  . . . . . . . . . . . .&lt;br /&gt;
                Programm/Prozedur . . . . . . . .             &lt;br /&gt;
                Men}  . . . . . . . . . . . . . .             &lt;br /&gt;
                Aktuelle Bibliothek . . . . . . .             &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
                                        (C) COPYRIGHT IBM CORP. 1980, 2013.&lt;br /&gt;
&lt;br /&gt;
=== Und nun Screen mit Bordmitteln und etwas HTML-Foo ===&lt;br /&gt;
&amp;lt;p style=&amp;quot;color:green; background-color:black&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
                                   Anmelden                                       &amp;lt;br/&amp;gt;&lt;br /&gt;
                                               System  . . . . . :   SLVRLAKE     &amp;lt;br/&amp;gt;&lt;br /&gt;
                                               Subsystem . . . . :   QINTER       &amp;lt;br/&amp;gt;&lt;br /&gt;
                                               Bildschirm  . . . :   QPADEV0004   &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                Benutzer  . . . . . . . . . . . .                                 &amp;lt;br/&amp;gt;&lt;br /&gt;
                Kennwort  . . . . . . . . . . . .                                 &amp;lt;br/&amp;gt;&lt;br /&gt;
                Programm/Prozedur . . . . . . . .                                 &amp;lt;br/&amp;gt;&lt;br /&gt;
                Men}  . . . . . . . . . . . . . .                                 &amp;lt;br/&amp;gt;&lt;br /&gt;
                Aktuelle Bibliothek . . . . . . .                                 &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                                                                  &amp;lt;br/&amp;gt;&lt;br /&gt;
                                        (C) COPYRIGHT IBM CORP. 1980, 2013.       &amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using (not-working) console-tag ===&lt;br /&gt;
&amp;lt;console&amp;gt;&lt;br /&gt;
Test&lt;br /&gt;
&amp;lt;/console&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;console&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                                   Anmelden            &lt;br /&gt;
                                               System  . . . . . :   SLVRLAKE&lt;br /&gt;
                                               Subsystem . . . . :   QINTER&lt;br /&gt;
                                               Bildschirm  . . . :   QPADEV0004&lt;br /&gt;
 &lt;br /&gt;
                Benutzer  . . . . . . . . . . . .             &lt;br /&gt;
                Kennwort  . . . . . . . . . . . .&lt;br /&gt;
                Programm/Prozedur . . . . . . . .             &lt;br /&gt;
                Men}  . . . . . . . . . . . . . .             &lt;br /&gt;
                Aktuelle Bibliothek . . . . . . .             &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
                                        (C) COPYRIGHT IBM CORP. 1980, 2013.&lt;br /&gt;
&amp;lt;/console&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* Links &lt;br /&gt;
** [[Basic Commands]]&lt;br /&gt;
* References:&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Basic Knowledge]]&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=Query_database_using_ODBC_from_a_linux_machine&amp;diff=669</id>
		<title>Query database using ODBC from a linux machine</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=Query_database_using_ODBC_from_a_linux_machine&amp;diff=669"/>
		<updated>2019-10-16T20:04:17Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* Output */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Accessing a AS/400 via ODBC is something that might come in handy some day, so I decided to explore how it can be done.&lt;br /&gt;
&lt;br /&gt;
Be warned: This is more like a log, showing (and hopefully solving) all issues I ran into doing this. I think this is more helpful than a ideal world example.&lt;br /&gt;
&lt;br /&gt;
== Create a database ==&lt;br /&gt;
I suggest you try [[Beginners Project: 99 Bottles Of Beer (using REXX)]] and [[Beginners Project: Hello World (using database, display file and RPG)]] before you try this!&amp;lt;ref&amp;gt;[[User:Heiko|Heiko]] made this pretty brief, f.e. not every &amp;lt;code&amp;gt;F3&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;&amp;amp;#x23CE;&amp;lt;/code&amp;gt; is noted.&amp;lt;/ref&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Create a database to play with ===&lt;br /&gt;
* This is the third project [[User:Heiko|Heiko]] did, so his personal Library was getting a bit cluttered. Therefore, let&#039;s create a library just for this niew project:&lt;br /&gt;
** &amp;lt;code&amp;gt;CRTLIB LIB(ODBC) TEXT(Library for ODBC project source)&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;CRTSRCPF FILE(ODBC/ODBCDB) RCDLEN(112) TEXT(&#039;Project ODBC and Database&#039;)&amp;lt;/code&amp;gt; to create new physical file to hold the DDS.&lt;br /&gt;
* &amp;lt;code&amp;gt;WRKMBRPDM FILE(ODBC/ODBCDB)&amp;lt;/code&amp;gt; Work with this file.&lt;br /&gt;
* &amp;lt;code&amp;gt;F6&amp;lt;/code&amp;gt; to create new member, insert member&#039;s name &amp;lt;code&amp;gt;ODBCDB&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;This wil change later. Read on...&amp;lt;/ref&amp;gt; and the type &amp;lt;code&amp;gt;PF&amp;lt;/code&amp;gt;:&amp;lt;br/&amp;gt;[[Image:ODBCDB01.png|666px]]&lt;br /&gt;
* Enter this DDS: ([https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/rzakc/rzakcdatel.htm Learn what the below means] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzasb/cpdtex.htm Especially time- and dateformats] [https://www.db2tutorial.com/db2-basics/db2-time/ Even more about wibbly-wobbly-timey-wimey-stuff] [https://www.ibm.com/support/knowledgecenter/en/SSEPEK_11.0.0/intro/src/tpc/db2z_datetimetimestamp.html and more])&lt;br /&gt;
         ***************** Datenanfang *******************************************************************************************&lt;br /&gt;
 0001.00      A          R CALLS                                                                                  191002          &lt;br /&gt;
 0002.00      A            CALLER        42A                                                                      191002          &lt;br /&gt;
 0003.00      A            CALLED        42A                                                                      191002          &lt;br /&gt;
 0004.00      A            DATE            L                TIMFMT(*ISO)                                          191002          &lt;br /&gt;
 0005.00      A            TIME            T                                                                      191002          &lt;br /&gt;
 0006.00      A            TIMESTAMP       Z                                                                      191002          &lt;br /&gt;
         ******************Datenende *********************************************************************************************&lt;br /&gt;
* &amp;lt;code&amp;gt;14&amp;lt;/code&amp;gt; to compile&amp;amp;#x2026;&amp;lt;br/&amp;gt;[[Image:ODBCDB02.png|666px]]&amp;lt;br/&amp;gt;&amp;amp;#x2026;I failed again. Stupid me. I can&#039;t create a new physical database file in the same place, where source physical file (with the same name!) exists.&lt;br /&gt;
** Just rename the DDS member from &amp;lt;code&amp;gt;ODBCDB&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;ODBCDBPF&amp;lt;/code&amp;gt;:&amp;lt;br/&amp;gt;[[Image:ODBCDB03.png|666px]]&amp;lt;br/&amp;gt;[[Image:ODBCDB04.png|666px]]&lt;br /&gt;
** And try again.&lt;br /&gt;
** Check with &amp;lt;code&amp;gt;DSPMSG&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;or use [[Compile Sources Without Queuing]]&amp;lt;/ref&amp;gt; whether the compile was successful or not. If it did, you find the new PF in the library:&amp;lt;br/&amp;gt;[[Image:ODBCDB10.png|666px]]&lt;br /&gt;
&lt;br /&gt;
=== Insert content into the database ===&lt;br /&gt;
* &amp;lt;code&amp;gt;STRSQL&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;F4&amp;lt;/code&amp;gt;&lt;br /&gt;
** Enter the library name, in this example &amp;lt;code&amp;gt;ODBC&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Shortcut: &amp;lt;code&amp;gt;STRSQL LIBOPT(ODBC)&amp;lt;/code&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
* In the interactive SQL session, enter:&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;INSERT INTO CALLS (CALLER, CALLED, DATE, TIME, TIMESTAMP) VALUES (&#039;Ernie&#039;, &#039;Bert&#039;, &#039;2019-10-05&#039;, &#039;23.23&#039;, &#039;2019-10-05 23:23:42&#039;)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Timestamp format: https://www.ibm.com/support/knowledgecenter/SSFMBX/com.ibm.swg.im.dashdb.sql.ref.doc/doc/r0007107.html&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;You can use either &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;:&amp;lt;/code&amp;gt; as delimiter in time fields. The proper way, according to the documentation I found, is: &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
* There are many ways to display the result:&lt;br /&gt;
** If you&#039;re still in STRSQL, enter: &amp;lt;code&amp;gt;SELECT * FROM CALLS&amp;lt;/code&amp;gt;&lt;br /&gt;
** On command line, try this: &amp;lt;code&amp;gt;DSPF FILE(ODBC/ODBCDBPF)&amp;lt;/code&amp;gt;&lt;br /&gt;
** Or use &amp;lt;code&amp;gt;STRDFU&amp;lt;/code&amp;gt;, select option 5 and fill out the displayed form&lt;br /&gt;
[[Image:ODBC_DSPF01.png|666px|Displayed using &amp;lt;code&amp;gt;DSPF&amp;lt;/code&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
== ODBC Queries ==&lt;br /&gt;
Make sure you&#039;ve set up your ODBC connection (&amp;lt;tt&amp;gt;/etc/odbc.ini&amp;lt;/tt&amp;gt;) correctly.&lt;br /&gt;
&lt;br /&gt;
=== Perl ===&lt;br /&gt;
Here is a nice [https://www.ibm.com/developerworks/data/library/techarticle/dm-0512greenstein/index.html HowTo] from IBM. Worth reading.&lt;br /&gt;
==== Script Source Code ====&lt;br /&gt;
 #!/usr/bin/perl&lt;br /&gt;
 use strict;&lt;br /&gt;
 use DBI;&lt;br /&gt;
 &lt;br /&gt;
 my $db_cfg=&amp;quot;YOURCONFIG&amp;quot;; # See your /etc/odbc.ini&lt;br /&gt;
 my $db_pwd=&amp;quot;YOURUSER&amp;quot;;&lt;br /&gt;
 my $db_user=&amp;quot;YOURPASSWORD&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 printf(&amp;quot;Connecting to source database on $db_cfg...\n&amp;quot;);&lt;br /&gt;
 my $dbh = DBI-&amp;gt;connect(&#039;DBI:ODBC:&#039; . $db_cfg, $db_user, $db_pwd, {PrintError =&amp;gt; 1, AutoCommit =&amp;gt; 1}); # Connecting to Db2 database&lt;br /&gt;
 if ( $dbh )&lt;br /&gt;
 {&lt;br /&gt;
 	my $sth = $dbh-&amp;gt;prepare (&amp;quot;SELECT * FROM ODBC/ODBCDBPF&amp;quot;);&lt;br /&gt;
 	if (!$sth-&amp;gt;execute)&lt;br /&gt;
 	{&lt;br /&gt;
 		printf(&amp;quot;Error: Preparing select on source failed.\n&amp;quot;);&lt;br /&gt;
 		die;&lt;br /&gt;
 	}&lt;br /&gt;
 	&lt;br /&gt;
 	my $fCaller; &lt;br /&gt;
 	my $fCalled;&lt;br /&gt;
 	my $fDate;&lt;br /&gt;
 	my $fTime;&lt;br /&gt;
 	my $fTS;	&lt;br /&gt;
 	while ( ($fCaller, $fCalled, $fDate, $fTime, $fTS) = $sth-&amp;gt;fetchrow ) # Read one row from source table&lt;br /&gt;
 	{&lt;br /&gt;
 		printf(&amp;quot;%s, %s, %s, %s, %s\n&amp;quot;, $fCaller, $fCalled, $fDate, $fTime, $fTS);&lt;br /&gt;
 	} &lt;br /&gt;
 &lt;br /&gt;
 	# Clean up last statements&lt;br /&gt;
 	$sth-&amp;gt;finish;&lt;br /&gt;
 &lt;br /&gt;
 	# Disconnect from database&lt;br /&gt;
 	if ( $dbh )&lt;br /&gt;
 	{&lt;br /&gt;
 		print(&amp;quot;Disconnecting from $db_cfg...\n&amp;quot;);&lt;br /&gt;
 		$dbh-&amp;gt;disconnect;&lt;br /&gt;
 	}&lt;br /&gt;
 }&lt;br /&gt;
 else&lt;br /&gt;
 {&lt;br /&gt;
 	printf(&amp;quot;Error: Connection to database (%s) failed:\n%s\n%s\n%s\n&amp;quot;, $db_cfg,	$DBI::err, $DBI::errstr, $DBI::state);&lt;br /&gt;
 	die;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
 $ ./as400-odbc.pl &lt;br /&gt;
 Connecting to source database on YOURCONFIG...&lt;br /&gt;
 Ernie                                      Bert                                       2019-10-05 23:24:00 2019-10-05 23:23:42.000000&lt;br /&gt;
 Bob                                        Heppo                                      2019-11-06 05:05:05 2019-10-05 23:23:42.000000&lt;br /&gt;
 Disconnecting from YOURCONFIG...&lt;br /&gt;
&lt;br /&gt;
=== PHP ===&lt;br /&gt;
I found several possible approaches:&lt;br /&gt;
* Use &amp;lt;code&amp;gt;odbc_&amp;lt;/code&amp;gt; command set&lt;br /&gt;
** [https://www.ibm.com/developerworks/library/os-php-odbc/index.html HowTo use PHP and ODBC]&amp;lt;ref&amp;gt;Sadly this is for mySQL. Db2 would be much more appreciated.&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Use &amp;lt;tt&amp;gt;PDO&amp;lt;/tt&amp;gt;&lt;br /&gt;
** [https://www.php.net/manual/en/ref.pdo-ibm.php Short Overview] &#039;&#039;&#039;&#039;&#039;@PoC: Is this compatible???&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
* Use Db2 driver &#039;&#039;&#039;&#039;&#039;@PoC: Is this compatible???&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
** [https://www.ibm.com/support/knowledgecenter/en/SS6NHC/com.ibm.swg.im.dashdb.doc/connecting/connect_driver_package.html Db2 client] &amp;amp; [https://public.dhe.ibm.com/ibmdl/export/pub/software/data/db2/drivers/odbc_cli/ direct link]&lt;br /&gt;
** [https://github.com/php/pecl-database-ibm_db2 Installation instructions]&lt;br /&gt;
** [https://www.php.net/manual/en/function.db2-connect.php Usage] and after client installation: &amp;lt;code&amp;gt;TBD -h&amp;lt;/code&amp;gt; might help!&lt;br /&gt;
&lt;br /&gt;
==== PHP Code using ODBC ====&lt;br /&gt;
Let me say right away, that didn&#039;t work out as easy as I hoped.&lt;br /&gt;
 &amp;lt;?php&lt;br /&gt;
 &lt;br /&gt;
 /* Sample Code: How to query a Db2 database on a AS/400 (iSeries) &lt;br /&gt;
  * Note:        apt-get install php-odbc might be necessary&lt;br /&gt;
  * About:       https://try-as400.pocnet.net&lt;br /&gt;
  * */&lt;br /&gt;
 &lt;br /&gt;
 $db_cfg=&amp;quot;YOURCONFIG&amp;quot;; # See your /etc/odbc.ini&lt;br /&gt;
 $db_user=&amp;quot;YOURUSER&amp;quot;;&lt;br /&gt;
 $db_pwd=&amp;quot;YOURPASSWORD&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 $dbh=odbc_connect($db_cfg, $db_user, $db_pwd);&lt;br /&gt;
 if ($dbh)&lt;br /&gt;
 {&lt;br /&gt;
 	$sql=&amp;quot;SELECT * FROM ODBC/ODBCDBPF&amp;quot;;&lt;br /&gt;
 	printf(&amp;quot;Preparing \&amp;quot;$sql\&amp;quot;...\n&amp;quot;);&lt;br /&gt;
 	$sth=odbc_prepare($dbh, $sql);&lt;br /&gt;
&lt;br /&gt;
As you can see, the source isn&#039;t complete. That&#039;s because I wasn&#039;t able to execute it any further. Output so far:&lt;br /&gt;
 Preparing &amp;quot;SELECT * FROM ODBC/ODBCDBPF&amp;quot;...&lt;br /&gt;
 &lt;br /&gt;
 mmap() failed: [12] Cannot allocate memory&lt;br /&gt;
 &lt;br /&gt;
 PHP Fatal error:  Out of memory (allocated 2097152) (tried to allocate 206158430251 bytes)&lt;br /&gt;
The driver seems to need 206158430251 bytes, that&#039;s 192GB, a bit greedy for my taste.&lt;br /&gt;
&lt;br /&gt;
After some research&amp;lt;ref&amp;gt;php-mmap-issue: https://stackoverflow.com/questions/42132558/odbc-prepare-gives-fatal-error-allowed-memory-size-exhausted&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;php-mmap-issue: https://stackoverflow.com/questions/21286589/linux-odbc-fatal-error-allowed-memory-size/21412667#21412667&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;unixodbc-32/64bit drivers: http://www.unixodbc.org/doc/db2.html&amp;lt;/ref&amp;gt;I&#039;m pretty sure, its old 32bit ODBC-drivers conflicting with 64bit PHP&amp;lt;ref&amp;gt;Oddly, the same drivers work with perl&amp;lt;/ref&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
STAY TUNED WE ARE WORKING ON A SOLUTION.&lt;br /&gt;
&lt;br /&gt;
==== PHP Code using DB2 client ====&lt;br /&gt;
That wasn&#039;t very smooth, either.&lt;br /&gt;
&lt;br /&gt;
I first installed some software:&lt;br /&gt;
* Get IBM&#039;s CLI driver: https://public.dhe.ibm.com/ibmdl/export/pub/software/data/db2/drivers/odbc_cli/ and move it to /home/clidriver&lt;br /&gt;
* Insert this into .bashrc:&lt;br /&gt;
 # CLI Driver (PHP -&amp;gt; Db2 (AS/400),&lt;br /&gt;
 export IBM_DB_HOME=/home/clidriver&lt;br /&gt;
 export LD_LIBRARY_PATH=${IBM_DB_HOME}/lib&lt;br /&gt;
 export PATH=${IBM_DB_HOME}/bin:$PATH&lt;br /&gt;
* apt-get install php-dev&lt;br /&gt;
* pecl install ibm_db2&lt;br /&gt;
* add extension=ibm_db2.so to /etc/php/7.0/cli/php.ini&lt;br /&gt;
* If used with apache (untested):&lt;br /&gt;
** add LD_LIBRARY_PATH as shown above to httpd.conf&lt;br /&gt;
** add extension=ibm_db2.so to /etc/php/7.0/apache2/php.ini&lt;br /&gt;
** Beyond: https://www.php.net/manual/en/ibm-db2.installation.php || https://github.com/php/pecl-database-ibm_db2 || https://public.dhe.ibm.com/ibmdl/export/pub/software/data/db2/drivers/odbc_cli/&lt;br /&gt;
&lt;br /&gt;
 $db_user=&amp;quot;YOURUSER&amp;quot;;&lt;br /&gt;
 $db_pwd=&amp;quot;YOURPASSWORT&amp;quot;;&lt;br /&gt;
 $db_db = &#039;ODBC&#039;;&lt;br /&gt;
 $db_hostname = &#039;silverlake.intern.mathpeter.com&#039;;&lt;br /&gt;
 $db_port = 8471; //50000; /* https://www.ibm.com/support/pages/tcpip-ports-required-ibm-i-access-and-related-functions */&lt;br /&gt;
 $db_options = array(&#039;autocommit&#039; =&amp;gt; DB2_AUTOCOMMIT_ON);&lt;br /&gt;
 &lt;br /&gt;
 ini_set(&amp;quot;display_errors&amp;quot;, 1);&lt;br /&gt;
 &lt;br /&gt;
 //$connectionString = &amp;quot;DRIVER={IBM DB2 ODBC DRIVER};DATABASE=$db_db;HOSTNAME=$db_hostname;PORT=$db_port;PROTOCOL=TCPIP;UID=$db_user;PWD=$db_pwd;&amp;quot;; // takes for ever to connect&lt;br /&gt;
 $connectionString = &amp;quot;DATABASE=$db_db;HOSTNAME=$db_hostname;PORT=$db_port;PROTOCOL=TCPIP;UID=$db_user;PWD=$db_pwd;&amp;quot;; // takes for ever to connect&lt;br /&gt;
 printf(&amp;quot;connectionString: $connectionString\n&amp;quot;);&lt;br /&gt;
 $dbh=db2_connect($connectionString, NULL, NULL, $db_options); // https://www.php.net/manual/en/function.db2-connect.php &lt;br /&gt;
&lt;br /&gt;
This code stalls at &amp;lt;code&amp;gt;db2_connect()&amp;lt;/code&amp;gt;. &amp;lt;tt&amp;gt;netstat&amp;lt;/tt&amp;gt; shows that the TCP-connection is &amp;lt;tt&amp;gt;ESTABLISHED&amp;lt;/tt&amp;gt;. It doesn&#039;t create heavy load or traffic. It doesn&#039;t run into a timeout.&lt;br /&gt;
&lt;br /&gt;
STAY TUNED - MAYBE I CAN GET THIS WORKING.&lt;br /&gt;
&lt;br /&gt;
==== PHP Code using PDO ====&lt;br /&gt;
TBD&lt;br /&gt;
&lt;br /&gt;
=== C ===&lt;br /&gt;
Nice to know:&lt;br /&gt;
* http://www.unixodbc.org&lt;br /&gt;
* http://www.unixodbc.org/doc/db2.html&lt;br /&gt;
* https://www.easysoft.com/developer/interfaces/odbc/linux.html&lt;br /&gt;
* https://www.easysoft.com/developer/languages/c/odbc_tutorial.html&lt;br /&gt;
* https://stackoverflow.com/questions/33020646/gcc-odbc-on-linux-is-not-linking&lt;br /&gt;
* You might need to install &amp;lt;tt&amp;gt;unixodbc-dev&amp;lt;/tt&amp;gt;&lt;br /&gt;
==== C Source Code ====&lt;br /&gt;
 /* File: as400-odbc.c&lt;br /&gt;
 * About: Learn more here: https://try-as400.pocnet.net&lt;br /&gt;
 */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;sql.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;sqlext.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 #define RESULT_LEN  256&lt;br /&gt;
 &lt;br /&gt;
 char *odbcConnectionString = &amp;quot;DSN=YOURCONFIG;UID=YOURLOGIN;PWD=YOURPASSWORD;&amp;quot;; // See /etc/odbc.ini for DSN, use your AS/400 account as credentials.&lt;br /&gt;
 &lt;br /&gt;
 #define CHECK_ERROR(e, s, h, t)\&lt;br /&gt;
 	(\&lt;br /&gt;
 		{\&lt;br /&gt;
 			if (e!=SQL_SUCCESS &amp;amp;&amp;amp; e != SQL_SUCCESS_WITH_INFO)\&lt;br /&gt;
 			{ extract_error(s, h, t); goto exit;}\&lt;br /&gt;
 		}\&lt;br /&gt;
 	)&lt;br /&gt;
 &lt;br /&gt;
 void extract_error(char *fn, SQLHANDLE handle, SQLSMALLINT type)&lt;br /&gt;
 {&lt;br /&gt;
 	SQLINTEGER i = 0;&lt;br /&gt;
 	SQLINTEGER NativeError;&lt;br /&gt;
 	SQLCHAR SQLState[7];&lt;br /&gt;
 	SQLCHAR MessageText[256];&lt;br /&gt;
 	SQLSMALLINT TextLength;&lt;br /&gt;
 	SQLRETURN ret;&lt;br /&gt;
 &lt;br /&gt;
 	fprintf(stderr, &amp;quot;\nThe driver reported the following error %s\n&amp;quot;, fn);&lt;br /&gt;
 	do&lt;br /&gt;
  	{&lt;br /&gt;
 		ret = SQLGetDiagRec(type, handle, ++i, SQLState, &amp;amp;NativeError,&lt;br /&gt;
 			MessageText, sizeof(MessageText), &amp;amp;TextLength);&lt;br /&gt;
 		if (SQL_SUCCEEDED(ret)) {&lt;br /&gt;
 			printf(&amp;quot;%s:%ld:%ld:%s\n&amp;quot;,&lt;br /&gt;
 				SQLState, (long)i, (long)NativeError, MessageText);&lt;br /&gt;
 		}&lt;br /&gt;
 	} while (ret == SQL_SUCCESS); &lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 int main()&lt;br /&gt;
 {&lt;br /&gt;
 &lt;br /&gt;
 	SQLHENV   henv = SQL_NULL_HENV;    // Environment&lt;br /&gt;
 	SQLHDBC   hdbc = SQL_NULL_HDBC;    // Connection handle&lt;br /&gt;
 	SQLHSTMT  hstmt = SQL_NULL_HSTMT;  // Statement handle&lt;br /&gt;
 	SQLRETURN retcode;&lt;br /&gt;
 	SQLCHAR   fCaller[RESULT_LEN];&lt;br /&gt;
 	SQLCHAR   fCalled[RESULT_LEN];&lt;br /&gt;
 	SQLCHAR   fDate[RESULT_LEN];&lt;br /&gt;
 	SQLCHAR   fTime[RESULT_LEN];&lt;br /&gt;
 	SQLCHAR   fTS[RESULT_LEN];&lt;br /&gt;
 	SQLCHAR   outstr[1024];&lt;br /&gt;
 	SQLSMALLINT outstrlen;&lt;br /&gt;
 	int i = 0;&lt;br /&gt;
 &lt;br /&gt;
 	// Allocate environment handle&lt;br /&gt;
 	retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &amp;amp;henv);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLAllocHandle(SQL_HANDLE_ENV)&amp;quot;, henv, SQL_HANDLE_ENV);&lt;br /&gt;
 &lt;br /&gt;
 	// Set the ODBC version environment attribute&lt;br /&gt;
 	retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLSetEnvAttr(SQL_ATTR_ODBC_VERSION)&amp;quot;, henv, SQL_HANDLE_ENV);&lt;br /&gt;
 &lt;br /&gt;
 	retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLSetEnvAttr(SQL_ATTR_ODBC_VERSION)&amp;quot;, henv, SQL_HANDLE_ENV);&lt;br /&gt;
 &lt;br /&gt;
 	// Allocate connection handle&lt;br /&gt;
 	retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &amp;amp;hdbc);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLAllocHandle(SQL_HANDLE_DBC)&amp;quot;, hdbc, SQL_HANDLE_DBC);&lt;br /&gt;
 &lt;br /&gt;
 	// Set login timeout to 5 seconds&lt;br /&gt;
 	SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLSetConnectAttr(SQL_LOGIN_TIMEOUT)&amp;quot;, hdbc, SQL_HANDLE_DBC);&lt;br /&gt;
 &lt;br /&gt;
 	// Connect to data source, replace with your connection string&lt;br /&gt;
 	retcode = SQLDriverConnect(hdbc, NULL, odbcConnectionString, SQL_NTS, outstr, sizeof(outstr), &amp;amp;outstrlen, SQL_DRIVER_NOPROMPT);&lt;br /&gt;
 &lt;br /&gt;
 	// Allocate statement handle&lt;br /&gt;
 	retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &amp;amp;hstmt);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLAllocHandle(SQL_HANDLE_STMT)&amp;quot;,	hstmt, SQL_HANDLE_STMT);&lt;br /&gt;
 &lt;br /&gt;
 	// Execute SQL Query&lt;br /&gt;
 	retcode = SQLExecDirect(hstmt, (SQLCHAR*) &amp;quot;SELECT * FROM ODBC/ODBCDBPF&amp;quot;, SQL_NTS);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLExecDirect()&amp;quot;, hstmt, SQL_HANDLE_STMT);&lt;br /&gt;
 &lt;br /&gt;
 	// Bind columns&lt;br /&gt;
 	retcode = SQLBindCol(hstmt, 1, SQL_C_CHAR, &amp;amp;fCaller, RESULT_LEN, 0);&lt;br /&gt;
 	retcode = SQLBindCol(hstmt, 2, SQL_C_CHAR, &amp;amp;fCalled, RESULT_LEN, 0);&lt;br /&gt;
 	retcode = SQLBindCol(hstmt, 3, SQL_C_CHAR, &amp;amp;fDate, RESULT_LEN, 0);&lt;br /&gt;
 	retcode = SQLBindCol(hstmt, 4, SQL_C_CHAR, &amp;amp;fTime, RESULT_LEN, 0);&lt;br /&gt;
 	retcode = SQLBindCol(hstmt, 5, SQL_C_CHAR, &amp;amp;fTS, RESULT_LEN, 0);&lt;br /&gt;
 &lt;br /&gt;
 	// Fetch and print each row of data until SQL_NO_DATA returned.&lt;br /&gt;
 	for (i = 0; ; i++)&lt;br /&gt;
 	{&lt;br /&gt;
 		retcode = SQLFetch(hstmt);&lt;br /&gt;
 		if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)&lt;br /&gt;
 		{&lt;br /&gt;
 			printf(&amp;quot;Row %d: %s\t%s\t%s\t%s\t%s\n&amp;quot;, i, fCaller, fCalled, fDate, fTime, fTS);&lt;br /&gt;
 		}&lt;br /&gt;
 		else&lt;br /&gt;
 		{&lt;br /&gt;
 			if (retcode != SQL_NO_DATA)&lt;br /&gt;
 			{&lt;br /&gt;
 				CHECK_ERROR(retcode, &amp;quot;SQLFetch()&amp;quot;, hstmt, SQL_HANDLE_STMT);&lt;br /&gt;
 			}&lt;br /&gt;
 			else&lt;br /&gt;
 			{&lt;br /&gt;
 				break;&lt;br /&gt;
 			}&lt;br /&gt;
 		}&lt;br /&gt;
 	}&lt;br /&gt;
 &lt;br /&gt;
 exit:&lt;br /&gt;
 &lt;br /&gt;
 	//&lt;br /&gt;
 	// Free handles&lt;br /&gt;
 	//&lt;br /&gt;
 	// Statement&lt;br /&gt;
 	if (hstmt != SQL_NULL_HSTMT)&lt;br /&gt;
 	{&lt;br /&gt;
 		SQLFreeHandle(SQL_HANDLE_STMT, hstmt);&lt;br /&gt;
 	}&lt;br /&gt;
 &lt;br /&gt;
 	// Connection&lt;br /&gt;
 	if (hdbc != SQL_NULL_HDBC)&lt;br /&gt;
 	{&lt;br /&gt;
 		SQLDisconnect(hdbc);&lt;br /&gt;
 		SQLFreeHandle(SQL_HANDLE_DBC, hdbc);&lt;br /&gt;
 	}&lt;br /&gt;
 &lt;br /&gt;
 	// Environment&lt;br /&gt;
 	if (henv != SQL_NULL_HENV)&lt;br /&gt;
 	{&lt;br /&gt;
 		SQLFreeHandle(SQL_HANDLE_ENV, henv);&lt;br /&gt;
 	}&lt;br /&gt;
 &lt;br /&gt;
 	return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
==== Compiling ====&lt;br /&gt;
 #!/bin/bash&lt;br /&gt;
 &lt;br /&gt;
 clear&lt;br /&gt;
 gcc as400-odbc.c -o as400-odbc_c -lodbc&lt;br /&gt;
Note the &amp;lt;code&amp;gt;-lodbc&amp;lt;/code&amp;gt; for linking against the ODBC-libraries.&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
 $./as400-odbc_c &lt;br /&gt;
 Row 0: Ernie                                     	Bert                                      	2019-10-05	23:24:00	2019-10-05 23:23:42.000000&lt;br /&gt;
 Row 1: Bob                                       	Heppo                                     	2019-11-06	05:05:05	2019-10-05 23:23:42.000000&lt;br /&gt;
 $ &lt;br /&gt;
&lt;br /&gt;
\o/&lt;br /&gt;
----&lt;br /&gt;
Footnotes and references:&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=Query_database_using_ODBC_from_a_linux_machine&amp;diff=668</id>
		<title>Query database using ODBC from a linux machine</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=Query_database_using_ODBC_from_a_linux_machine&amp;diff=668"/>
		<updated>2019-10-16T20:04:05Z</updated>

		<summary type="html">&lt;p&gt;Heiko: /* Output */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Accessing a AS/400 via ODBC is something that might come in handy some day, so I decided to explore how it can be done.&lt;br /&gt;
&lt;br /&gt;
Be warned: This is more like a log, showing (and hopefully solving) all issues I ran into doing this. I think this is more helpful than a ideal world example.&lt;br /&gt;
&lt;br /&gt;
== Create a database ==&lt;br /&gt;
I suggest you try [[Beginners Project: 99 Bottles Of Beer (using REXX)]] and [[Beginners Project: Hello World (using database, display file and RPG)]] before you try this!&amp;lt;ref&amp;gt;[[User:Heiko|Heiko]] made this pretty brief, f.e. not every &amp;lt;code&amp;gt;F3&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;&amp;amp;#x23CE;&amp;lt;/code&amp;gt; is noted.&amp;lt;/ref&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Create a database to play with ===&lt;br /&gt;
* This is the third project [[User:Heiko|Heiko]] did, so his personal Library was getting a bit cluttered. Therefore, let&#039;s create a library just for this niew project:&lt;br /&gt;
** &amp;lt;code&amp;gt;CRTLIB LIB(ODBC) TEXT(Library for ODBC project source)&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;CRTSRCPF FILE(ODBC/ODBCDB) RCDLEN(112) TEXT(&#039;Project ODBC and Database&#039;)&amp;lt;/code&amp;gt; to create new physical file to hold the DDS.&lt;br /&gt;
* &amp;lt;code&amp;gt;WRKMBRPDM FILE(ODBC/ODBCDB)&amp;lt;/code&amp;gt; Work with this file.&lt;br /&gt;
* &amp;lt;code&amp;gt;F6&amp;lt;/code&amp;gt; to create new member, insert member&#039;s name &amp;lt;code&amp;gt;ODBCDB&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;This wil change later. Read on...&amp;lt;/ref&amp;gt; and the type &amp;lt;code&amp;gt;PF&amp;lt;/code&amp;gt;:&amp;lt;br/&amp;gt;[[Image:ODBCDB01.png|666px]]&lt;br /&gt;
* Enter this DDS: ([https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/rzakc/rzakcdatel.htm Learn what the below means] [https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzasb/cpdtex.htm Especially time- and dateformats] [https://www.db2tutorial.com/db2-basics/db2-time/ Even more about wibbly-wobbly-timey-wimey-stuff] [https://www.ibm.com/support/knowledgecenter/en/SSEPEK_11.0.0/intro/src/tpc/db2z_datetimetimestamp.html and more])&lt;br /&gt;
         ***************** Datenanfang *******************************************************************************************&lt;br /&gt;
 0001.00      A          R CALLS                                                                                  191002          &lt;br /&gt;
 0002.00      A            CALLER        42A                                                                      191002          &lt;br /&gt;
 0003.00      A            CALLED        42A                                                                      191002          &lt;br /&gt;
 0004.00      A            DATE            L                TIMFMT(*ISO)                                          191002          &lt;br /&gt;
 0005.00      A            TIME            T                                                                      191002          &lt;br /&gt;
 0006.00      A            TIMESTAMP       Z                                                                      191002          &lt;br /&gt;
         ******************Datenende *********************************************************************************************&lt;br /&gt;
* &amp;lt;code&amp;gt;14&amp;lt;/code&amp;gt; to compile&amp;amp;#x2026;&amp;lt;br/&amp;gt;[[Image:ODBCDB02.png|666px]]&amp;lt;br/&amp;gt;&amp;amp;#x2026;I failed again. Stupid me. I can&#039;t create a new physical database file in the same place, where source physical file (with the same name!) exists.&lt;br /&gt;
** Just rename the DDS member from &amp;lt;code&amp;gt;ODBCDB&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;ODBCDBPF&amp;lt;/code&amp;gt;:&amp;lt;br/&amp;gt;[[Image:ODBCDB03.png|666px]]&amp;lt;br/&amp;gt;[[Image:ODBCDB04.png|666px]]&lt;br /&gt;
** And try again.&lt;br /&gt;
** Check with &amp;lt;code&amp;gt;DSPMSG&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;or use [[Compile Sources Without Queuing]]&amp;lt;/ref&amp;gt; whether the compile was successful or not. If it did, you find the new PF in the library:&amp;lt;br/&amp;gt;[[Image:ODBCDB10.png|666px]]&lt;br /&gt;
&lt;br /&gt;
=== Insert content into the database ===&lt;br /&gt;
* &amp;lt;code&amp;gt;STRSQL&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;F4&amp;lt;/code&amp;gt;&lt;br /&gt;
** Enter the library name, in this example &amp;lt;code&amp;gt;ODBC&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Shortcut: &amp;lt;code&amp;gt;STRSQL LIBOPT(ODBC)&amp;lt;/code&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
* In the interactive SQL session, enter:&amp;lt;br/&amp;gt;&amp;lt;code&amp;gt;INSERT INTO CALLS (CALLER, CALLED, DATE, TIME, TIMESTAMP) VALUES (&#039;Ernie&#039;, &#039;Bert&#039;, &#039;2019-10-05&#039;, &#039;23.23&#039;, &#039;2019-10-05 23:23:42&#039;)&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Timestamp format: https://www.ibm.com/support/knowledgecenter/SSFMBX/com.ibm.swg.im.dashdb.sql.ref.doc/doc/r0007107.html&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;You can use either &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;:&amp;lt;/code&amp;gt; as delimiter in time fields. The proper way, according to the documentation I found, is: &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
* There are many ways to display the result:&lt;br /&gt;
** If you&#039;re still in STRSQL, enter: &amp;lt;code&amp;gt;SELECT * FROM CALLS&amp;lt;/code&amp;gt;&lt;br /&gt;
** On command line, try this: &amp;lt;code&amp;gt;DSPF FILE(ODBC/ODBCDBPF)&amp;lt;/code&amp;gt;&lt;br /&gt;
** Or use &amp;lt;code&amp;gt;STRDFU&amp;lt;/code&amp;gt;, select option 5 and fill out the displayed form&lt;br /&gt;
[[Image:ODBC_DSPF01.png|666px|Displayed using &amp;lt;code&amp;gt;DSPF&amp;lt;/code&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
== ODBC Queries ==&lt;br /&gt;
Make sure you&#039;ve set up your ODBC connection (&amp;lt;tt&amp;gt;/etc/odbc.ini&amp;lt;/tt&amp;gt;) correctly.&lt;br /&gt;
&lt;br /&gt;
=== Perl ===&lt;br /&gt;
Here is a nice [https://www.ibm.com/developerworks/data/library/techarticle/dm-0512greenstein/index.html HowTo] from IBM. Worth reading.&lt;br /&gt;
==== Script Source Code ====&lt;br /&gt;
 #!/usr/bin/perl&lt;br /&gt;
 use strict;&lt;br /&gt;
 use DBI;&lt;br /&gt;
 &lt;br /&gt;
 my $db_cfg=&amp;quot;YOURCONFIG&amp;quot;; # See your /etc/odbc.ini&lt;br /&gt;
 my $db_pwd=&amp;quot;YOURUSER&amp;quot;;&lt;br /&gt;
 my $db_user=&amp;quot;YOURPASSWORD&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 printf(&amp;quot;Connecting to source database on $db_cfg...\n&amp;quot;);&lt;br /&gt;
 my $dbh = DBI-&amp;gt;connect(&#039;DBI:ODBC:&#039; . $db_cfg, $db_user, $db_pwd, {PrintError =&amp;gt; 1, AutoCommit =&amp;gt; 1}); # Connecting to Db2 database&lt;br /&gt;
 if ( $dbh )&lt;br /&gt;
 {&lt;br /&gt;
 	my $sth = $dbh-&amp;gt;prepare (&amp;quot;SELECT * FROM ODBC/ODBCDBPF&amp;quot;);&lt;br /&gt;
 	if (!$sth-&amp;gt;execute)&lt;br /&gt;
 	{&lt;br /&gt;
 		printf(&amp;quot;Error: Preparing select on source failed.\n&amp;quot;);&lt;br /&gt;
 		die;&lt;br /&gt;
 	}&lt;br /&gt;
 	&lt;br /&gt;
 	my $fCaller; &lt;br /&gt;
 	my $fCalled;&lt;br /&gt;
 	my $fDate;&lt;br /&gt;
 	my $fTime;&lt;br /&gt;
 	my $fTS;	&lt;br /&gt;
 	while ( ($fCaller, $fCalled, $fDate, $fTime, $fTS) = $sth-&amp;gt;fetchrow ) # Read one row from source table&lt;br /&gt;
 	{&lt;br /&gt;
 		printf(&amp;quot;%s, %s, %s, %s, %s\n&amp;quot;, $fCaller, $fCalled, $fDate, $fTime, $fTS);&lt;br /&gt;
 	} &lt;br /&gt;
 &lt;br /&gt;
 	# Clean up last statements&lt;br /&gt;
 	$sth-&amp;gt;finish;&lt;br /&gt;
 &lt;br /&gt;
 	# Disconnect from database&lt;br /&gt;
 	if ( $dbh )&lt;br /&gt;
 	{&lt;br /&gt;
 		print(&amp;quot;Disconnecting from $db_cfg...\n&amp;quot;);&lt;br /&gt;
 		$dbh-&amp;gt;disconnect;&lt;br /&gt;
 	}&lt;br /&gt;
 }&lt;br /&gt;
 else&lt;br /&gt;
 {&lt;br /&gt;
 	printf(&amp;quot;Error: Connection to database (%s) failed:\n%s\n%s\n%s\n&amp;quot;, $db_cfg,	$DBI::err, $DBI::errstr, $DBI::state);&lt;br /&gt;
 	die;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
 $ ./as400-odbc.pl &lt;br /&gt;
 Connecting to source database on YOURCONFIG...&lt;br /&gt;
 Ernie                                      Bert                                       2019-10-05 23:24:00 2019-10-05 23:23:42.000000&lt;br /&gt;
 Bob                                        Heppo                                      2019-11-06 05:05:05 2019-10-05 23:23:42.000000&lt;br /&gt;
 Disconnecting from YOURCONFIG...&lt;br /&gt;
&lt;br /&gt;
=== PHP ===&lt;br /&gt;
I found several possible approaches:&lt;br /&gt;
* Use &amp;lt;code&amp;gt;odbc_&amp;lt;/code&amp;gt; command set&lt;br /&gt;
** [https://www.ibm.com/developerworks/library/os-php-odbc/index.html HowTo use PHP and ODBC]&amp;lt;ref&amp;gt;Sadly this is for mySQL. Db2 would be much more appreciated.&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Use &amp;lt;tt&amp;gt;PDO&amp;lt;/tt&amp;gt;&lt;br /&gt;
** [https://www.php.net/manual/en/ref.pdo-ibm.php Short Overview] &#039;&#039;&#039;&#039;&#039;@PoC: Is this compatible???&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
* Use Db2 driver &#039;&#039;&#039;&#039;&#039;@PoC: Is this compatible???&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
** [https://www.ibm.com/support/knowledgecenter/en/SS6NHC/com.ibm.swg.im.dashdb.doc/connecting/connect_driver_package.html Db2 client] &amp;amp; [https://public.dhe.ibm.com/ibmdl/export/pub/software/data/db2/drivers/odbc_cli/ direct link]&lt;br /&gt;
** [https://github.com/php/pecl-database-ibm_db2 Installation instructions]&lt;br /&gt;
** [https://www.php.net/manual/en/function.db2-connect.php Usage] and after client installation: &amp;lt;code&amp;gt;TBD -h&amp;lt;/code&amp;gt; might help!&lt;br /&gt;
&lt;br /&gt;
==== PHP Code using ODBC ====&lt;br /&gt;
Let me say right away, that didn&#039;t work out as easy as I hoped.&lt;br /&gt;
 &amp;lt;?php&lt;br /&gt;
 &lt;br /&gt;
 /* Sample Code: How to query a Db2 database on a AS/400 (iSeries) &lt;br /&gt;
  * Note:        apt-get install php-odbc might be necessary&lt;br /&gt;
  * About:       https://try-as400.pocnet.net&lt;br /&gt;
  * */&lt;br /&gt;
 &lt;br /&gt;
 $db_cfg=&amp;quot;YOURCONFIG&amp;quot;; # See your /etc/odbc.ini&lt;br /&gt;
 $db_user=&amp;quot;YOURUSER&amp;quot;;&lt;br /&gt;
 $db_pwd=&amp;quot;YOURPASSWORD&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 $dbh=odbc_connect($db_cfg, $db_user, $db_pwd);&lt;br /&gt;
 if ($dbh)&lt;br /&gt;
 {&lt;br /&gt;
 	$sql=&amp;quot;SELECT * FROM ODBC/ODBCDBPF&amp;quot;;&lt;br /&gt;
 	printf(&amp;quot;Preparing \&amp;quot;$sql\&amp;quot;...\n&amp;quot;);&lt;br /&gt;
 	$sth=odbc_prepare($dbh, $sql);&lt;br /&gt;
&lt;br /&gt;
As you can see, the source isn&#039;t complete. That&#039;s because I wasn&#039;t able to execute it any further. Output so far:&lt;br /&gt;
 Preparing &amp;quot;SELECT * FROM ODBC/ODBCDBPF&amp;quot;...&lt;br /&gt;
 &lt;br /&gt;
 mmap() failed: [12] Cannot allocate memory&lt;br /&gt;
 &lt;br /&gt;
 PHP Fatal error:  Out of memory (allocated 2097152) (tried to allocate 206158430251 bytes)&lt;br /&gt;
The driver seems to need 206158430251 bytes, that&#039;s 192GB, a bit greedy for my taste.&lt;br /&gt;
&lt;br /&gt;
After some research&amp;lt;ref&amp;gt;php-mmap-issue: https://stackoverflow.com/questions/42132558/odbc-prepare-gives-fatal-error-allowed-memory-size-exhausted&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;php-mmap-issue: https://stackoverflow.com/questions/21286589/linux-odbc-fatal-error-allowed-memory-size/21412667#21412667&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;unixodbc-32/64bit drivers: http://www.unixodbc.org/doc/db2.html&amp;lt;/ref&amp;gt;I&#039;m pretty sure, its old 32bit ODBC-drivers conflicting with 64bit PHP&amp;lt;ref&amp;gt;Oddly, the same drivers work with perl&amp;lt;/ref&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
STAY TUNED WE ARE WORKING ON A SOLUTION.&lt;br /&gt;
&lt;br /&gt;
==== PHP Code using DB2 client ====&lt;br /&gt;
That wasn&#039;t very smooth, either.&lt;br /&gt;
&lt;br /&gt;
I first installed some software:&lt;br /&gt;
* Get IBM&#039;s CLI driver: https://public.dhe.ibm.com/ibmdl/export/pub/software/data/db2/drivers/odbc_cli/ and move it to /home/clidriver&lt;br /&gt;
* Insert this into .bashrc:&lt;br /&gt;
 # CLI Driver (PHP -&amp;gt; Db2 (AS/400),&lt;br /&gt;
 export IBM_DB_HOME=/home/clidriver&lt;br /&gt;
 export LD_LIBRARY_PATH=${IBM_DB_HOME}/lib&lt;br /&gt;
 export PATH=${IBM_DB_HOME}/bin:$PATH&lt;br /&gt;
* apt-get install php-dev&lt;br /&gt;
* pecl install ibm_db2&lt;br /&gt;
* add extension=ibm_db2.so to /etc/php/7.0/cli/php.ini&lt;br /&gt;
* If used with apache (untested):&lt;br /&gt;
** add LD_LIBRARY_PATH as shown above to httpd.conf&lt;br /&gt;
** add extension=ibm_db2.so to /etc/php/7.0/apache2/php.ini&lt;br /&gt;
** Beyond: https://www.php.net/manual/en/ibm-db2.installation.php || https://github.com/php/pecl-database-ibm_db2 || https://public.dhe.ibm.com/ibmdl/export/pub/software/data/db2/drivers/odbc_cli/&lt;br /&gt;
&lt;br /&gt;
 $db_user=&amp;quot;YOURUSER&amp;quot;;&lt;br /&gt;
 $db_pwd=&amp;quot;YOURPASSWORT&amp;quot;;&lt;br /&gt;
 $db_db = &#039;ODBC&#039;;&lt;br /&gt;
 $db_hostname = &#039;silverlake.intern.mathpeter.com&#039;;&lt;br /&gt;
 $db_port = 8471; //50000; /* https://www.ibm.com/support/pages/tcpip-ports-required-ibm-i-access-and-related-functions */&lt;br /&gt;
 $db_options = array(&#039;autocommit&#039; =&amp;gt; DB2_AUTOCOMMIT_ON);&lt;br /&gt;
 &lt;br /&gt;
 ini_set(&amp;quot;display_errors&amp;quot;, 1);&lt;br /&gt;
 &lt;br /&gt;
 //$connectionString = &amp;quot;DRIVER={IBM DB2 ODBC DRIVER};DATABASE=$db_db;HOSTNAME=$db_hostname;PORT=$db_port;PROTOCOL=TCPIP;UID=$db_user;PWD=$db_pwd;&amp;quot;; // takes for ever to connect&lt;br /&gt;
 $connectionString = &amp;quot;DATABASE=$db_db;HOSTNAME=$db_hostname;PORT=$db_port;PROTOCOL=TCPIP;UID=$db_user;PWD=$db_pwd;&amp;quot;; // takes for ever to connect&lt;br /&gt;
 printf(&amp;quot;connectionString: $connectionString\n&amp;quot;);&lt;br /&gt;
 $dbh=db2_connect($connectionString, NULL, NULL, $db_options); // https://www.php.net/manual/en/function.db2-connect.php &lt;br /&gt;
&lt;br /&gt;
This code stalls at &amp;lt;code&amp;gt;db2_connect()&amp;lt;/code&amp;gt;. &amp;lt;tt&amp;gt;netstat&amp;lt;/tt&amp;gt; shows that the TCP-connection is &amp;lt;tt&amp;gt;ESTABLISHED&amp;lt;/tt&amp;gt;. It doesn&#039;t create heavy load or traffic. It doesn&#039;t run into a timeout.&lt;br /&gt;
&lt;br /&gt;
STAY TUNED - MAYBE I CAN GET THIS WORKING.&lt;br /&gt;
&lt;br /&gt;
==== PHP Code using PDO ====&lt;br /&gt;
TBD&lt;br /&gt;
&lt;br /&gt;
=== C ===&lt;br /&gt;
Nice to know:&lt;br /&gt;
* http://www.unixodbc.org&lt;br /&gt;
* http://www.unixodbc.org/doc/db2.html&lt;br /&gt;
* https://www.easysoft.com/developer/interfaces/odbc/linux.html&lt;br /&gt;
* https://www.easysoft.com/developer/languages/c/odbc_tutorial.html&lt;br /&gt;
* https://stackoverflow.com/questions/33020646/gcc-odbc-on-linux-is-not-linking&lt;br /&gt;
* You might need to install &amp;lt;tt&amp;gt;unixodbc-dev&amp;lt;/tt&amp;gt;&lt;br /&gt;
==== C Source Code ====&lt;br /&gt;
 /* File: as400-odbc.c&lt;br /&gt;
 * About: Learn more here: https://try-as400.pocnet.net&lt;br /&gt;
 */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;sql.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;sqlext.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 #define RESULT_LEN  256&lt;br /&gt;
 &lt;br /&gt;
 char *odbcConnectionString = &amp;quot;DSN=YOURCONFIG;UID=YOURLOGIN;PWD=YOURPASSWORD;&amp;quot;; // See /etc/odbc.ini for DSN, use your AS/400 account as credentials.&lt;br /&gt;
 &lt;br /&gt;
 #define CHECK_ERROR(e, s, h, t)\&lt;br /&gt;
 	(\&lt;br /&gt;
 		{\&lt;br /&gt;
 			if (e!=SQL_SUCCESS &amp;amp;&amp;amp; e != SQL_SUCCESS_WITH_INFO)\&lt;br /&gt;
 			{ extract_error(s, h, t); goto exit;}\&lt;br /&gt;
 		}\&lt;br /&gt;
 	)&lt;br /&gt;
 &lt;br /&gt;
 void extract_error(char *fn, SQLHANDLE handle, SQLSMALLINT type)&lt;br /&gt;
 {&lt;br /&gt;
 	SQLINTEGER i = 0;&lt;br /&gt;
 	SQLINTEGER NativeError;&lt;br /&gt;
 	SQLCHAR SQLState[7];&lt;br /&gt;
 	SQLCHAR MessageText[256];&lt;br /&gt;
 	SQLSMALLINT TextLength;&lt;br /&gt;
 	SQLRETURN ret;&lt;br /&gt;
 &lt;br /&gt;
 	fprintf(stderr, &amp;quot;\nThe driver reported the following error %s\n&amp;quot;, fn);&lt;br /&gt;
 	do&lt;br /&gt;
  	{&lt;br /&gt;
 		ret = SQLGetDiagRec(type, handle, ++i, SQLState, &amp;amp;NativeError,&lt;br /&gt;
 			MessageText, sizeof(MessageText), &amp;amp;TextLength);&lt;br /&gt;
 		if (SQL_SUCCEEDED(ret)) {&lt;br /&gt;
 			printf(&amp;quot;%s:%ld:%ld:%s\n&amp;quot;,&lt;br /&gt;
 				SQLState, (long)i, (long)NativeError, MessageText);&lt;br /&gt;
 		}&lt;br /&gt;
 	} while (ret == SQL_SUCCESS); &lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 int main()&lt;br /&gt;
 {&lt;br /&gt;
 &lt;br /&gt;
 	SQLHENV   henv = SQL_NULL_HENV;    // Environment&lt;br /&gt;
 	SQLHDBC   hdbc = SQL_NULL_HDBC;    // Connection handle&lt;br /&gt;
 	SQLHSTMT  hstmt = SQL_NULL_HSTMT;  // Statement handle&lt;br /&gt;
 	SQLRETURN retcode;&lt;br /&gt;
 	SQLCHAR   fCaller[RESULT_LEN];&lt;br /&gt;
 	SQLCHAR   fCalled[RESULT_LEN];&lt;br /&gt;
 	SQLCHAR   fDate[RESULT_LEN];&lt;br /&gt;
 	SQLCHAR   fTime[RESULT_LEN];&lt;br /&gt;
 	SQLCHAR   fTS[RESULT_LEN];&lt;br /&gt;
 	SQLCHAR   outstr[1024];&lt;br /&gt;
 	SQLSMALLINT outstrlen;&lt;br /&gt;
 	int i = 0;&lt;br /&gt;
 &lt;br /&gt;
 	// Allocate environment handle&lt;br /&gt;
 	retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &amp;amp;henv);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLAllocHandle(SQL_HANDLE_ENV)&amp;quot;, henv, SQL_HANDLE_ENV);&lt;br /&gt;
 &lt;br /&gt;
 	// Set the ODBC version environment attribute&lt;br /&gt;
 	retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLSetEnvAttr(SQL_ATTR_ODBC_VERSION)&amp;quot;, henv, SQL_HANDLE_ENV);&lt;br /&gt;
 &lt;br /&gt;
 	retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLSetEnvAttr(SQL_ATTR_ODBC_VERSION)&amp;quot;, henv, SQL_HANDLE_ENV);&lt;br /&gt;
 &lt;br /&gt;
 	// Allocate connection handle&lt;br /&gt;
 	retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &amp;amp;hdbc);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLAllocHandle(SQL_HANDLE_DBC)&amp;quot;, hdbc, SQL_HANDLE_DBC);&lt;br /&gt;
 &lt;br /&gt;
 	// Set login timeout to 5 seconds&lt;br /&gt;
 	SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLSetConnectAttr(SQL_LOGIN_TIMEOUT)&amp;quot;, hdbc, SQL_HANDLE_DBC);&lt;br /&gt;
 &lt;br /&gt;
 	// Connect to data source, replace with your connection string&lt;br /&gt;
 	retcode = SQLDriverConnect(hdbc, NULL, odbcConnectionString, SQL_NTS, outstr, sizeof(outstr), &amp;amp;outstrlen, SQL_DRIVER_NOPROMPT);&lt;br /&gt;
 &lt;br /&gt;
 	// Allocate statement handle&lt;br /&gt;
 	retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &amp;amp;hstmt);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLAllocHandle(SQL_HANDLE_STMT)&amp;quot;,	hstmt, SQL_HANDLE_STMT);&lt;br /&gt;
 &lt;br /&gt;
 	// Execute SQL Query&lt;br /&gt;
 	retcode = SQLExecDirect(hstmt, (SQLCHAR*) &amp;quot;SELECT * FROM ODBC/ODBCDBPF&amp;quot;, SQL_NTS);&lt;br /&gt;
 	CHECK_ERROR(retcode, &amp;quot;SQLExecDirect()&amp;quot;, hstmt, SQL_HANDLE_STMT);&lt;br /&gt;
 &lt;br /&gt;
 	// Bind columns&lt;br /&gt;
 	retcode = SQLBindCol(hstmt, 1, SQL_C_CHAR, &amp;amp;fCaller, RESULT_LEN, 0);&lt;br /&gt;
 	retcode = SQLBindCol(hstmt, 2, SQL_C_CHAR, &amp;amp;fCalled, RESULT_LEN, 0);&lt;br /&gt;
 	retcode = SQLBindCol(hstmt, 3, SQL_C_CHAR, &amp;amp;fDate, RESULT_LEN, 0);&lt;br /&gt;
 	retcode = SQLBindCol(hstmt, 4, SQL_C_CHAR, &amp;amp;fTime, RESULT_LEN, 0);&lt;br /&gt;
 	retcode = SQLBindCol(hstmt, 5, SQL_C_CHAR, &amp;amp;fTS, RESULT_LEN, 0);&lt;br /&gt;
 &lt;br /&gt;
 	// Fetch and print each row of data until SQL_NO_DATA returned.&lt;br /&gt;
 	for (i = 0; ; i++)&lt;br /&gt;
 	{&lt;br /&gt;
 		retcode = SQLFetch(hstmt);&lt;br /&gt;
 		if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)&lt;br /&gt;
 		{&lt;br /&gt;
 			printf(&amp;quot;Row %d: %s\t%s\t%s\t%s\t%s\n&amp;quot;, i, fCaller, fCalled, fDate, fTime, fTS);&lt;br /&gt;
 		}&lt;br /&gt;
 		else&lt;br /&gt;
 		{&lt;br /&gt;
 			if (retcode != SQL_NO_DATA)&lt;br /&gt;
 			{&lt;br /&gt;
 				CHECK_ERROR(retcode, &amp;quot;SQLFetch()&amp;quot;, hstmt, SQL_HANDLE_STMT);&lt;br /&gt;
 			}&lt;br /&gt;
 			else&lt;br /&gt;
 			{&lt;br /&gt;
 				break;&lt;br /&gt;
 			}&lt;br /&gt;
 		}&lt;br /&gt;
 	}&lt;br /&gt;
 &lt;br /&gt;
 exit:&lt;br /&gt;
 &lt;br /&gt;
 	//&lt;br /&gt;
 	// Free handles&lt;br /&gt;
 	//&lt;br /&gt;
 	// Statement&lt;br /&gt;
 	if (hstmt != SQL_NULL_HSTMT)&lt;br /&gt;
 	{&lt;br /&gt;
 		SQLFreeHandle(SQL_HANDLE_STMT, hstmt);&lt;br /&gt;
 	}&lt;br /&gt;
 &lt;br /&gt;
 	// Connection&lt;br /&gt;
 	if (hdbc != SQL_NULL_HDBC)&lt;br /&gt;
 	{&lt;br /&gt;
 		SQLDisconnect(hdbc);&lt;br /&gt;
 		SQLFreeHandle(SQL_HANDLE_DBC, hdbc);&lt;br /&gt;
 	}&lt;br /&gt;
 &lt;br /&gt;
 	// Environment&lt;br /&gt;
 	if (henv != SQL_NULL_HENV)&lt;br /&gt;
 	{&lt;br /&gt;
 		SQLFreeHandle(SQL_HANDLE_ENV, henv);&lt;br /&gt;
 	}&lt;br /&gt;
 &lt;br /&gt;
 	return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
==== Compiling ====&lt;br /&gt;
 #!/bin/bash&lt;br /&gt;
 &lt;br /&gt;
 clear&lt;br /&gt;
 gcc as400-odbc.c -o as400-odbc_c -lodbc&lt;br /&gt;
Note the &amp;lt;code&amp;gt;-lodbc&amp;lt;/code&amp;gt; for linking against the ODBC-libraries.&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
 $./as400-odbc_c &lt;br /&gt;
 Row 0: Ernie                                     	Bert                                      	2019-10-05	23:24:00	2019-10-05 23:23:42.000000&lt;br /&gt;
 Row 1: Bob                                       	Heppo                                     	2019-11-06	05:05:05	2019-10-05 23:23:42.000000&lt;br /&gt;
 $ &lt;br /&gt;
&lt;br /&gt;
\o/&lt;br /&gt;
----&lt;br /&gt;
Footnotes and references:&lt;br /&gt;
&amp;lt;/references&amp;gt;&lt;/div&gt;</summary>
		<author><name>Heiko</name></author>
	</entry>
</feed>