LCOV - code coverage report
Current view: top level - src/ctlib/unittests - rpc_ct_param.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 195 234 83.3 %
Date: 2025-04-26 20:22:58 Functions: 3 3 100.0 %

          Line data    Source code
       1             : #include "common.h"
       2             : 
       3             : #include <freetds/macros.h>
       4             : 
       5             : static CS_INT ex_display_dlen(CS_DATAFMT * column);
       6             : static CS_RETCODE ex_display_header(CS_INT numcols, CS_DATAFMT columns[]);
       7             : 
       8             : typedef struct _ex_column_data
       9             : {
      10             :         CS_SMALLINT indicator;
      11             :         CS_CHAR *value;
      12             :         CS_INT valuelen;
      13             : }
      14             : EX_COLUMN_DATA;
      15             : 
      16             : /* Testing: array binding of result set */
      17          10 : TEST_MAIN()
      18             : {
      19             :         CS_CONTEXT *ctx;
      20             :         CS_CONNECTION *conn;
      21             :         CS_COMMAND *cmd;
      22          10 :         int verbose = 0;
      23             : 
      24             :         CS_RETCODE ret;
      25             :         CS_INT res_type;
      26             :         CS_INT num_cols;
      27             : 
      28             :         CS_CHAR cmdbuf[4096];
      29             : 
      30             :         CS_DATAFMT datafmt;
      31             :         CS_DATAFMT srcfmt;
      32             :         CS_DATAFMT destfmt;
      33             :         CS_INT intvar;
      34             :         CS_SMALLINT smallintvar;
      35             :         CS_FLOAT floatvar;
      36             :         CS_MONEY moneyvar;
      37             :         CS_BINARY binaryvar;
      38          10 :         CS_BIT bitvar = 1;
      39             :         char moneystring[10];
      40             :         char rpc_name[15];
      41             :         CS_INT destlen;
      42             :         CS_INT i;
      43             :         CS_INT j;
      44          10 :         CS_INT row_count = 0;
      45             :         CS_INT rows_read;
      46             :         CS_INT disp_len;
      47             :         EX_COLUMN_DATA *coldata;
      48             :         CS_DATAFMT *outdatafmt;
      49             :         CS_SMALLINT msg_id;
      50             : 
      51             : 
      52             : 
      53          10 :         printf("%s: submit a stored procedure using ct_param \n", __FILE__);
      54             :         if (verbose) {
      55             :                 printf("Trying login\n");
      56             :         }
      57          10 :         check_call(try_ctlogin, (&ctx, &conn, &cmd, verbose));
      58          10 :         error_to_stdout = true;
      59             : 
      60             :         /* do not test error */
      61          10 :         run_command(cmd, "IF OBJECT_ID('sample_rpc') IS NOT NULL DROP PROCEDURE sample_rpc");
      62             : 
      63          10 :         strcpy(cmdbuf, "create proc sample_rpc (@intparam int, \
      64             :         @sintparam smallint output, @floatparam float output, \
      65             :         @moneyparam money output,  \
      66             :         @dateparam datetime output, @charparam char(20) output, @empty varchar(20) output, \
      67             :         @binaryparam    binary(20) output, @bitparam bit) \
      68             :         as ");
      69             : 
      70          10 :         strcat(cmdbuf, "select @intparam, @sintparam, @floatparam, @moneyparam, \
      71             :         @dateparam, @charparam, @binaryparam \
      72             :         select @sintparam = @sintparam + @intparam \
      73             :         select @floatparam = @floatparam + @intparam \
      74             :         select @moneyparam = @moneyparam + convert(money, @intparam) \
      75             :         select @dateparam = getdate() \
      76             :         select @charparam = \'The char parameters\' \
      77             :         select @empty = \'\' \
      78             :         select @binaryparam = @binaryparam \
      79             :         print \'This is the message printed out by sample_rpc.\'");
      80             : 
      81          10 :         check_call(run_command, (cmd, cmdbuf));
      82             : 
      83             :         /*
      84             :          * Assign values to the variables used for parameter passing.
      85             :          */
      86             : 
      87          10 :         intvar = 2;
      88          10 :         smallintvar = 234;
      89          10 :         floatvar = 0.12;
      90          10 :         binaryvar = (CS_BINARY) 0xff;
      91          10 :         strcpy(rpc_name, "sample_rpc");
      92          10 :         strcpy(moneystring, "300.90");
      93             : 
      94             :         /*
      95             :          * Clear and setup the CS_DATAFMT structures used to convert datatypes.
      96             :          */
      97             : 
      98          10 :         memset(&srcfmt, 0, sizeof(CS_DATAFMT));
      99             :         srcfmt.datatype = CS_CHAR_TYPE;
     100          10 :         srcfmt.maxlength = (CS_INT) strlen(moneystring);
     101          10 :         srcfmt.precision = 5;
     102          10 :         srcfmt.scale = 2;
     103             :         srcfmt.locale = NULL;
     104             : 
     105          10 :         memset(&destfmt, 0, sizeof(CS_DATAFMT));
     106          10 :         destfmt.datatype = CS_MONEY_TYPE;
     107          10 :         destfmt.maxlength = sizeof(CS_MONEY);
     108          10 :         destfmt.precision = 5;
     109          10 :         destfmt.scale = 2;
     110             :         destfmt.locale = NULL;
     111             : 
     112             :         /*
     113             :          * Convert the string representing the money value
     114             :          * to a CS_MONEY variable. Since this routine does not have the
     115             :          * context handle, we use the property functions to get it.
     116             :          */
     117          10 :         check_call(ct_cmd_props, (cmd, CS_GET, CS_PARENT_HANDLE, &conn, CS_UNUSED, NULL));
     118          10 :         check_call(ct_con_props, (conn, CS_GET, CS_PARENT_HANDLE, &ctx, CS_UNUSED, NULL));
     119          10 :         check_call(cs_convert, (ctx, &srcfmt, (CS_VOID *) moneystring, &destfmt, &moneyvar, &destlen));
     120             : 
     121             :         /*
     122             :          * Send the RPC command for our stored procedure.
     123             :          */
     124          10 :         check_call(ct_command, (cmd, CS_RPC_CMD, rpc_name, CS_NULLTERM, CS_NO_RECOMPILE));
     125             : 
     126             :         /*
     127             :          * Clear and setup the CS_DATAFMT structure, then pass
     128             :          * each of the parameters for the RPC.
     129             :          */
     130          10 :         memset(&datafmt, 0, sizeof(datafmt));
     131          10 :         strcpy(datafmt.name, "@intparam");
     132          10 :         datafmt.namelen = CS_NULLTERM;
     133          10 :         datafmt.datatype = CS_INT_TYPE;
     134          10 :         datafmt.maxlength = CS_UNUSED;
     135          10 :         datafmt.status = CS_INPUTVALUE;
     136             :         datafmt.locale = NULL;
     137             : 
     138          10 :         check_call(ct_param, (cmd, &datafmt, (CS_VOID *) & intvar, CS_SIZEOF(CS_INT), 0));
     139             : 
     140          10 :         strcpy(datafmt.name, "@sintparam");
     141          10 :         datafmt.namelen = CS_NULLTERM;
     142          10 :         datafmt.datatype = CS_SMALLINT_TYPE;
     143          10 :         datafmt.maxlength = 255;
     144          10 :         datafmt.status = CS_RETURN;
     145          10 :         datafmt.locale = NULL;
     146             : 
     147          10 :         check_call(ct_param, (cmd, &datafmt, (CS_VOID *) & smallintvar, CS_SIZEOF(CS_SMALLINT), 0));
     148             : 
     149          10 :         strcpy(datafmt.name, "@floatparam");
     150          10 :         datafmt.namelen = CS_NULLTERM;
     151          10 :         datafmt.datatype = CS_FLOAT_TYPE;
     152          10 :         datafmt.maxlength = 255;
     153          10 :         datafmt.status = CS_RETURN;
     154          10 :         datafmt.locale = NULL;
     155             : 
     156          10 :         check_call(ct_param, (cmd, &datafmt, (CS_VOID *) & floatvar, CS_SIZEOF(CS_FLOAT), 0));
     157             : 
     158          10 :         strcpy(datafmt.name, "@moneyparam");
     159          10 :         datafmt.namelen = CS_NULLTERM;
     160          10 :         datafmt.datatype = CS_MONEY_TYPE;
     161          10 :         datafmt.maxlength = 255;
     162          10 :         datafmt.status = CS_RETURN;
     163          10 :         datafmt.locale = NULL;
     164             : 
     165          10 :         check_call(ct_param, (cmd, &datafmt, (CS_VOID *) & moneyvar, CS_SIZEOF(CS_MONEY), 0));
     166             : 
     167          10 :         strcpy(datafmt.name, "@dateparam");
     168          10 :         datafmt.namelen = CS_NULLTERM;
     169          10 :         datafmt.datatype = CS_DATETIME4_TYPE;
     170          10 :         datafmt.maxlength = 255;
     171          10 :         datafmt.status = CS_RETURN;
     172          10 :         datafmt.locale = NULL;
     173             : 
     174             :         /*
     175             :          * The datetime variable is filled in by the RPC so pass NULL for
     176             :          * the data, 0 for data length, and -1 for the indicator arguments.
     177             :          */
     178          10 :         check_call(ct_param, (cmd, &datafmt, NULL, 0, -1));
     179          10 :         strcpy(datafmt.name, "@charparam");
     180          10 :         datafmt.namelen = CS_NULLTERM;
     181          10 :         datafmt.datatype = CS_CHAR_TYPE;
     182          10 :         datafmt.maxlength = 60;
     183          10 :         datafmt.status = CS_RETURN;
     184          10 :         datafmt.locale = NULL;
     185             : 
     186             :         /*
     187             :          * The character string variable is filled in by the RPC so pass NULL
     188             :          * for the data 0 for data length, and -1 for the indicator arguments.
     189             :          */
     190          10 :         check_call(ct_param, (cmd, &datafmt, NULL, 0, -1));
     191             : 
     192          10 :         strcpy(datafmt.name, "@empty");
     193          10 :         datafmt.namelen = CS_NULLTERM;
     194          10 :         datafmt.datatype = CS_VARCHAR_TYPE;
     195          10 :         datafmt.maxlength = 60;
     196          10 :         datafmt.status = CS_RETURN;
     197          10 :         datafmt.locale = NULL;
     198             : 
     199             :         /*
     200             :          * The character string variable is filled in by the RPC so pass NULL
     201             :          * for the data 0 for data length, and -1 for the indicator arguments.
     202             :          */
     203          10 :         check_call(ct_param, (cmd, &datafmt, NULL, 0, -1));
     204             : 
     205          10 :         strcpy(datafmt.name, "@binaryparam");
     206          10 :         datafmt.namelen = CS_NULLTERM;
     207          10 :         datafmt.datatype = CS_BINARY_TYPE;
     208          10 :         datafmt.maxlength = 255;
     209          10 :         datafmt.status = CS_RETURN;
     210          10 :         datafmt.locale = NULL;
     211             : 
     212          10 :         check_call(ct_param, (cmd, &datafmt, (CS_VOID *) & binaryvar, CS_SIZEOF(CS_BINARY), 0));
     213             : 
     214          10 :         strcpy(datafmt.name, "@bitparam");
     215          10 :         datafmt.namelen = CS_NULLTERM;
     216          10 :         datafmt.datatype = CS_BIT_TYPE;
     217          10 :         datafmt.maxlength = 1;
     218          10 :         datafmt.status = 0;
     219          10 :         datafmt.locale = NULL;
     220             : 
     221          10 :         check_call(ct_param, (cmd, &datafmt, (CS_VOID *) & bitvar, CS_SIZEOF(CS_BIT), 0));
     222             : 
     223             :         /*
     224             :          * Send the command to the server
     225             :          */
     226          10 :         check_call(ct_send, (cmd));
     227             : 
     228             :         /*
     229             :          * Process the results of the RPC.
     230             :          */
     231          80 :         while ((ret = ct_results(cmd, &res_type)) == CS_SUCCEED) {
     232          60 :                 switch ((int) res_type) {
     233          30 :                 case CS_ROW_RESULT:
     234             :                 case CS_PARAM_RESULT:
     235             :                 case CS_STATUS_RESULT:
     236             :                         /*
     237             :                          * Print the result header based on the result type.
     238             :                          */
     239          30 :                         switch ((int) res_type) {
     240          10 :                         case CS_ROW_RESULT:
     241          10 :                                 printf("\nROW RESULTS\n");
     242          10 :                                 break;
     243             : 
     244          10 :                         case CS_PARAM_RESULT:
     245          10 :                                 printf("\nPARAMETER RESULTS\n");
     246          10 :                                 break;
     247             : 
     248          10 :                         case CS_STATUS_RESULT:
     249          10 :                                 printf("\nSTATUS RESULTS\n");
     250          10 :                                 break;
     251             :                         }
     252          30 :                         fflush(stdout);
     253             : 
     254             :                         /*
     255             :                          * All three of these result types are fetchable.
     256             :                          * Since the result model for rpcs and rows have
     257             :                          * been unified in the New Client-Library, we
     258             :                          * will use the same routine to display them
     259             :                          */
     260             : 
     261             :                         /*
     262             :                          * Find out how many columns there are in this result set.
     263             :                          */
     264          30 :                         check_call(ct_res_info, (cmd, CS_NUMDATA, &num_cols, CS_UNUSED, NULL));
     265             : 
     266             :                         /*
     267             :                          * Make sure we have at least one column
     268             :                          */
     269          30 :                         if (num_cols <= 0) {
     270           0 :                                 fprintf(stderr, "ct_res_info(CS_NUMDATA) returned zero columns");
     271           0 :                                 return 1;
     272             :                         }
     273             : 
     274             :                         /*
     275             :                          * Our program variable, called 'coldata', is an array of
     276             :                          * EX_COLUMN_DATA structures. Each array element represents
     277             :                          * one column.  Each array element will re-used for each row.
     278             :                          * 
     279             :                          * First, allocate memory for the data element to process.
     280             :                          */
     281          30 :                         coldata = (EX_COLUMN_DATA *) malloc(num_cols * sizeof(EX_COLUMN_DATA));
     282          30 :                         if (coldata == NULL) {
     283           0 :                                 fprintf(stderr, "malloc coldata failed \n");
     284           0 :                                 return 1;
     285             :                         }
     286             : 
     287          30 :                         outdatafmt = (CS_DATAFMT *) malloc(num_cols * sizeof(CS_DATAFMT));
     288          30 :                         if (outdatafmt == NULL) {
     289           0 :                                 fprintf(stderr, "malloc outdatafmt failed \n");
     290           0 :                                 return 1;
     291             :                         }
     292             : 
     293         150 :                         for (i = 0; i < num_cols; i++) {
     294         150 :                                 check_call(ct_describe, (cmd, (i + 1), &outdatafmt[i]));
     295             : 
     296         150 :                                 outdatafmt[i].maxlength = ex_display_dlen(&outdatafmt[i]) + 1;
     297         150 :                                 outdatafmt[i].datatype = CS_CHAR_TYPE;
     298         150 :                                 outdatafmt[i].format = CS_FMT_NULLTERM;
     299             : 
     300         150 :                                 coldata[i].value = (CS_CHAR *) malloc(outdatafmt[i].maxlength);
     301         150 :                                 if (coldata[i].value == NULL) {
     302           0 :                                         fprintf(stderr, "malloc coldata.value failed \n");
     303           0 :                                         return 1;
     304             :                                 }
     305         150 :                                 coldata[i].value[0] = 0;
     306             : 
     307         150 :                                 check_call(ct_bind, (cmd, (i + 1), &outdatafmt[i], coldata[i].value, &coldata[i].valuelen,
     308             :                                               & coldata[i].indicator));
     309             :                         }
     310             : 
     311          30 :                         ex_display_header(num_cols, outdatafmt);
     312             : 
     313          90 :                         while (((ret = ct_fetch(cmd, CS_UNUSED, CS_UNUSED, CS_UNUSED,
     314          30 :                                                 &rows_read)) == CS_SUCCEED) || (ret == CS_ROW_FAIL)) {
     315             :                                 /*
     316             :                                  * Increment our row count by the number of rows just fetched.
     317             :                                  */
     318          30 :                                 row_count = row_count + rows_read;
     319             : 
     320             :                                 /*
     321             :                                  * Check if we hit a recoverable error.
     322             :                                  */
     323          30 :                                 if (ret == CS_ROW_FAIL) {
     324           0 :                                         printf("Error on row %d.\n", row_count);
     325           0 :                                         fflush(stdout);
     326             :                                 }
     327             : 
     328             :                                 /*
     329             :                                  * We have a row.  Loop through the columns displaying the
     330             :                                  * column values.
     331             :                                  */
     332         150 :                                 for (i = 0; i < num_cols; i++) {
     333             :                                         /*
     334             :                                          * Display the column value
     335             :                                          */
     336         150 :                                         printf("%s", coldata[i].value);
     337         150 :                                         fflush(stdout);
     338             : 
     339             :                                         /*
     340             :                                          * If not last column, Print out spaces between this
     341             :                                          * column and next one.
     342             :                                          */
     343         150 :                                         if (i != num_cols - 1) {
     344         120 :                                                 disp_len = ex_display_dlen(&outdatafmt[i]);
     345         120 :                                                 disp_len -= coldata[i].valuelen - 1;
     346        2258 :                                                 for (j = 0; j < disp_len; j++) {
     347        2138 :                                                         fputc(' ', stdout);
     348             :                                                 }
     349             :                                         }
     350             :                                 }
     351          30 :                                 printf("\n");
     352          30 :                                 fflush(stdout);
     353             :                         }
     354             : 
     355             :                         /*
     356             :                          * Free allocated space.
     357             :                          */
     358         150 :                         for (i = 0; i < num_cols; i++) {
     359         150 :                                 free(coldata[i].value);
     360             :                         }
     361          30 :                         free(coldata);
     362          30 :                         free(outdatafmt);
     363             : 
     364             :                         /*
     365             :                          * We're done processing rows.  Let's check the final return
     366             :                          * value of ct_fetch().
     367             :                          */
     368          30 :                         switch ((int) ret) {
     369          30 :                         case CS_END_DATA:
     370             :                                 /*
     371             :                                  * Everything went fine.
     372             :                                  */
     373          30 :                                 printf("All done processing rows.\n");
     374          30 :                                 fflush(stdout);
     375             :                                 break;
     376             : 
     377           0 :                         case CS_FAIL:
     378             :                                 /*
     379             :                                  * Something terrible happened.
     380             :                                  */
     381           0 :                                 fprintf(stderr, "ct_fetch returned CS_FAIL\n");
     382           0 :                                 return 1;
     383             :                                 break;
     384             : 
     385           0 :                         default:
     386             :                                 /*
     387             :                                  * We got an unexpected return value.
     388             :                                  */
     389           0 :                                 fprintf(stderr, "ct_fetch returned %d\n", ret);
     390           0 :                                 return 1;
     391             :                                 break;
     392             : 
     393             :                         }
     394          30 :                         break;
     395             : 
     396           0 :                 case CS_MSG_RESULT:
     397           0 :                         check_call(ct_res_info, (cmd, CS_MSGTYPE, (CS_VOID *) & msg_id, CS_UNUSED, NULL));
     398           0 :                         printf("ct_result returned CS_MSG_RESULT where msg id = %d.\n", msg_id);
     399           0 :                         fflush(stdout);
     400           0 :                         break;
     401             : 
     402             :                 case CS_CMD_SUCCEED:
     403             :                         /*
     404             :                          * This means no rows were returned.
     405             :                          */
     406             :                         break;
     407             : 
     408             :                 case CS_CMD_DONE:
     409             :                         /*
     410             :                          * Done with result set.
     411             :                          */
     412             :                         break;
     413             : 
     414           0 :                 case CS_CMD_FAIL:
     415             :                         /*
     416             :                          * The server encountered an error while
     417             :                          * processing our command.
     418             :                          */
     419           0 :                         fprintf(stderr, "ct_results returned CS_CMD_FAIL.");
     420           0 :                         break;
     421             : 
     422           0 :                 default:
     423             :                         /*
     424             :                          * We got something unexpected.
     425             :                          */
     426           0 :                         fprintf(stderr, "ct_results returned unexpected result type.");
     427           0 :                         return CS_FAIL;
     428             :                 }
     429             :         }
     430             : 
     431             :         /*
     432             :          * We're done processing results. Let's check the
     433             :          * return value of ct_results() to see if everything
     434             :          * went ok.
     435             :          */
     436          10 :         switch ((int) ret) {
     437             :         case CS_END_RESULTS:
     438             :                 /*
     439             :                  * Everything went fine.
     440             :                  */
     441             :                 break;
     442             : 
     443           0 :         case CS_FAIL:
     444             :                 /*
     445             :                  * Something failed happened.
     446             :                  */
     447           0 :                 fprintf(stderr, "ct_results failed.");
     448           0 :                 break;
     449             : 
     450           0 :         default:
     451             :                 /*
     452             :                  * We got an unexpected return value.
     453             :                  */
     454           0 :                 fprintf(stderr, "ct_results returned unexpected result type.");
     455           0 :                 break;
     456             :         }
     457             : 
     458          10 :         run_command(cmd, "DROP PROCEDURE sample_rpc");
     459             : 
     460             :         if (verbose) {
     461             :                 printf("Trying logout\n");
     462             :         }
     463          10 :         check_call(try_ctlogout, (ctx, conn, cmd, verbose));
     464             : 
     465          10 :         return 0;
     466             : }
     467             : 
     468             : static CS_INT
     469         570 : ex_display_dlen(CS_DATAFMT * column)
     470             : {
     471             : CS_INT len;
     472             : 
     473         570 :         switch ((int) column->datatype) {
     474         450 :         case CS_CHAR_TYPE:
     475             :         case CS_VARCHAR_TYPE:
     476             :         case CS_TEXT_TYPE:
     477             :         case CS_IMAGE_TYPE:
     478         450 :                 len = TDS_MIN(column->maxlength, 1024);
     479         450 :                 break;
     480             : 
     481          20 :         case CS_BINARY_TYPE:
     482             :         case CS_VARBINARY_TYPE:
     483          20 :                 len = TDS_MIN((2 * column->maxlength) + 2, 1024);
     484          20 :                 break;
     485             : 
     486             :         case CS_BIT_TYPE:
     487             :         case CS_TINYINT_TYPE:
     488             :                 len = 3;
     489             :                 break;
     490             : 
     491          20 :         case CS_SMALLINT_TYPE:
     492          20 :                 len = 6;
     493          20 :                 break;
     494             : 
     495          20 :         case CS_INT_TYPE:
     496          20 :                 len = 11;
     497          20 :                 break;
     498             : 
     499          20 :         case CS_REAL_TYPE:
     500             :         case CS_FLOAT_TYPE:
     501          20 :                 len = 20;
     502          20 :                 break;
     503             : 
     504          20 :         case CS_MONEY_TYPE:
     505             :         case CS_MONEY4_TYPE:
     506          20 :                 len = 24;
     507          20 :                 break;
     508             : 
     509          20 :         case CS_DATETIME_TYPE:
     510             :         case CS_DATETIME4_TYPE:
     511          20 :                 len = 30;
     512          20 :                 break;
     513             : 
     514           0 :         case CS_NUMERIC_TYPE:
     515             :         case CS_DECIMAL_TYPE:
     516           0 :                 len = (CS_MAX_PREC + 2);
     517           0 :                 break;
     518             : 
     519           0 :         default:
     520           0 :                 len = 12;
     521           0 :                 break;
     522             :         }
     523             : 
     524         570 :         return TDS_MAX((CS_INT) (strlen(column->name) + 1), len);
     525             : }
     526             : 
     527             : static CS_RETCODE
     528          30 : ex_display_header(CS_INT numcols, CS_DATAFMT columns[])
     529             : {
     530             : CS_INT i;
     531             : CS_INT l;
     532             : CS_INT j;
     533             : CS_INT disp_len;
     534             : 
     535          30 :         fputc('\n', stdout);
     536         180 :         for (i = 0; i < numcols; i++) {
     537         150 :                 disp_len = ex_display_dlen(&columns[i]);
     538         150 :                 printf("%s", columns[i].name);
     539         150 :                 fflush(stdout);
     540         150 :                 l = disp_len - (CS_INT) strlen(columns[i].name);
     541        8410 :                 for (j = 0; j < l; j++) {
     542        8260 :                         fputc(' ', stdout);
     543        8260 :                         fflush(stdout);
     544             :                 }
     545             :         }
     546          30 :         fputc('\n', stdout);
     547          30 :         fflush(stdout);
     548         180 :         for (i = 0; i < numcols; i++) {
     549         150 :                 disp_len = ex_display_dlen(&columns[i]);
     550         150 :                 l = disp_len - 1;
     551        8960 :                 for (j = 0; j < l; j++) {
     552        8810 :                         fputc('-', stdout);
     553             :                 }
     554         150 :                 fputc(' ', stdout);
     555             :         }
     556          30 :         fputc('\n', stdout);
     557             : 
     558          30 :         return CS_SUCCEED;
     559             : }

Generated by: LCOV version 1.13