/*   SHOWTABL.C version 2.5 derived from the original version by */
/*   Antti Karttunen for Neil Sloane's Online Encyclopedia of    */
/*   Integer Sequences, illustrating keywords "tabl" and "cons". */

/*   Compile with    gcc -o showtabl.cgi showtabl.c              */

/* Version 2.5 (June 27 2003) NJAS changed line 481 slightly     */
/* * replaced iSC by Plouffe's Inverter "PI" in show_isc()       */

/* Version 2.4 (June 2003) introducing digit tables (format=5):  */
/* * Added format=5 for a simple table for constants, where a(n) */
/*   is the "decimal" digit corresponding to 10^n, e.g. a(0)=3   */
/*   in the case of pi (3*10^0), starting at offset 1 minus 1.   */
/*   It works for constants in any base, a(1) = a(0) = 1 for 2+1 */
/*   with %O A004601 2,0 in the binary expansion of pi is fine.  */
/* * Minor cleanup of the comments at the begin of showtabl.c :  */
/* <URL:http://www.research.att.com/~njas/sequences/showtabl.c>, */
/* <URL:http://purl.net/xyzzy/eis/showtabl.c>                    */

/* Version 2.3 (June 2003)                                       */
/* * Removed W3C validator link, Neil prefers manual validation. */
/* * Added "readonly" to format=0 form for constants.            */
/* * Added "disabled" to format=4 form for the terms.            */
/* * Added TEXTAREA_COLUMNS 55 to limit the length of lines for  */
/*   format=4.  DO NOT MODIFY without testing several different  */
/*   browsers, the effects can be VERY ugly.  55 is okay for...  */
/*   - IBM WebExplorer (obsolete pre-HTML 3.0 browser)           */
/*   - OS/2 Netscape 2.02 (= 3.x, 55 results in very long lines) */
/*   - OS/2 Netscape 4.61 (= 4.x).                               */
/*   - Lynx 2.8.5 (anything below 79 would work, 55 is okay)     */
/*   <small> and <font size="-1"> have no or unwanted effects on */
/*   the displayed textarea.  I have not tested new CSS tricks.  */

/* Version 2.2 (May 2003) introducing simple tables (format=4):  */
/* * Neil prefers width="318" and height="58" for a smaller map. */
/* * Add code for leading zeros (negative offset) as in A081818. */
/*   Do not try %0*d resp. %.*d or similar with gcc 2.6.3, width */
/*   or precision * does not work with this compiler (BUG).      */
/* * Use default format=312 (triangle + 2 arrays) if none given. */
/* * Added a "show internal format? [Yes]" form above EIS links. */
/* * Added format=4 and show_seq() for a simple table plus line. */

/* Version 2.1 (May 2003) introducing a format=0 constant form:  */
/* * removed unused showdiff() for a difference table.           */
/* * added format=0 for a decimal constant by a new show_isc(),  */
/*   use gl_isc_url       = ... to define a CGI for constants,   */
/*   use gl_isc_parameter = ... to define the parameter name,    */
/*   use gl_isc_hidden    = ... to define a hidden parameter,    */
/*   use gl_isc_submit    = ... to define a submit button text,  */
/* * major cleanup for valid XHTML 1.0 transitional output.      */
/* * replace CopyrightNotice by CopyrightNotice2 in footer map.  */
/* * add FAQ to EIS links, keep Webcam instead of old Browse.    */

/* Version 2.0 (May 2001) by Frank.Ellermann@t-online.de         */
/* * removed options tb=/te=, rb=/re=, cb=/ce= because Neil uses */
/*   the default (hardwired) tags <table>,</table>, <tr>,</tr>,  */
/*   <td align=right><tt>,</tt></td>.  To modify these tags edit */
/*   gl_... variables below in the C source and compile again.   */
/* * removed option seqb= (there was no code for evaluating any  */
/*   gl_seqb in SHOWTABL.C, so this probably never worked), and  */
/*   removed undocumented options cnt=, end=, and O= (no effect) */
/* * removed option width=, because Neil uses the default table  */
/*   size determined either by the number of terms or a height=  */
/*   argument.                                                   */
/* * removed "magic formula" to determine a table size based on  */
/*   the number of terms, the known formula ( n*n+n ) / 2 allows */
/*   to get rid of libm.a, <math.h>, and compiler option -lm.    */
/* * reduced MAXTERMS from 10000 to 136, because there are less  */
/*   than 136 = (16*16+16)/2 terms in a sequence (3 * 34 = 112). */
/* * for normal (1),(2,3),(4,5,6),(7,8,9,0) triangles avoid the  */
/*   cell padding - cells are already separated by blank cells - */
/*   and use align=center - right adjusted triangles were ugly.  */
/* * integrated showrow() into showtabl(), added shownrows() to  */
/*   remove trailing terms, i.e. only filled table rows shown.   */
/* * replaced cut_to_terms() by <string.h> strtok( x, gl_tok ).  */
/* * added format=0 for a difference table by a new showdiff().  */

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>

