Author Topic: Rexx -> IBM C  (Read 381 times)

André Heldoorn

  • Sr. Member
  • ****
  • Thank You
  • -Given: 38
  • -Receive: 9
  • Posts: 337
    • View Profile
Rexx -> IBM C
« on: October 10, 2018, 11:36:50 am »
I've got a list of names, with about 10 possibly occuring characters which have to be converted to Netscape's HTML. I'm checking all characters and insert missing characters ("&": "amp", "á": "á"). The number of characters is known and limited.

The virtual code below works. Is this a normal way to do this? Should I be using "case" instead of a nested "if"? Several apps use the same code (and names), so should this become a DLL?

Execution speed is not a problem. Speed gains are nice-to-have, in this case.

Just checking, I don't want to get used to bad programming habits like using a sprintf(buf,"%s",text) instead of a strcpy(buf,text). I'm aware of the lack of comments, and so on. A global variable (buffer) is used to avoid arguments, TBH. With Rexx I'd use functions like INSERT and/or CHANGESTR, but I assumed that with C you'll have to insert characters the harder way.


Code: [Select]
void HTMLName(void)
{
int i,j,len;

len=strlen(buffer);

for (i=0;i<len;i++)
   {
   if (buffer[i]=='&')
      {             
      for (j=len+3;j-4>i;j--)
         buffer[j]=buffer[j-4];
      buffer[++i]='a';
      buffer[++i]='m';
      buffer[++i]='p';
      buffer[++i]=';';
      buffer[len+4]=0;
      len=strlen(buffer);
      }
   else if (buffer[i]=='á')
      {             
      for (j=len+6;j-7>i;j--)
         buffer[j]=buffer[j-7];
      buffer[i]='&';
      buffer[++i]='a';
      buffer[++i]='a';
      buffer[++i]='c';
      buffer[++i]='u';
      buffer[++i]='t';
      buffer[++i]='e';
      buffer[++i]=';';
      buffer[len+7]=0;
      len=strlen(buffer);
      }
   else if (buffer[i]=='¥')
      {             

      ...

      }
   else if (buffer[i]== ... )
      {             

      ...

      }
   }
return;
}

Rick C. Hodgin

  • Newbie
  • *
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 37
  • Greetings. I come in peace (for OS/2 things only).
    • View Profile
Re: Rexx -> IBM C
« Reply #1 on: October 10, 2018, 02:21:44 pm »
I've got a list of names, with about 10 possibly occuring characters which have to be converted to Netscape's HTML. I'm checking all characters and insert missing characters ("&": "amp", "á": "&aacute;"). The number of characters is known and limited.

The virtual code below works. Is this a normal way to do this? Should I be using "case" instead of a nested "if"? Several apps use the same code (and names), so should this become a DLL?

Execution speed is not a problem. Speed gains are nice-to-have, in this case.

Just checking, I don't want to get used to bad programming habits like using a sprintf(buf,"%s",text) instead of a strcpy(buf,text). I'm aware of the lack of comments, and so on. A global variable (buffer) is used to avoid arguments, TBH. With Rexx I'd use functions like INSERT and/or CHANGESTR, but I assumed that with C you'll have to insert characters the harder way.


Code: [Select]
void HTMLName(void)
{
int i,j,len;

len=strlen(buffer);

for (i=0;i<len;i++)
   {
   if (buffer[i]=='&')
      {             
      for (j=len+3;j-4>i;j--)
         buffer[j]=buffer[j-4];
      buffer[++i]='a';
      buffer[++i]='m';
      buffer[++i]='p';
      buffer[++i]=';';
      buffer[len+4]=0;
      len=strlen(buffer);
      }
   else if (buffer[i]=='á')
      {             
      for (j=len+6;j-7>i;j--)
         buffer[j]=buffer[j-7];
      buffer[i]='&';
      buffer[++i]='a';
      buffer[++i]='a';
      buffer[++i]='c';
      buffer[++i]='u';
      buffer[++i]='t';
      buffer[++i]='e';
      buffer[++i]=';';
      buffer[len+7]=0;
      len=strlen(buffer);
      }
   else if (buffer[i]=='¥')
      {             

      ...

      }
   else if (buffer[i]== ... )
      {             

      ...

      }
   }
return;
}

I don't think the code you have will work like you want it to.  You're scanning through buffer[ i ], and you're updating into buffer[ ++i ], meaning when you encounter "&" you'll be replacing it with "&amp;" and overwriting whatever would've come after.  So to address this you're moving everything over backward from the end, but how big was your allocation buffer to begin with?  You're likely to destroy memory control blocks doing this unless your allocated buffer just happened to have enough space to allow this expansion.

What you should do instead is allocate a bufout block, and rename your buffer to bufin, and then copy everything from bufin to bufout and when you encounter special characters, use the translation and inject the multiple characters.  You can also do this in a lazy fashion, meaning you don't need to allocate the output buffer until you do a first pass through to find out how big your output buffer needs to be.  If you don't find any special characters, no translation is required.  If so, you know exactly how many to add.

If you know your input buffer is ASCII-0 terminated, then you can change your loop, which will prevent the initial scan all the way through buffer to get the count.

