martes, 12 de junio de 2012

Ordenador vs computador

Llevo 14 años organizando archivos, para computar números saqué la calculadora solar durante ese periodo.

domingo, 10 de junio de 2012

Inforvudú: Win7 y caracteres no latinos

Ventana de lenguaje no Unicode
Jai chinai chinita
Supuestamente desde Windows Vista, por defecto ya viene instalado el soporte para caracteres no latinos (más bien asiáticos, porque el griego, árabe y el cirílico no suele dar muchos problemas). Con Vista la verdad es que no tuve ningún problema, faltaban caracteres de lenguajes y otros símbolos que nunca ví ni usé excepto en páginas especializadas en Unicode.

Podía ver los símbolos de la página de Wikipedia de la (¿ex?)mujer de Frank de la Jungla o ver el nombre de un archivo con caracteres chinos/japoneses en el disco duro (sobre todo música, otra cosa es que el Evil Player no me lo reprodujera por esa cuestión, aunque otros programas sí que lo hacían sin problema)

Sin embargo con Windows 7 Professional 64 bits, me sucede un caso de inforvudú singular: En las páginas web el Unicode funciona sin ningún problema, pero en cualquier otro programa o el explorador se me ven los dichoso cuadraditos (incluso también en la barra de título del navegador).

También la Informagia que hay que hacer para que se puedan ver se las trae... buscando por ahí en los foros de Micosoft he encontrado dos posibles soluciones. Agarraos a cada una más cutre y desesperante para clamar al cielo:
  1. Cambiar el lenguaje por defecto para los programas no Unicode a los distintos lenguajes que dan problemas:
    Se haría yendo a Panel de Control / Configuración regional y de idioma / Administrativo / Cambiar configuración regiona del sistema y en esa ventana seleccionar Chino por ejemplo y aceptar los cambios.

    De entrada cada vez que se cambia el idioma hay que reiniciar, y es un coñazo. Pero la informagia es que si tras reiniciar vuelves a ponerlo en español los caracteres siguen funcionando como si no ha pasado nada. Para rizar el rizo, de hecho se puede hacer el combo: Chino -> Tailándes -> ... -> Español y volverán a funcionar tanto los de tailandés como los chinos y otros que te hayas recorrido.

    Pero claro, no todo va a ser magia buena... Windows 7 se puede vengar de un momento a otro (tras actualizar el sistema o instalar algún programa) y te vuelve a mostrar los cuadraditos sin más. Aunque posiblemente te hayas enfadado más porque te ha jodido las asociaciones de las extensiones de archivos a programas "gratis legales"
  2. Tener en el escritorio un archivo o carpeta que contenga alguno de estos símbolos:
    Me cagüen todo, solo faltaba que se tuviera que introducir el código Konami.

Realmente creo que el problema debe estar con la caché de fuentes de texto... pero aún así cojines, sino se encuentra en la caché búscalo en el disco duro hostias...

Kanji de Cerdo (豕) + Kanji de Corona (宀) = 家 ... Casa

miércoles, 6 de junio de 2012

Utilidad de Chixpy: FTerraChat (Obsoleta)

Meh, como hace mucho que no escribo voy a poner el código fuente de una pequeña utilidad que acabo de descubrir que ha quedado obsoleta. Hacía más de 7 u 8 meses que no la usaba, así que no sé cuando dejo funcionar... Posiblemente si me animo suba pequeños códigos fuente de programitas triviales que he ido haciendo.

El código está escrito en Object Pascal con Lazarus y fue probado en Linux. En principio no debería ningún problema por compilarlo en Windows (u otro SO), pero por razones obvias que luego verás se hizo en Linux.

El programa: FTerraChat