#ifdef     __WATCOMC__
#define   strcasecmp( x, y )  stricmp( x, y )
#endif
#ifdef    __EMX__
#define   strcasecmp( x, y )  _stricmp( x, y )
#endif
#define   MAXTERMS            ((16*16+16)/2)
#define   TITLE_TERMS_SIZE    60
#define   TEXTAREA_COLUMNS    55

int   gl_height               = 0;
int   gl_count                = 0;
char *gl_bell                 = "http://www.research.att.com";
char *gl_format               = "312";
char *gl_tok                  = " \t,;.+";
char *gl_table_begin_array    = "\n<table>";
char *gl_table_begin_triangle = "\n<table cellpadding=\"0\">";
char *gl_table_end            = "\n</table>\n";
char *gl_row_begin            = "\n<tr>";
char *gl_row_end              = "\n</tr>";
char *gl_cell                 = "<td></td>";
char *gl_cell_begin_array     = "<td align=\"right\"><tt>";
char *gl_cell_begin_triangle  = "<td align=\"center\"><tt>";
char *gl_cell_end             = "</tt></td>";
char *gl_A_seqid              = "";
char *gl_seq                  = NULL;
char *gl_terms[ MAXTERMS +1 ];

/* ------------------------------------------------------------------ */

char *gl_isc_url         = "http://pi.lacim.uqam.ca/cgi-bin/lookup.pl";
char *gl_isc_parameter   = "number";
char *gl_isc_hidden      = "name=\"lookup_type\" value=\"simple\"";
char *gl_isc_submit      = "&#160;PI&#160;";

void show_isc( void )
{
     int k;

     printf(   "<form method=\"get\" action=\"%s\"><input type=\"text\""
               " name=\"%s\" size=\"60\" maxlength=\"255\" readonly=\"r"
               "eadonly\" value=\"", gl_isc_url, gl_isc_parameter );

     if (      gl_height <  0 )    /* bypass a serious gcc 2.6.3 bug, */
     {    printf( "0." );          /* the star in "%.*d" doesn't work */
          for ( k = gl_height; k++; ) printf( "0" );
     }
     else if ( gl_height == 0 )    printf( "0" ); /* no height: 0.123 */

     for ( k = 0; gl_terms[ k ]; k++ )
     {
          if ( gl_height == k )    printf( "." ); /* decimal point    */
          printf( gl_terms[ k ] );
     }
     if (      gl_height == k )    printf( "." ); /* compare A003678  */

     printf(   "\" />&#160;<input type=\"hidden\" %s /><input type=\""
               "submit\" value=\"%s\" /></form>",
               gl_isc_hidden, gl_isc_submit );
}
/* ------------------------------------------------------------------ */

int  shownrows( void )
{
     int i, j;

     for ( i = 0, j = 1; ( j*j +j ) / 2 <= gl_count; i = j++ )
          if ( gl_height && gl_height < j ) break;

     return i;
}
/* ------------------------------------------------------------------ */

void showtable( int format )
{
     int nth_row, i, j;
     int height = shownrows();

     printf( gl_table_begin_array );

     for ( nth_row=0; nth_row < height; nth_row++ )
     {
          printf( gl_row_begin );

          j = ( format ? nth_row : 0 );

          for ( i = 0; i < j;   i++ ) printf( gl_cell );
          for ( i = 0; i < height - nth_row; i++ )
          {
               j = nth_row + i;
               j = nth_row + ( j*j+j )/2;
               if ( ! gl_terms[ j ] ) break;
               printf( gl_cell_begin_array );
               printf( gl_terms[j] );
               printf( gl_cell_end );
          }

          printf( gl_row_end );
     }

     printf( gl_table_end );
}
/* ------------------------------------------------------------------ */