Code: [Select]
for (i = 0; bufin[i] != 0; ++i)
{
    // Code here
}

You can also use switch if you are looking for single-character cues.  Make sure you add the breaks.  And you can use a default clause to just copy:

Code: [Select]
switch (bufin[i])
{
    case '&':
        // Code here
        break;

    case 'á':
        // Code here
        break;

    case '¥':
        // Code here
        break;

    ...

    default:
        bufout[j++] = bufin[i];
        break;
}

When you're finished, bufout will be the HTMLName version, and bufin can be discarded.

General form:
Code: [Select]
for (pass = 1; pass <= 2; ++pass)
{
    if (pass == 1)
    {
        // Counting how big bufout will need to be
        for (i = 0, newsize = 0; bufin[i] != 0; ++i)
        {
            switch (bufin[i])
            {
                case '&':
                    newsize += 5;   // size of "&amp;"
                    break;
                case 'á':
                    newsize += 8;   // size of "&accute;"
                    break;
                ...
                default:
                    ++newsize;
                    break;
            }
        }
        continue;

    } else if (newsize == i - 1) {
        // No expansion was required;
        bufout = NULL;

    } else if ((bufout = malloc(newsize + 1))) {
        // Populate our output buffer
        bufout[newsize] = 0;
        for (i = 0, newsize = 0; bufin[i] != 0; ++i)
        {
            switch (bufin[i])
            {
                case '&':
                    newsize += strcpy(bufout + newsize, "&amp;");
                    break;
                case 'á':
                    newsize += strcpy(bufout + newsize, "&accute;");
                    break;
                ...
                default:
                    bufout[newsize++] = bufin[i];
                    break;
            }
        }
    }

    // Free our input buffer
    if (bufout)    free(bufin);
    else           bufout = bufin;

}

Untested, but something like that.
« Last Edit: October 10, 2018, 06:24:44 pm by Rick C. Hodgin »

André Heldoorn

  • Sr. Member
  • ****
  • Thank You
  • -Given: 38
  • -Receive: 9
  • Posts: 337
    • View Profile
Re: Rexx -> IBM C
« Reply #2 on: October 12, 2018, 01:27:58 pm »
I don't think the code you have will work like you want it to.  You're scanning through buffer[ i ], and you're updating into buffer[ ++i ], meaning when you encounter "&" you'll be replacing it with "&amp;" and overwriting whatever would've come after.

Thanks, I'll apply the suggestions, if anything to avoid a weird coding style. Main ones: compile a new string to not save a few bytes or to mimic a Rexx function, and switch.

The &amp; code works (which should insert "amp;"), but the other code may be broken:

"Boussard&Gavaudan £" -> "Boussard&amp;Gavaudan £". I was expecting a &pound; as a final character now, but I'll have to check that specific character later. Not important; this is about not adopting a weird coding style due to mainly ported code. Fixing a bug, if any, should be easy. The on-topic &amp; is the expected result.

André Heldoorn

  • Sr. Member
  • ****
  • Thank You
  • -Given: 38
  • -Receive: 9
  • Posts: 337
    • View Profile
Re: Rexx -> IBM C
« Reply #3 on: October 13, 2018, 08:08:07 pm »
"Boussard&Gavaudan £" -> "Boussard&amp;Gavaudan £". I was expecting a &pound; as a final character now

FWIW: possibly a feature (of a FF) instead of a bug. The real source code uses &pound;, but source code displayed by a FF apparently shows this as £ again. The target browser is Netscape/2 (and anything newer), so I didn't check which character may possible be supported by now without having to HTMLífy this character.

The code now uses strcat() and switch(). No pointers (to pointers) yet, but the global variable isn't that large and I claim to know how that works. Instead of using HTMLName(record.name) I'm using strcpy(buffer,record.name);HTMLName() now.

Dave Yeo

  • Hero Member
  • *****
  • Thank You
  • -Given: 9
  • -Receive: 109
  • Posts: 1569
    • View Profile
Re: Rexx -> IBM C
« Reply #4 on: October 13, 2018, 08:40:26 pm »
It may depend on codepage how FF prints a character. Really everything should be unicode but our port still supports codepages and there may be bugs as Mozilla mostly ripped out codepage support and Bitwise re-added.

André Heldoorn

  • Sr. Member
  • ****
  • Thank You
  • -Given: 38
  • -Receive: 9
  • Posts: 337
    • View Profile
Re: Rexx -> IBM C
« Reply #5 on: October 14, 2018, 11:01:27 am »
It may even be a bug of FF 62.0.3, or a feature of DOM. DOM says the source code of the selected text is "£".  The source code of the whole page gets is right by showing the original "&pound;". Perhaps, with ye olde charset=iso-8859-1 or all charsets, is DOM trying to be smart when &pound; may not be required (anymore) to display the GBP character correctly.

The source of the "&" in the same name is always "&amp;".

AFAICT all browsers are showing the HTML page correctly. It could have been my bug because the "£" was a last character of a name, but it wasn't.

If you ever want to copy & paste HTML code, then don't use "DOM source" but use the source code of the whole page. Apparently DOM may show interpreted, improved or simplified source code.