Pues digamos que el programa lo único que hacía era dar formato a la conversación UDP (o TCP, I don't remember) generada entre el cliente de IRC de Terra y los servidores de IRCHispano. Nada más complicado, excepto para los que les ha sonado a chino la anterior oración XD.

Intentando explicarlo de forma más sencilla: Cuando alguien entra al chat de Terra, los textos enviados y recibidos tenían el siguiente formato:
:ALADIN!la641hm@BA5L1y.CWhlKX.virtual PRIVMSG PARDILLO:Me tengo que ir
:Marymar_5!la641hm@B6fxQ3.DRMh13.virtual JOIN :#mas_de_40
:JOVENXMADURA_MADRID!mDc@BU9aIM.AEIp50.virtual NICK :zorra50
:invitado-337326!6A0B@DbBIXG.D2wdID.virtual JOIN :#mas_de_40
:invitado-633896!d@CQzhbI.AgXaWl.virtual NICK :Antonio_
:luz38!ce7g@BA5L1y.AH03TI.virtual PRIVMSG #mas_de_40 :hola hola, alguien de castellon
:BecquerParis!s@BR7GQQ.CWhlKX.virtual PRIVMSG #mas_de_40 :alguien que le guste la poesia,romanticismo y paris?privados
PRIVMSG ALADIN :adios
:maria47!c7@Bzlt96.AH4dq0.virtual QUIT :Terra Chat

Ough, no proguntéis de cuando ni de quién lo he sacado... y el cómo... es tema aparte e interesante, porque obviamente no es mío ;-D. Entonces localizando esa conversación es un coñazo intentar seguirla si que me hice el programita para que limpiara un poquito y separara los canales abiertos (y privados >:-Q ) dejándolo:
#mas_de_40

         <luz38> hola hola, alguien de castellon
  <BecquerParis> alguien que le guste la poesia,romanticismo y paris?privados

----- -----

ALADIN

          <ALADIN> Me tengo que ir
        <PARDILLO> Adios

Que a pesar de posibles simbolillos para colores, puto analfabetismo en general y demás mariconadas, es más legible a gran escala. PARDILLO es el nombre para referirse a la persona que estaba a este lado del chat. El programa también tenía previsto poder manejar otros evento si es necesario como entradas, salidas, cambios de nick, etc; pero en verdad tan solo era reñadir morralla al asunto.

El código


program FChatTerraExe;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes, SysUtils, CustApp, strutils
  { you can add units after this };

const
  Espacio = 25;
  NPardillo = '<PARDILLO>';
type

  { TFChatTerra }

  TFChatTerra = class(TCustomApplication)
  private
    Canales: array of TStringList;

    function GetCanal(Nombre: UTF8String): TStringList;

  protected
    property Canal[Nombre:UTF8String]: TStringList read GetCanal;

    procedure DoRun; override;

  public
    procedure WriteHelp; virtual;

    procedure ProcesarLinea(aLinea: UTF8String);

    constructor Create(TheOwner: TComponent); override;
    destructor Destroy; override;
  end;

{ TFChatTerra }

function TFChatTerra.GetCanal(Nombre: UTF8String): TStringList;
var
  i: Integer;
  NCanales: Integer;
begin
  Result := nil;
  NCanales := Length(Canales);

  i := 0;
  while (i < NCanales) and (Result = nil) do
  begin
    if Canales[i] <> nil then
    begin
      if Canales[i][0] = Nombre then
        Result := Canales[i];
    end;
    Inc(i);
  end;

  if Result = nil then
  begin
    SetLength(Canales, NCanales + 1);
    Canales[NCanales]:= TStringList.Create;
    Canales[NCanales].Add(Nombre);
    Canales[NCanales].Add('');
    Result := Canales[NCanales];
  end;
end;

procedure TFChatTerra.DoRun;
var
  ErrorMsg: String;
  ChatFile: TStringList;
  i: Integer;
  Fecha: TDateTime;
begin
  // quick check parameters
  ErrorMsg:=CheckOptions('h','help');
  if ErrorMsg<>'' then begin
    ShowException(Exception.Create(ErrorMsg));
    Terminate;
    Exit;
  end;

  // parse parameters
  if (HasOption('h','help')) or (Params[1]= '') then begin
    WriteHelp;
    Terminate;
    Exit;
  end;

  if not FileExists(Params[1]) then
  begin
    WriteLn('No se ha encontrado el archivo: ' + Params[1]);
    Terminate;
    Exit;
  end;

  // TODO 2: ¿Cómo se envían las multilíneas?
  ChatFile := TStringList.Create;
  try
    ChatFile.LoadFromFile(Params[1]);
    i:=0;
    while i < ChatFile.Count do
    begin
      ProcesarLinea(ChatFile[i]);
      Inc(i);
    end;
  finally
    FreeAndNil(ChatFile);
  end;

  ChatFile := TStringList.Create;
  try
    i:=0;
    while i < Length(Canales) do
    begin
      ChatFile.AddStrings(Canales[i]);
      ChatFile.Add('');
      ChatFile.Add('----- -----');
      ChatFile.Add('');
      Inc(i);
    end;
  finally
    Fecha := FileDateToDateTime(FileAge(Params[1]));
    ChatFile.SaveToFile(ExtractFilePath(Params[1]) +
      FormatDateTime('yyyymmddhhnnss', Fecha) + ' - Terra.txt');
    FreeAndNil(ChatFile);
  end;

  // stop program loop
  Terminate;
end;

constructor TFChatTerra.Create(TheOwner: TComponent);
begin
  inherited Create(TheOwner);
  StopOnException:=True;
end;

destructor TFChatTerra.Destroy;
begin
  inherited Destroy;
end;

procedure TFChatTerra.WriteHelp;
begin
  { add your help code here }
  writeln('Usage: ',ExeName,' -h');
end;

procedure TFChatTerra.ProcesarLinea(aLinea: UTF8String);

  procedure DoPRIVMSG(aNick, aCanal, aMensaje: UTF8String);
  var
    CurCanal: TStringList;
  begin
    // ¿Es un mensaje privado al pardillo?
    // Si es así el canal es el nick que envía el mensaje
    if (aCanal[1] <> '#') and (aNick <> NPardillo) then
      aCanal := aNick;
    CurCanal := GetCanal(aCanal);
    CurCanal.Add(RightStr(DupeString(' ', Espacio) + '<' + aNick + '> ', Espacio)
      + aMensaje);
  end;

  procedure DoQUIT(aNick, aCanal, aMensaje: UTF8String);
  var
    i: Integer;
    CurCanal: TStringList;
    NCanales: Integer;
  begin
    // TODO 2: Añadir un parametro para añadir esta info
    Exit;
    {
    i := 0;
    NCanales := Length(Canales);
    while (i < NCanales) do
    begin
      CurCanal := Canales[i];
      if CurCanal <> nil then
        if CurCanal[0][1] = '#' then
          CurCanal.Add(DupeString(' ', Espacio) + '<== QUIT <== ' + aNick +
            ' (' + aMensaje + ')');
      Inc(i);
    end;
    }
  end;

  procedure DoPART(aNick, aCanal, aMensaje: UTF8String);
  var
    CurCanal: TStringList;
  begin
    // TODO 2: Añadir un parametro para añadir esta info
    Exit;
    {
    if aCanal[1] <> '#' then
      aCanal := '#' + aNick;
    CurCanal := GetCanal(aCanal);
    CurCanal.Add(DupeString(' ', Espacio) + '<-- PART ' + aNick + ' (' + aMensaje + ')');
    }
  end;

  procedure DoJOIN(aNick, aCanal, aMensaje: UTF8String);
  var
    CurCanal: TStringList;
  begin
    // TODO 2: Añadir un parametro para añadir esta info
    Exit;
    {
    // El JOIN no tiene canal, pero lo indica en el mensaje
    if aMensaje[1] <> '#' then
      aMensaje := '#' + aMensaje;
    CurCanal := GetCanal(aMensaje);
    CurCanal.Add(DupeString(' ', Espacio) + '==> JOIN ' + aNick + ' (' + aMensaje + ')');
    }
  end;

  procedure DoPING(aNick, aCanal, aMensaje: UTF8String);
  begin
    // Por el momento lo ignoramos
    Exit;
  end;

  procedure DoPONG(aNick, aCanal, aMensaje: UTF8String);
  begin
    // Por el momento lo ignoramos
    Exit;
  end;

  procedure DoMODE(aNick, aCanal, aMensaje: UTF8String);
  begin
    // Ignoramos los baneos y cambios de modo, no interesan por el momento
    Exit;
  end;

  procedure DoKICK(aNick, aCanal, aMensaje: UTF8String);
  begin
    // Ignoramos los kick, no interesan por el momento
    Exit;
  end;

  procedure DoNICK(aNick, aCanal, aMensaje: UTF8String);
  begin
    // También ignoramos los cambios de nick...

    Exit;
  end;

  procedure DoACTION(aNick, aAccion, aCanal, aMensaje: UTF8String);
  var
    i: Integer;
    CurCanal: TStringList;
    NCanales: Integer;
  begin
    if aCanal = '' then
    begin
      i := 0;
      NCanales := Length(Canales);

      while (i < NCanales) do
      begin
        CurCanal := Canales[i];
        if CurCanal <> nil then
          if CurCanal[0][1] = '#' then
            CurCanal.Add('[' + aAccion + '] ' + aNick + ' (' + aMensaje + ')');
        Inc(i);
      end;
    end
    else
    begin
      if aCanal[1] <> '#' then
        aCanal := '#' + aNick;
      CurCanal := GetCanal(aCanal);
      CurCanal.Add('[' + aAccion + '] ' + aNick + ' (' + aMensaje + ')');
    end;
  end;

var
  aPos: Integer;
  aNick: UTF8String;
  aAccion: UTF8String;
  aCanal: UTF8String;
  aMensaje: UTF8String;
begin
  // YEEEEP!!! Los mensajes a los canales se realizan con private message
  //   (PRIVMSG) peeeero los canales tienen # y los privados de verdad no.
  // Esto me hace la tarea algo más fácil...

  if aLinea[1] = ':' then
  begin // Es un mensaje normal...
    aLinea := Copy(aLinea, 2, MaxInt);

    // NICK
    // No creo que necesite el !blah@blah.blah
    //   Aunque... vendría perfecto para los cambios de nombre o
    //   cuando uno sale y entra on otro nick.
    aNick := Copy(aLinea, 1, Pos('!', aLinea) - 1);
    aLinea := Copy(aLinea, Pos(' ', aLinea) + 1, MaxInt);
  end;

  // ACCION
  aAccion := Copy(aLinea, 1, Pos(' ', aLinea) - 1);
  aLinea := Copy(aLinea, Pos(' ', aLinea) + 1, MaxInt);

  // CANAL
  if aLinea[1] = ':' then
  begin
    // Algunas acciones no tienen Canal -> ':nick!bla@bla QUIT :Terra Chat'
    aCanal := '';
    aLinea := Copy(aLinea, 2, MaxInt);
  end
  else
  begin
    // Algunas acciones no tienen mensaje: ':nick!bla@bla PART #canal'
    aPos := Pos(' :', aLinea);
    if aPos = 0 then
    begin
      aCanal := Copy(aLinea, 1, MaxInt);
      aLinea := ''
    end
    else
      aCanal := Copy(aLinea, 1, aPos - 1);
      aLinea := Copy(aLinea, aPos + 2, MaxInt);
  end;

  // MENSAJE
  // (Podía haberlo puesto dónde el canal pero así queda más ordenado)
  aMensaje := aLinea;

  if aNick = '' then
    aNick := NPardillo;

  if aAccion = 'PRIVMSG' then DoPRIVMSG(aNick, aCanal, aMensaje)
  else if aAccion = 'QUIT' then DoQUIT(aNick, aCanal, aMensaje)
  else if aAccion = 'PART' then DoPART(aNick, aCanal, aMensaje)
  else if aAccion = 'JOIN' then DoJOIN(aNick, aCanal, aMensaje)
  else if aAccion = 'PING' then DoPING(aNick, aCanal, aMensaje)
  else if aAccion = 'PONG' then DoPONG(aNick, aCanal, aMensaje)
  else if aAccion = 'MODE' then DoMODE(aNick, aCanal, aMensaje)
  else if aAccion = 'NICK' then DoNICK(aNick, aCanal, aMensaje)
  else if aAccion = 'KICK' then DoKICK(aNick, aCanal, aMensaje)
  else DoACTION(aNick, aAccion, aCanal, aMensaje);
end;

var
  Application: TFChatTerra;

{$IFDEF WINDOWS}{$R FChatTerraExe.rc}{$ENDIF}

begin
  Application:=TFChatTerra.Create(nil);
  Application.Title:='FChatTerra';
  Application.Run;
  Application.Free;
end.

Posibilidad de actualización


Puede que algún día me entretenga, analizando el nuevo formato y adapte el programa en consecuencia; ya que no es tan difícil de entender aunque esté algo ofuscado.