void showtriangle( void )
{
     int skip, nth_row, i, j, k;
     int height = shownrows();

     printf( gl_table_begin_triangle ); k = 0;

     for  (    nth_row = 0, skip = height -1;
               nth_row < height && 0 <= skip;
               nth_row++, skip--
          )
     {
          printf( gl_row_begin );
          for ( i=0; i < skip; i++ ) printf( gl_cell );
          for ( j = 0; j < 2 * height -skip; j++ )
          {
               if ( ! gl_terms[ k ] ) break;
               printf( gl_cell_begin_triangle );
               if ( !( j & 1 ) && ( j / 2 <= nth_row ))
                    printf( gl_terms[ k++ ] );
               printf( gl_cell_end );
          }

          printf( gl_row_end );
     }

     printf( gl_table_end );
}
/* ------------------------------------------------------------------ */

void show_seq( int format )
{
     int k, j, len, row;

     printf( gl_table_begin_array );
     printf( gl_row_begin );  printf( gl_cell_begin_array );
     printf( "<strong>n</strong>" );
     printf( gl_cell_end );   printf( gl_cell_begin_array );
     printf( "<strong>a(n)</strong>" );
     printf( gl_cell_end );   printf( gl_row_end );

     for ( k = 0; gl_terms[ k ]; k++ )
     {
          printf( gl_row_begin );  printf( gl_cell_begin_array );
          printf( "%d", ( format ? -k -1 : k ) + gl_height );
          printf( gl_cell_end );   printf( gl_cell_begin_array );
          printf( "%s", gl_terms[ k ] );
          printf( gl_cell_end );   printf( gl_row_end );
     }
     printf( gl_table_end );

     for ( k = len = row = 0; gl_terms[ k ]; k++ )
     {
          j = 1 + strlen( gl_terms[ k ] );   len += j;
          if ( len > TEXTAREA_COLUMNS ) (    len  = j, row++ );
     }

     printf(   "\n<div align=\"center\"><form method=\"get\" action=\""
               "%s/cgi-bin/access.cgi/as/njas/sequences/eisA.cgi\"><in"
               "put type=\"hidden\" name=\"Anum\" value=\"%s\" />"
               "       <textarea name=\"dummy\" disabled=\"disabled\" "
               "rows=\"%d\" cols=\"%d\">",
               gl_bell, gl_A_seqid, ++row, 1 + TEXTAREA_COLUMNS );

     for ( k = len = 0; gl_terms[ k ]; k++ )
     {
          j = 1 + strlen( gl_terms[ k ] );   len += j;

          if ( len > TEXTAREA_COLUMNS )
          {    printf( "\n" );               len = j;
          }

          printf( "%s%s", (char *)( k ? "," : "[" ), gl_terms[ k ] );
     }
     printf(   "]</textarea>        </form></div>" );
}
/* ------------------------------------------------------------------ */

char *parse_url_value( char *url_piece )
{
     char *s,*t;

     s = t = url_piece;

     while ( *s )
     {
          if ( *s == '+' )         /* Plus signs to spaces */
          {         *t++ = ' ';    s++;      continue;
          }
          if ( *s == '%' )
          {
               if (*(s+1) == '%')  /* Double %% used for escaping % */
               {    *t++ = '%';    s += 2;   continue;
               }
               if ( isalnum( *(s+1) ) && ( 3 <= strlen( s )))
               {    /* Convert two hex digits to int */
                    unsigned tmp;
                    char save_char = *(s+3);

                    *(s+3) = '\0';      sscanf( s+1, "%x", &tmp );
                    *(s+3) = save_char; *t++ = ((char) tmp);
                                   s += 3;   continue;
          }    }

          *t++ = *s++;
     }

     *t = '\0';
     return url_piece;
}
/* ------------------------------------------------------------------ */

int  parse_url_query_string( char *query_string )
{
     char *ptr1, *ptr2, *ptr3;
     int count=0;

     ptr1 = query_string;

     while ( ptr1 )
     {
          if ( ! ( ptr2 = strchr( ptr1, '=' ))) break;

          if (( ptr3 = strchr( ptr2, '&' ))) *ptr3++ = '\0';

          *ptr2++ = '\0';

          /* ptr1 points to the beginning of the variable name.         */
          /* ptr2 points two characters past the end of the             */
          /*      variable name, i.e. one past the equal sign (=)       */
          /*      which has been overwritten by zero '\0', that         */
          /*      is to the beginning of the variable value,            */
          /*      corresponding to variable name where ptr1 points to.  */
          /* ptr3 points two characters past the end of variable value, */
          /*      i.e. one past the ampersand (&) which has been        */
          /*      overwritten by zero, that is to the beginning of      */
          /*      the next variable name. Or if we have found the       */
          /*      last name=value pair, then it contains the NULL.      */

          if (*ptr2)
          {
               if      ( ! strcasecmp( ptr1, "A"       ))
                    gl_A_seqid     = parse_url_value( ptr2 );
               else if ( ! strcasecmp( ptr1, "format"  ))
                    gl_format      = parse_url_value( ptr2 );
               else if ( ! strcasecmp( ptr1, "seq"     ))
                    gl_seq         = parse_url_value( ptr2 );
               else if ( ! strcasecmp( ptr1, "height"  ))
                    gl_height      = atoi( parse_url_value( ptr2 ));
          }

          ptr1 = ptr3;   count++;
     }

     return count;
}
/* ------------------------------------------------------------------ */

int  strong( char const *html, char const *text )
{
     return printf( "<a href=\"%s/~njas/sequences/%s\">"
                    "<strong>%s</strong></a> |\n", gl_bell, html, text );
}
/* ------------------------------------------------------------------ */

int  fail1( char const *text )
{
     fprintf(  stderr,
               "Specify %s sequence\n\teither as command line "
               "arguments separated by blanks after any options,\n\t"
               "or as argument seq=1,2,2,3,3,3 etc. (no blanks).\n",
               text );
     return 1;
}
/* ------------------------------------------------------------------ */

int  usage( char const *prog )
{
     fprintf(  stderr,
               "Usage: %s [A=A0XXXXX] [format=0,1,2,3,4]"
               "\n\t[height=max. table rows resp. offset]"
               "\n\t[seq=comma separated integers |"
               " sequence of integers separated by blanks]"
               "\n\tdefaults format=321 and height=0", prog );
     return 1;
}
/* ------------------------------------------------------------------ */

int  main(int argc, char **argv)
{
     int  i, j;
     char *s = getenv( "QUERY_STRING" );

     if ( s )       /* Started as CGI: invalidate arguments */
     {
          argv++;   parse_url_query_string( s );
          printf( "Content-Type: %s\r\n\r\n", "text/html" );
          fflush( NULL );
     }
     else if ( argc < 2 ) return usage( *argv );
     else while ( *++argv && strchr( *argv, '=' ))
          parse_url_query_string( *argv );

     /* ------ either args or seq ----------------------------------- */

     if        ( ! *argv == ! gl_seq )  return fail1( "one" );
     else if   ( ! *argv )
          for ( s = strtok( gl_seq, gl_tok ); s; s = strtok( 0, gl_tok ))
          {
               if ( gl_count == MAXTERMS ) break;
               gl_terms[ gl_count++ ] = s;
          }
     else for ( ; *argv; gl_terms[ gl_count++ ] = *argv++ )
               if ( gl_count == MAXTERMS ) break;

     if ( ! gl_count ) return fail1( "a" );

     /* ------ TITLE ------------------------------------------------ */

     j = TITLE_TERMS_SIZE;    s = calloc( j + 1, sizeof (char));

     for ( i = 0; i < gl_count; ++i )
     {
          j -= strlen( gl_terms[ i ] ) + 1;  if ( j < 0 ) break;
          if ( i ) strcat( s, "," );         strcat( s, gl_terms[ i ] );
     }

     printf(   "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitio"
               "nal//EN\" \"http://validator.w3.org/sgml-lib/REC-xhtml1"
               "-20020801/xhtml1-transitional.dtd\">\n<html lang=\"en\""
               " xml:lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\""
               "><head>\n    <meta http-equiv=\"Content-Type\" content="
               "\"text/html; charset=us-ascii\" />\n    <title>%s %u te"
               "rms: %s%s</title>\n</head>",
               gl_A_seqid, gl_count, s, ( i < gl_count ? ",..." : "" ));
     printf( "\n<!-- njas " __FILE__ ", " __DATE__ " " __TIME__ " -->" );
     free( s );

     /* ------ EIS LOGO --------------------------------------------- */

     printf( "\n<body bgcolor=\"#ffffff\">" );
     printf(   "<div align=\"center\"> <h1><img border=\"0\" width=\"33"
               "6\" height=\"48\" src=\"%s/~njas/banners/IntegerSeq.gif"
               "\" alt=\"Encyclopedia of Integer Sequences\" /></h1></d"
               "iv>", gl_bell );

     /* ------ TABLES ----------------------------------------------- */

     for ( i = 0, s = gl_format; *s; s++ )
     {
          printf(   "\n<div align=\"center\"><h2><a href=\"%s/cgi-bin/"
                    "access.cgi/as/njas/sequences/eisA.cgi?Anum=%s\">%"
                    "s</a> format", gl_bell, gl_A_seqid, gl_A_seqid );
          switch (*s)
          {
               case '0':
                    printf(   "ted as a constant (usually in base 10):"
                              "</h2>" );
                    show_isc();                   break;
               case '1':
                    printf( "ted as a square array:</h2>" );
                    showtable( 0 );     i = 1;    break;
               case '2':
                    printf( "ted as an upper right triangle:</h2>" );
                    showtable( 1 );     i = 1;    break;
               case '3':
                    printf( "ted as a triangular array:</h2>" );
                    showtriangle();     i = 1;    break;
               case '4':
                    printf( "ted as simple table:</h2>" );
                    show_seq( 0 );                break;
               case '5':
                    printf( "ted as table of digits:</h2>" );
                    show_seq( 1 );                break;
               default:
                    printf( " unknown - please report error</h2>" );
                    break;
          }

          printf( "</div>\n" );
     }
     /* ------ NOTE ------------------------------------------------- */

     if ( i )
          printf(   "\n<p>"
                    "<strong>Note:</strong> These are just suggestions"
                    " - check the entry <a href=\"%s/cgi-bin/access.cg"
                    "i/as/njas/sequences/eisA.cgi?Anum=%s\">%s</a>, es"
                    "pecially the Example lines, to see if one of them"
                    " is compatible with the description of the sequen"
                    "ce.</p>" , gl_bell , gl_A_seqid , gl_A_seqid );

     /* ------ EIS LINKS -------------------------------------------- */

     printf(   "\n<div align=\"center\"><form method=\"get\" action=\""
               "%s/cgi-bin/access.cgi/as/njas/sequences/eisA2.cgi\">"
               "Show <a href=\"%s/~njas/sequences/eishelp1.html\">inte"
               "rnal format</a> for this sequence? <input type=\"hidde"
               "n\" name=\"Anum\" value=\"%s\" /> <input type=\"submit"
               "\" value=\"Yes\" /></form><p>" ,
               gl_bell , gl_bell , gl_A_seqid );

     strong( "index.html", "Lookup" );
     strong( "Sindx.html", "Index" );
     strong( "WebCam.html", "WebCam" );
     strong( "FAQ.html", "FAQ" );
     strong( "eishelp2.html", "Format" );
     strong( "Submit.html", "Contribute" );
     strong( "Seis.html", "EIS" );
     printf(   "<a href=\"%s/~njas/\"><strong>NJAS</strong></a>\n",
               gl_bell );
     printf( "</p></div>\n" );

     /* ------ ATT LINKS -------------------------------------------- */

     printf(   "<hr /><div align=\"center\"><p><small>\n"
               " <a href=\"/\">home</a> |\n"
               " <a href=\"/info/\">people</a> |\n"
               " <a href=\"/info/Projects\">projects</a> |\n"
               " <a href=\"/areas/\">research areas</a> |\n"
               " <a href=\"/resources/\">resources</a> \n"
               "</small></p></div>\n" );

     /* ------ POLICY MAP ------------------------------------------- */

     printf(   "<a href=\"/maps/CopyrightNotice2.map\"><img ismap=\"is"
               "map\" src=\"/footers/CopyrightNotice2.gif\" width=\"31"
               "9\" height=\"58\" border =\"0\" alt=\" Copyright and P"
               "rivacy Notice\" /></a>" );
     printf( "\n</body></html>\n" );

     return 0;
}
