
//  ------------------------------------------------------------------
//  GoldED+
//  Copyright (C) 1990-1999 Odinn Sorensen
//  Copyright (C) 1999-2000 Alexander S. Aganichev
//  ------------------------------------------------------------------
//  This program is free software; you can redistribute it and/or
//  modify it under the terms of the GNU General Public License as
//  published by the Free Software Foundation; either version 2 of the
//  License, or (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
//  MA 02111-1307 USA
//  ------------------------------------------------------------------
//  $Id$
//  ------------------------------------------------------------------
//  Language compiler
//  ------------------------------------------------------------------

#include <golded.h>
#include <gclang.h>
#include <gregex.h>


//  ------------------------------------------------------------------
//  Structure of language crc list

struct LangCrc
{
    word   crc;
    char** langptr;
    char*  langdef;
};


//  ------------------------------------------------------------------
//  Language CRC16/Pointer/Default list

static LangCrc LangCrcs[] =
{

    { CRC_MS_SWSUN, NULL, "Sun" },
    { CRC_MS_SWMON, NULL, "Mon" },
    { CRC_MS_SWTUE, NULL, "Tue" },
    { CRC_MS_SWWED, NULL, "Wed" },
    { CRC_MS_SWTHU, NULL, "Thu" },
    { CRC_MS_SWFRI, NULL, "Fri" },
    { CRC_MS_SWSAT, NULL, "Sat" },

    { CRC_MS_LWSUNDAY, NULL, "Sunday" },
    { CRC_MS_LWMONDAY, NULL, "Monday" },
    { CRC_MS_LWTUESDAY, NULL, "Tuesday" },
    { CRC_MS_LWWEDNESDAY, NULL, "Wednesday" },
    { CRC_MS_LWTHURSDAY, NULL, "Thursday" },
    { CRC_MS_LWFRIDAY, NULL, "Friday" },
    { CRC_MS_LWSATURDAY, NULL, "Saturday" },

    { CRC_MS_SMJAN, NULL, "Jan" },
    { CRC_MS_SMFEB, NULL, "Feb" },
    { CRC_MS_SMMAR, NULL, "Mar" },
    { CRC_MS_SMAPR, NULL, "Apr" },
    { CRC_MS_SMMAY, NULL, "May" },
    { CRC_MS_SMJUN, NULL, "Jun" },
    { CRC_MS_SMJUL, NULL, "Jul" },
    { CRC_MS_SMAUG, NULL, "Aug" },
    { CRC_MS_SMSEP, NULL, "Sep" },
    { CRC_MS_SMOCT, NULL, "Oct" },
    { CRC_MS_SMNOV, NULL, "Nov" },
    { CRC_MS_SMDEC, NULL, "Dec" },

    { CRC_MS_LMJANUARY, NULL, "January" },
    { CRC_MS_LMFEBRUARY, NULL, "February" },
    { CRC_MS_LMMARCH, NULL, "March" },
    { CRC_MS_LMAPRIL, NULL, "April" },
    { CRC_MS_LMMAY, NULL, "May" },
    { CRC_MS_LMJUNE, NULL, "June" },
    { CRC_MS_LMJULY, NULL, "July" },
    { CRC_MS_LMAUGUST, NULL, "August" },
    { CRC_MS_LMSEPTEMBER, NULL, "September" },
    { CRC_MS_LMOCTOBER, NULL, "October" },
    { CRC_MS_LMNOVEMBER, NULL, "November" },
    { CRC_MS_LMDECEMBER, NULL, "December" },

    { CRC_MS_UPTIME, NULL, "%days day(s) %hours:%minutes:%seconds.%useconds" },

    { CRC_ST_IMPORTFILE, NULL, "Import File" },
    { CRC_WT_IMPORTWHICHFILE, NULL, " Import which file? " },
    { CRC_WT_IMPORTPICK, NULL, " Import " },
    { CRC_WT_IMPORTTXT, NULL, " Import " },
    { CRC_MI_IMPORTTXTTEXT, NULL, "T File as Text   " },
    { CRC_MI_IMPORTTXTQUOTE, NULL, "Q File as Quote  " },
    { CRC_MI_IMPORTTXTUUE, NULL, "U Binary as UUE  " },
    { CRC_MI_IMPORTTXTMIME, NULL, "M Binary as MIME " },
    { CRC_MI_IMPORTTXTCLIP, NULL, "C From Clipboard " },
    { CRC_MI_IMPORTTXTXLAT, NULL, "s Use Charset..  " },
    { CRC_MI_IMPORTTXTQUIT, NULL, "N Nothing / Quit " },
    { CRC_ST_IMPORTSTATUS, NULL, "Importing from %s" },
    { CRC_ST_EXPORTFILE, NULL, "Export File" },
    { CRC_WT_EXPORTWHATFILE, NULL, " Export to what file? " },
    { CRC_ST_EXPORTSTATUS, NULL, "Exporting to %s" },
    { CRC_ST_EDITSTATUS, NULL, "Edit %i,%i (%02X). %s" },
    { CRC_ST_SELECTFILES, NULL, "Select Files" },
    { CRC_WL_SELECTEDFILES, NULL, "Selected Files      " },
    { CRC_WL_SELECTEDBYTES, NULL, "         Bytes      " },
    { CRC_WL_TOTALFILES, NULL, "Total    Files      " },
    { CRC_WL_TOTALBYTES, NULL, "         Bytes      " },
    { CRC_WL_SCANNINGDIRECTORY, NULL, "             Scanning Directory             " },
    { CRC_WL_NOFILESFOUND, NULL, "             * NO FILES FOUND *             " },
    { CRC_ST_FILESPRESSKEY, NULL, "Press any key to continue" },
    { CRC_WT_AREA, NULL, "Area" },
    { CRC_WT_DESCRIPTION, NULL, "Description" },
    { CRC_WT_MSGS, NULL, "Msgs" },
    { CRC_WT_LAST, NULL, "Last" },
    { CRC_WT_ECHOID, NULL, "EchoID" },
    { CRC_ST_UNREAD, NULL, "unread" },
    { CRC_WT_SCANAREAS, NULL, " Scan Areas " },
    { CRC_MI_SCANALL, NULL, "A Scan All       " },
    { CRC_MI_SCANMARKED, NULL, "M Scan Marked    " },
    { CRC_MI_SCANCURRENT, NULL, "C Scan Current   " },
    { CRC_MI_SCANMATCHING, NULL, "t Scan Matching  " },
    { CRC_MI_SCANUNSCANNED, NULL, "U Scan Unscanned " },
    { CRC_MI_NOSCAN, NULL, "N No Scan  / ESC " },
    { CRC_WT_HEATAREAS, NULL, " Heat Areas " },
    { CRC_MI_HEATALL, NULL, "A Heat All      " },
    { CRC_MI_HEATMARKED, NULL, "M Heat Marked   " },
    { CRC_MI_HEATCURRENT, NULL, "C Heat Current  " },
    { CRC_MI_NOHEAT, NULL, "N No Heat / ESC " },
    { CRC_WT_ZAPAREAS, NULL, " Zap Areas " },
    { CRC_MI_ZAPALL, NULL, "A Zap All      " },
    { CRC_MI_ZAPMARKED, NULL, "M Zap Marked   " },
    { CRC_MI_ZAPCURRENT, NULL, "C Zap Current  " },
    { CRC_MI_NOZAP, NULL, "N No Zap / ESC " },
    { CRC_MS_DOS_SHELL, NULL, "GoldED Shell. Type EXIT To Return." },
    { CRC_IL_SCANNINGAREA, NULL, " Scanning Area:" },
    { CRC_IL_SEARCHINGFOR, NULL, " Searching for" },
    { CRC_ST_READINGMSG, NULL, "Reading Msg %u of %u" },
    { CRC_ER_OUTOFMEM, NULL, "Out of memory!" },
    { CRC_MS_HEXDUMPHEAD, NULL, "Hexdump of message header:" },
    { CRC_MS_HEXDUMPTEXT, NULL, "Hexdump of message text:" },
    { CRC_ST_RENUMBERING, NULL, "Renumbering" },
    { CRC_ST_LOCKED, NULL, " (locked)" },
    { CRC_ST_RENUMBERED, NULL, "Messages Renumbered - Press Key" },
    { CRC_WL_BLANKMSG, NULL, "" },
    { CRC_WL_WAIT, NULL, " Wait " },
    { CRC_IL_GENHEXDUMP, NULL, " Generating Hexdump - Please Wait " },
    { CRC_ST_PROCESSCC, NULL, "Processing Carbon Copies" },
    { CRC_ST_STATUSCC, NULL, "CC: %s of %s" },
    { CRC_ST_DESTINATIONCC, NULL, "Select Carbon Copy Destination" },
    { CRC_MS_LISTCC, NULL, "%s  %s" },
    { CRC_WT_DELORIG, NULL, " Delete Original? " },
    { CRC_MI_DELORIGYES, NULL, "Y       Yes Please.      " },
    { CRC_MI_DELORIGNO, NULL, "N           No!          " },
    { CRC_WT_DROPMSG, NULL, " Drop This Msg? " },
    { CRC_MI_DROPMSGYES, NULL, "Y       Yes Please.      " },
    { CRC_MI_DROPMSGNO, NULL, "N           No!          " },
    { CRC_WT_ZONEGATE, NULL, " Send via ZoneGate? " },
    { CRC_MI_ZONEGATEYES, NULL, "Y       Yes Please.      " },
    { CRC_MI_ZONEGATENO, NULL, "N           No!          " },
    { CRC_ST_QUOTEPCT, NULL, "Your Msg Contains %i%% Quotes%s" },
    { CRC_WT_SAVEMSG, NULL, " Save these %i lines? " },
    { CRC_MI_YESGREAT, NULL, "Y Yes, it's great stuff " },
    { CRC_MI_KICKIT, NULL, "N No, drop it..   / ESC " },
    { CRC_MI_CONTINUE, NULL, "C Continue writing      " },
    { CRC_MI_ROT13, NULL, "R ROT13 Crypting        " },
    { CRC_MI_ATTRS, NULL, "A Change Attributes     " },
    { CRC_MI_ORIGS, NULL, "O Change Origin         " },
    { CRC_MI_VIEW, NULL, "V View the message      " },
    { CRC_ST_SELECTDESTNODE, NULL, "Select Destination Node" },
    { CRC_WT_ATTACHFILES, NULL, " Attach Files " },
    { CRC_WT_UPDREQFILES, NULL, " Update Request Files " },
    { CRC_ST_EDITHEADER, NULL, "Edit Header Data" },
    { CRC_WT_EDITING, NULL, " Editing " },
    { CRC_MI_INTERNALED, NULL, "I Internal Editor " },
    { CRC_MI_EXTERNALED, NULL, "E External Editor " },
    { CRC_MI_SAVEMESSAGE, NULL, "S Save Message    " },
    { CRC_MI_ATTRO, NULL, "A Attributes      " },
    { CRC_MI_TEMPLATE, NULL, "T Templates       " },
    { CRC_MI_ORIGIN, NULL, "O Origins         " },
    { CRC_MI_QUITMESSAGE, NULL, "Q Quit      / ESC " },
    { CRC_ST_TEMPLATES, NULL, " Templates " },
    { CRC_WT_CHANGETEMPLATES, NULL, "Change Default Template" },
    { CRC_WT_CARBONCOPY, NULL, " Carbon Copy " },
    { CRC_MI_CCPROCESS, NULL, "P Process CC's " },
    { CRC_MI_CCIGNORE, NULL, "I Ignore  CC's " },
    { CRC_MI_CCATTRIBS, NULL, "C Change Attrs " },
    { CRC_MI_CCLISTFMT, NULL, "L List Format  " },
    { CRC_WT_CCLIST, NULL, " CC List " },
    { CRC_MI_CCLISTKEEP, NULL, "K Keep       " },
    { CRC_MI_CCLISTNAMES, NULL, "N Names only " },
    { CRC_MI_CCLISTVISIBLE, NULL, "V Visible    " },
    { CRC_MI_CCLISTHIDDEN, NULL, "H Hidden     " },
    { CRC_MI_CCLISTREMOVE, NULL, "R Remove     " },
    { CRC_WT_ATTRTITLE, NULL, " Attributes " },
    { CRC_MI_ATTR01, NULL, " Private             <Alt-P>   Archive/Sent         <Alt-B> " },
    { CRC_MI_ATTR02, NULL, " Crash               <Alt-C>   Direct               <Alt-D> " },
    { CRC_MI_ATTR03, NULL, " Received            <Alt-R>   Zonegate             <Alt-G> " },
    { CRC_MI_ATTR04, NULL, " Sent                <Alt-S>   Hub/Host-Route       <Alt-V> " },
    { CRC_MI_ATTR05, NULL, " File Attach         <Alt-A>   Immediate            <Alt-I> " },
    { CRC_MI_ATTR06, NULL, " Transit             <Alt-J>   Xmail                <Alt-X> " },
    { CRC_MI_ATTR07, NULL, " Orphan              <Alt-O>   Erase File/Sent      <Alt-E> " },
    { CRC_MI_ATTR08, NULL, " Kill/Sent           <Alt-K>   Trunc File/Sent      <Alt-T> " },
    { CRC_MI_ATTR09, NULL, " Local               <Alt-W>   Locked               <Alt-L> " },
    { CRC_MI_ATTR10, NULL, " Hold                <Alt-H>   Confirm Rcpt Request <Alt-Y> " },
    { CRC_MI_ATTR11, NULL, " File Request        <Alt-F>   FTS1 Reserved        <Alt-1> " },
    { CRC_MI_ATTR12, NULL, " Return Rcpt Request <Alt-M>   QBBS Reserved, Net   <Alt-2> " },
    { CRC_MI_ATTR13, NULL, " Return Rcpt         <Alt-N>   QBBS Reserved, Echo  <Alt-3> " },
    { CRC_MI_ATTR14, NULL, " Audit Request       <Alt-Q>   Squish Scanned       <Alt-4> " },
    { CRC_MI_ATTR15, NULL, " File Update Request <Alt-U>   Zap all attribs      <Alt-Z> " },
    { CRC_HD_FROM, NULL, " From : " },
    { CRC_HD_TO, NULL, " To   : " },
    { CRC_HD_SUBJ, NULL, " Subj : " },
    { CRC_HD_FILE, NULL, " File : " },
    { CRC_MS_EMPTYMSG, NULL, "\r" },
    { CRC_MS_AUTOATTACHMSG, NULL, "\r" },
    { CRC_MS_AUTOREQUESTMSG, NULL, "\r" },
    { CRC_MS_AUTOUPDREQMSG, NULL, "\r" },
    { CRC_WT_FILEATTACH, NULL, " File Attach " },
    { CRC_WT_FILEREQUEST, NULL, " File Request " },
    { CRC_WT_FILEUPDREQ, NULL, " Update Request " },
    { CRC_ST_FILEATTACHING, NULL, "File Attaching [%i/%i] to %u:%u/%u.%u" },
    { CRC_ST_FILEREQUESTING, NULL, "File Requesting [%i/%i] from %u:%u/%u.%u" },
    { CRC_ST_FILEUPDREQING, NULL, "Update Requesting [%i/%i] from %u:%u/%u.%u" },
    { CRC_ST_READMARKED, NULL, "Read Marked - Msg %u of %u (%u left)" },
    { CRC_ST_READALL, NULL, "Read All - Msg %u of %u (%u left)" },
    { CRC_ST_NOQRENUM, NULL, "This area cannot be renumbered" },
    { CRC_MS_HIDINGTWIT, NULL, "This is a Twit Message - Press <Home> to read."},
    { CRC_HD_VIA, NULL, "via" },
    { CRC_WT_CHANGEATTRS, NULL, "Change Message Attributes" },
    { CRC_WT_HEADERTEXT, NULL, " Enter Searchstring (Header+Text) " },
    { CRC_WT_HEADERONLY, NULL, " Enter Searchstring (Header Only) " },
    { CRC_WT_NEWAREA, NULL, ">>Pick New Area: " },
    { CRC_WT_REPLYAREA, NULL, ">>Answer In Area: " },
    { CRC_WT_COPYAREA, NULL, ">>Copy To Area: " },
    { CRC_WT_MOVEAREA, NULL, ">>Move To Area: " },
    { CRC_WT_FORWARDAREA, NULL, ">>Forward To Area: " },
    { CRC_WT_FREQAREA, NULL, ">>Filerequest In Area: " },
    { CRC_WT_FREQMENUTITLE, NULL, "Requestable files" },
    { CRC_ST_FREQSTAT, NULL, "Pick files to request" },
    { CRC_IL_FREQINFONOFILES, NULL, " No requestable files were found in this msg! " },
    { CRC_WT_COPY, NULL, " Copy " },
    { CRC_WT_MOVE, NULL, " Move " },
    { CRC_WT_COPYING, NULL, " Copying " },
    { CRC_WT_MOVING, NULL, " Moving " },
    { CRC_ST_COPYINGMSG, NULL, "Copying Msg %u of %u to %s" },
    { CRC_ST_MOVINGMSG, NULL, "Moving Msg %u of %u to %s" },
    { CRC_WT_DELETE, NULL, " Delete " },
    { CRC_WT_DELETING, NULL, " Deleting " },
    { CRC_ST_DELETINGMSG, NULL, "Deleting Msg %u of %u" },
    { CRC_WT_WRITE, NULL, " Write " },
    { CRC_WT_WRITEMSGS, NULL, " Write Msg(s) to File " },
    { CRC_WT_WRITING, NULL, " Writing " },
    { CRC_ST_WRITINGMSG, NULL, "Writing Msg %u of %u" },
    { CRC_WT_WRITINGFILE, NULL, " Writing Msg(s) to File %s " },
    { CRC_WT_WRITINGPRN, NULL, " Writing Msg(s) to Print Device " },
    { CRC_IL_READONLYWARN, NULL, " This area is READ ONLY! " },
    { CRC_WT_ISREADONLY, NULL, " Write msg anyway? " },
    { CRC_MI_READONLYYES, NULL, "Y       Yes Please.      " },
    { CRC_MI_READONLYNO, NULL, "N           No!          " },
    { CRC_IL_CHANGEWARN, NULL, " This msg is NOT from you! " },
    { CRC_WT_CHANGE, NULL, " Change this msg? " },
    { CRC_MI_CHANGEYES, NULL, "Y       Yes Please.      " },
    { CRC_MI_CHANGENO, NULL, "N           No!          " },
    { CRC_WT_DELETETHIS, NULL, " Delete this msg? " },
    { CRC_MI_DELETEYES, NULL, "Y       Yes Please.      " },
    { CRC_MI_DELETENO, NULL, "N           No!          " },
    { CRC_MI_DELETENOASK, NULL, "D       Don't ask..      " },
    { CRC_WT_GOTONEXT, NULL, " Goto Next Area? " },
    { CRC_MI_GOTONEXTYES, NULL, "Y       Yes Please.      " },
    { CRC_MI_GOTONEXTNO, NULL, "N           No!          " },
    { CRC_MI_GOTONEXTNEW, NULL, "U Yes, Next Unread Area. " },
    { CRC_WT_FORWARD, NULL, " Use FWD kludges? " },
    { CRC_MI_FORWARDYES, NULL, "Y       Yes Please.      " },
    { CRC_MI_FORWARDNO, NULL, "N           No!          " },
    { CRC_WT_MSG, NULL, "Msg" },
    { CRC_WT_MSGREAL, NULL, "Msg#" },
    { CRC_WT_FROML, NULL, "From" },
    { CRC_WT_TOL, NULL, "To" },
    { CRC_WT_SUBJL, NULL, "Subj" },
    { CRC_ST_MSGLISTER, NULL, "Lister - Msg %u of %u (%u left)" },
    { CRC_ST_COPYMOVEFORWARD, NULL, "Copy, Move or Forward this message" },
    { CRC_WT_SELECTACTION, NULL, " Action " },
    { CRC_MI_FORWARDMESSAGE, NULL, "F Forward Msg " },
    { CRC_MI_MOVEMESSAGE, NULL, "M Move    Msg " },
    { CRC_MI_COPYMESSAGE, NULL, "C Copy    Msg " },
    { CRC_MI_TOGGLESENT, NULL, "T Toggle sent " },
    { CRC_MI_QUITCMF, NULL, "Q Quit  / ESC " },
    { CRC_ST_ARE, NULL, "messages are" },
    { CRC_ST_IS, NULL, "message is" },
    { CRC_ST_MARKED, NULL, "marked" },
    { CRC_MI_MARKEDMSG, NULL, "M Marked Msgs " },
    { CRC_MI_CURRENTMSG, NULL, "C Current Msg " },
    { CRC_MI_QUITMSGS, NULL, "Q Quit  / ESC " },
    { CRC_ST_WRITEMSGSTO, NULL, "Write Msg(s) to File or Printer" },
    { CRC_WT_WRITETO, NULL, " Write To: " },
    { CRC_MI_DISKFILE, NULL, "D Disk File    " },
    { CRC_MI_PRINTER, NULL, "P Print device " },
    { CRC_MI_QUITWRITE, NULL, "Q Quit   / ESC " },
    { CRC_ST_MARKINGOPTIONS, NULL, "Message Marking" },
    { CRC_WT_MARKWHAT, NULL, " Mark What? " },
    { CRC_MI_YOURMAIL, NULL, "Y Your personal mail     " },
    { CRC_MI_FROMTOSUBJ, NULL, "H Header (From/To/Subj)  " },
    { CRC_MI_TEXTHDR, NULL, "T Text and header        " },
    { CRC_MI_THREAD, NULL, "R Reply thread           " },
    { CRC_MI_ASREAD, NULL, "s Mark thread as read    " },
    { CRC_MI_NEWMSGS, NULL, "N New msgs      >current " },
    { CRC_MI_OLDMSGS, NULL, "O Old msgs      <current " },
    { CRC_MI_ALLMSGS, NULL, "A All msgs               " },
    { CRC_MI_UNMARK, NULL, "U Unmark all msgs        " },
    { CRC_MI_RANGE, NULL, "M Msg range (bookm-curr) " },
    { CRC_MI_MARKSTOGGLE, NULL, "g Toggle all marks       " },
    { CRC_MI_QUITMARKS, NULL, "Q Quit             / ESC " },
    { CRC_WT_ENTERMARKSTRING, NULL, " Enter Marking String " },
    { CRC_ST_SEARCHINGMSG, NULL, "Searching Msg %u of %u. Marked: %u" },
    { CRC_WT_USERLISTNAME, NULL, " Userlist filename? " },
    { CRC_IL_GENUSERLIST, NULL, " Generating Userlist " },
    { CRC_WT_FILEEXISTS, NULL, " File Exists! " },
    { CRC_MI_APPEND, NULL, "A Append to end of file   " },
    { CRC_MI_OVERWRITE, NULL, "O Overwrite the file      " },
    { CRC_MI_QUITEXIST, NULL, "R Re-enter filename / ESC " },
    { CRC_IL_WARNUNSENT, NULL, " WARNING! This message is NOT sent! " },
    { CRC_IL_WARNLOCKED, NULL, " WARNING! This message is LOcKed! "},
    { CRC_ST_CHANGEORIGIN, NULL, "Change Default Origin" },
    { CRC_WT_ORIGINS, NULL, " Origins " },
    { CRC_ST_CHANGEUSERNAME, NULL, "Change Default Username" },
    { CRC_WT_USERNAMES, NULL, " Usernames " },
    { CRC_ST_CHANGEAKA, NULL, "Change Default Address AKA" },
    { CRC_WT_AKAS, NULL, " AKA's " },
    { CRC_WT_LOOKUP, NULL, " Lookup: %s " },
    { CRC_WL_PHONE, NULL, "Phone" },
    { CRC_WT_QUITGOLDED, NULL, " Quit GoldED? " },
    { CRC_MI_QUITYES, NULL, "Y       Yes Please.      " },
    { CRC_MI_QUITNO, NULL, "N           No!          " },
    { CRC_MS_EDITCMD, NULL, "Editor: %s" },
    { CRC_IL_NOORIGDEFINED, NULL, " No origins defined. Press key " },
    { CRC_IL_NOUSERDEFINED, NULL, " No usernames defined. Press key " },
    { CRC_IL_NOAKADEFINED, NULL, " No AKA's defined. Press key " },
    { CRC_IL_NOTPLDEFINED, NULL, " No templates defined. Press key " },
    { CRC_IL_NOTHREADLIST, NULL, " Sorry, no thread available. Press key "},
    { CRC_MS_SKIPPINGTWIT, NULL, "Skipping Twit Message..." },
    { CRC_MS_SKIPPINGDELETED, NULL, "Skipping Deleted Message..." },
    { CRC_MS_KILLINGTWIT, NULL, "Killing Twit Message..." },
    { CRC_IL_WRITINGCFG, NULL, " Writing Configuration " },
    { CRC_IL_COULDNOTOPEN, NULL, " Couldn't open %s " },
    { CRC_MS_PROMPT, NULL, "Enter the command \"EXIT\" to return to GoldED.\r\n" },
    { CRC_IL_UNFINISHEDMSG, NULL, " Unfinished message found! " },
    { CRC_ST_LOADUNFINISHED, NULL, "Press any key to load it or <ESC> to ignore" },
    { CRC_IL_READINGECHOLIST, NULL, "Reading Echolist Files" },
    { CRC_IL_READINGADDRMACROS, NULL, "Reading Address Macros" },
    { CRC_IL_CHECKINGNODELISTS, NULL, "Checking Nodelists" },
    { CRC_ST_CROSSPOSTING, NULL, "Crossposting in %s" },
    { CRC_IL_TWITBLANKED, NULL, " Twit Msgs Blanked " },
    { CRC_IL_TWITSKIPPED, NULL, " Twit Msgs Skipped " },
    { CRC_IL_TWITIGNORESKIP, NULL, " Twit Msgs Ignored and Skipped " },
    { CRC_IL_TWITDISPLAYED, NULL, " Twit Msgs Displayed " },
    { CRC_IL_TWITKILLED, NULL, " Twit Msgs Killed " },
    { CRC_IL_STYLECODESNO, NULL, " Stylecodes disabled " },
    { CRC_IL_STYLECODESYES, NULL, " Stylecodes enabled " },
    { CRC_IL_STYLECODESHIDE, NULL, " Stylecodes enabled and stripped " },
    { CRC_ST_GENCFMRECEIPT, NULL, "Generating Confirmation Receipt" },
    { CRC_WT_NEW, NULL, "New" },
    { CRC_ST_LOOKUPINFO, NULL, "Nodelist Lookup Information" },
    { CRC_MS_DATETIMEFMT, NULL, "%d %b %y %H:%M:%S" },
    { CRC_MS_DATEFMT, NULL, "%d %b %y" },
    { CRC_MS_TIMEFMT, NULL, "%H:%M" },
    { CRC_MS_ORIGINALLYIN, NULL, "* Originally in %s" },
    { CRC_MS_CROSSPOSTEDIN, NULL, "* Crossposted in %s" },
    { CRC_MS_CCTO, NULL, "* Carbon copied to %s" },
    { CRC_ST_STATUSLINEHELP, NULL, "F1 Help" },
    { CRC_HD_OF, NULL, "of" },
    { CRC_MS_ROBOTMSG, NULL, "\r--- @longpid @version\r" },
    { CRC_ST_STATUSLINETIMEFMT, NULL, "%H:%M:%S" },

    { CRC_WT_REPLIES, NULL, " Replies " },
    { CRC_ST_SELECTREPLY, NULL, "Select the reply you want to see" },
    { CRC_IL_WAITOREXIT, NULL, " At this point you must either wait or exit GoldED entirely - Sorry! " },
    { CRC_WT_REALLYEXIT, NULL, " Really exit? " },
    { CRC_MI_TAGLINES, NULL, "T Change Tagline" },
    { CRC_MI_HEADEREDIT, NULL, "H Edit Header" },
    { CRC_MI_SCANGROUP, NULL, "G Scan Group" },
    { CRC_WT_QWKPACKET, NULL, " QWK Packet " },
    { CRC_MI_SCANQWK, NULL, "Q QWK Packet" },
    { CRC_WT_SOUPPACKET, NULL, " SOUP Packet " },
    { CRC_MI_SCANSOUP, NULL, "S SOUP Packet" },
    { CRC_MI_SCANIMPORT, NULL, "I Import" },
    { CRC_MI_SCANEXPORT, NULL, "E Export" },
    { CRC_WT_SCANPM, NULL, " Scan PM " },
    { CRC_MI_TAGLINE, NULL, "g Taglines" },
    { CRC_WT_CONFIRM, NULL, " Honor receipt request? " },
    { CRC_MI_CONFIRMYES, NULL, "Y Yes, send a receipt msg " },
    { CRC_MI_CONFIRMNO, NULL, "N No, ignore the request  " },
    { CRC_IL_CONFIRMINFO, NULL, " The sender of this message requests confirmation of receipt (CFM) " },
    { CRC_ST_MSG, NULL, "msg" },
    { CRC_ST_MSGS, NULL, "msgs" },
    { CRC_ST_PERSONAL, NULL, "personal" },
    { CRC_WT_GRP, NULL, "Grp" },
    { CRC_IL_FOUNDPERSONAL, NULL, " Found %u personal mail%s in %u area%s " },
    { CRC_IL_NOPERSONAL, NULL, " No personal mail found " },
    { CRC_ST_ESCORCONTINUE, NULL, "ESC exits. Other keys: Tries to continue" },
    { CRC_MS_SPELLCHECKER, NULL, "SpellChecker: %s" },
    { CRC_WT_INS, NULL, " Ins " },
    { CRC_WT_DRAWSL, NULL, " DL1 " },
    { CRC_WT_DRAWDL, NULL, " DL2 " },
    { CRC_MI_FILELISTFROM, NULL, "Filelist from %s" },
    { CRC_ST_INITIALIZING, NULL, "Initializing ..." },
    { CRC_ST_CHECKING, NULL, "Checking" },
    { CRC_ST_LOCKSHARECAP, NULL, "%s Lock/Share Capability" },
    { CRC_WT_ATTRTURNOFF, NULL, " Press Alt-F1 to turn off this window " },
    { CRC_WT_TAGLINES, NULL, " Taglines " },
    { CRC_ST_CHANGETAGLINE, NULL, "Change Default Tagline" },
    { CRC_IL_NOTAGLINE, NULL, " No taglines defined. Press key " },
    { CRC_WT_CHARSETS, NULL, " Charsets " },
    { CRC_ST_CHANGEXLATIMP, NULL, "Change Default Import Charset" },
    { CRC_MI_CHARSETAUTO, NULL, " Auto " },
    { CRC_IL_NOXLATIMPORT, NULL, " No XLATIMPORT's defined. Press key " },
    { CRC_WT_N_A, NULL, "n/a" },
    { CRC_WT_WRITTEN, NULL, "Written" },
    { CRC_WT_ARRIVED, NULL, "Arrived" },
    { CRC_WT_RECEIVED, NULL, "Received" },
    { CRC_IL_NONODELIST, NULL, " Unable to access the nodelist or index files " },
    { CRC_IL_NODELISTMISSING, NULL, "Nodelist missing:" },
    { CRC_IL_NODELISTOUTDATED, NULL, "Nodelist out of date:" },
    { CRC_MS_REPLYLINKER, NULL, "Replylinker: %s" },
    { CRC_WT_ENTERMSGNO, NULL, " Enter msgno " },
    { CRC_IL_WAITUUDECODING, NULL, " Wait - uudecoding " },
    { CRC_IL_COMPLETEDUUDECODE, NULL, " Completed uudecode of %s " },
    { CRC_IL_NOTUUENCODED, NULL, " Could not find anything to uudecode " },
    { CRC_IL_UUEINVALIDPATH, NULL, " Invalid path for uudecoding - file not written " },
    { CRC_IL_TMPINVALIDPATH, NULL, " Invalid path for temporary files (TEMPPATH) - do nothing " },
    { CRC_IL_PATHREPORT, NULL, " Generating PATH report " },
    { CRC_IL_ERRORINSOUP, NULL, " Error in SOUP file %s " },
    { CRC_IL_WARNALREADYSENT, NULL, " WARNING: This message is already sent! " },
    { CRC_IL_WAITLOCKED, NULL, " Wait: %s is locked " },
    { CRC_ST_RETRYORESC, NULL, "%s retry (%lu). Press ESC to exit GoldED." },
    { CRC_ST_RETRYLOCK, NULL, "Lock" },
    { CRC_ST_RETRYOPEN, NULL, "Open" },
    { CRC_WT_TOUCHSEMAPHORE, NULL, " Enter name of semaphore file to touch " },
    { CRC_MI_WRITETOHDRNO, NULL, "H Use Header: NO   " },
    { CRC_MI_WRITETOHDRYES, NULL, "H Use Header: YES  "},
    { CRC_MI_WRITETOHDRONLY, NULL, "H Use Header: ONLY "},
    { CRC_MI_CLIPBOARD, NULL, "C Clipboard "},
    { CRC_WT_SELECTMARKS, NULL, " Select Mark " },
    { CRC_WT_SELECTMARKSEDIT, NULL, " Edit Mark Description " },
    { CRC_IL_DROPMARKSINFO, NULL, " %s Messages Are Marked " },
    { CRC_WT_DROPMARKS, NULL, " Drop Msg Marks " },
    { CRC_MI_DROPALL, NULL, "A Drop All       " },
    { CRC_MI_DROPMARKED, NULL, "M Drop Marked    " },
    { CRC_MI_DROPCURRENT, NULL, "C Drop Current   " },
    { CRC_MI_NODROP, NULL, "N No Drop / ESC  " },
    { CRC_WT_CATCHAREAS, NULL, " Catch-Up Areas " },
    { CRC_MI_CATCHALL, NULL, "A Catch All      " },
    { CRC_MI_CATCHMARKED, NULL, "M Catch Marked   " },
    { CRC_MI_CATCHCURRENT, NULL, "C Catch Current  " },
    { CRC_MI_NOCATCH, NULL, "N No Catch / ESC " },
    { CRC_WT_CROSSPOST, NULL, " Crosspost " },
    { CRC_MI_XCPROCESS, NULL, "P Process XC's " },
    { CRC_MI_XCIGNORE, NULL, "I Ignore  XC's " },
    { CRC_MI_XCLISTFMT, NULL, "L List Format  " },
    { CRC_WT_XCLIST, NULL, " XC List " },
    { CRC_MI_XCLISTRAW, NULL, "K Keep       " },
    { CRC_MI_XCLISTVERBOSE, NULL, "V Verbose    " },
    { CRC_MI_XCLISTLINE, NULL, "L Line       " },
    { CRC_MI_XCLISTREMOVE, NULL, "R Remove     " },

    { CRC_WT_ADDRESSBOOK, NULL, " Addressbook " },
    { CRC_WT_ADVANCEDSEARCH, NULL, " Advanced Search " },
    { CRC_IL_NOMOREMATCHES, NULL, " No more matches found " },
    { CRC_WT_HEADEREDITHELP_1, NULL, " Shift-F10: Nodelist " },
    { CRC_WT_HEADEREDITHELP_2, NULL, " F10: Addressbook " },
    { CRC_WT_THREADLISTTITLE, NULL, " Message Thread List " },
    { CRC_WT_ADVANCEDMARKING, NULL, " Advanced Marking " },
    { CRC_ST_USERSTATUSLINE, NULL, "GoldED's Address Book - %d of %d (%d left)" },
    { CRC_WT_USERHEADERNAME, NULL, "Name" },
    { CRC_WT_USERHEADERORG, NULL, "Organization" },
    { CRC_WT_USERHEADERAKA, NULL, "Address" },
    { CRC_IL_USERWAIT, NULL, " Wait - Browsing Address Book... " },

    { CRC_MI_ALSELECTIONS1, NULL, "Mark Areas with New Mail" },
    { CRC_MI_ALSELECTIONS2, NULL, "(unused)" },
    { CRC_IL_DECODE, NULL, "Decode" },
    { CRC_IL_PREPARING, NULL, "Preparing" },

    { CRC_WT_EXTERNUTIL, NULL, "External utilities" },
    { CRC_ST_EXTERNUTIL, NULL, "Select external utility to execute" },
    { CRC_WT_EXECCMDLINE, NULL, "Enter command line to execute" },
    { CRC_MI_ENTERCMDLINE, NULL, " Enter command line " },

    { CRC_WT_PEEKURL, NULL, "Available URLs" },
    { CRC_ST_PEEKURL, NULL, "Select URL" },
    { CRC_IL_PEEKINFONOURLS, NULL, " No valid URLs were found in this msg! " },
    { CRC_IL_PEEKINFONOHANDLER, NULL, " URL handler are not defined in config file! " },

    { CRC_MI_MMMAIN, NULL, "M Main " },
    { CRC_MI_MMSHELL, NULL, "S Shell to OS " },
    { CRC_MI_MMQUIT, NULL, "Q Quit GoldED " },
    { CRC_MI_MMEDIT, NULL, "E Edit " },
    { CRC_MI_MMNEWMSG, NULL, "E Enter new msg                        " },
    { CRC_MI_MMQUOTEREPLY, NULL, "Q Quote-reply                          " },
    { CRC_MI_MMDIRQUOTEREPLY, NULL, "D Direct quote-reply (ignore Reply-To) " },
    { CRC_MI_MMCMTREPLY, NULL, "C Comment-reply                        " },
    { CRC_MI_MMOTHERAREA, NULL, "O Other area reply >                   " },
    { CRC_WT_MMOTHERAREA, NULL, " Other Area " },
    { CRC_MI_MMOQUOTEREPLY, NULL, "Q Quote-reply                          " },
    { CRC_MI_MMODIRQUOTEREPLY, NULL, "D Direct quote-reply (ignore Reply-To) " },
    { CRC_MI_MMOCMTREPLY, NULL, "C Comment-reply                        " },
    { CRC_MI_MMCHANGE, NULL, "C Change " },
    { CRC_MI_MMORIGIN, NULL, "O Origin    " },
    { CRC_MI_MMUSERNAME, NULL, "U Username  " },
    { CRC_MI_MMAKA, NULL, "A Aka       " },
    { CRC_MI_MMATTRIBUTES, NULL, "M Msg attrs " },
    { CRC_MI_MMTEMPLATE, NULL, "T Template  " },
    { CRC_MI_MMUTIL, NULL, "U Util " },
    { CRC_MI_MMCOPYMOVEFORWARD, NULL, "C Copy/Move/Forward     " },
    { CRC_MI_MMLIST, NULL, "L List messages         " },
    { CRC_MI_MMWRITE, NULL, "W Write to disk/printer " },
    { CRC_MI_MMFREQ, NULL, "F File request          " },

    { CRC_LAST_CRC, NULL, NULL }
};


//  ------------------------------------------------------------------
//  Compare two crcs

static int CmpLangCrc(LangCrc* a, LangCrc* b)
{

    return((a->crc > b->crc) ? 1 : ((a->crc < b->crc) ? -1 : 0));
}


//  ------------------------------------------------------------------
//  Call the function matching the keyword

static bool SwitchLanguage(word crc, char* str)
{
    LangCrc* lptr;
    LangCrc lkey;
    lkey.crc = crc;

    switch (crc)
    {
    case CRC_ST_EDITSTATUS:
        gregex reg;
        reg.compile("^.*%[0-9-]*[dioux].*%[0-9-]*[dioux].*%[0-9-]*[dioux].*%[-0-9\\.]*s", gregex::icase);
        if (!reg.match(str))
        {
            STD_PRINTNL("ST_EDITSTATUS has wrong format. Read NOTEWORK.TXT for details or announce author if this error is false positive (first try to set true locale). Your format string is \"" << str << "\", should be 3 numbers and one string.");
            SayBibi();
            waitkeyt(10000);
        }
        break;
    }

    lptr = (LangCrc*)bsearch(&lkey, LangCrcs, sizeof(LangCrcs)/sizeof(LangCrc), sizeof(LangCrc), (StdCmpCP)CmpLangCrc);
    if(lptr != NULL)
    {
        if(lptr->langptr != NULL)
        {
            throw_xfree(*(lptr->langptr));
            *(lptr->langptr) = throw_strdup(StripQuotes(str));
        }
        return 0;
    }
    else
        return bool(-1);
}


//  ------------------------------------------------------------------
//  Unallocate all language strings

static void LangReset(void)
{

    LangCrc* lngptr = LangCrcs;

    for(; lngptr->crc < CRC_LAST_CRC; lngptr++)
        if(lngptr->langptr != NULL)
            throw_xfree(*(lngptr->langptr));

    throw_release(LNG);

    int n;
    for(n=0; n<7; n++)
        gsweekday[n] = NULL;
    for(n=0; n<7; n++)
        glweekday[n] = NULL;
    for(n=0; n<12; n++)
        gsmonth[n] = NULL;
    for(n=0; n<12; n++)
        glmonth[n] = NULL;
}


//  ------------------------------------------------------------------
//  Initialize language

void LangInit()
{

    LNG = (LangGed*)throw_calloc(1, sizeof(LangGed));
    LNG->Outofmem = throw_strdup("Out of memory!");

    // Init LangCrc pointers to LNG
    char** lptr = (char**)LNG;
    for(LangCrc* lngptr = LangCrcs; lngptr->crc != CRC_LAST_CRC; lngptr++, lptr++)
        lngptr->langptr = lptr;

    // Sort the crc list
    qsort(LangCrcs, sizeof(LangCrcs)/sizeof(LangCrc), sizeof(LangCrc), (StdCmpCP)CmpLangCrc);

    atexit(LangReset);
}


//  ------------------------------------------------------------------
//  Assign weekday/month names

void AssignDateNames()
{

    gsweekday[0] = LNG->SWSun;
    gsweekday[1] = LNG->SWMon;
    gsweekday[2] = LNG->SWTue;
    gsweekday[3] = LNG->SWWed;
    gsweekday[4] = LNG->SWThu;
    gsweekday[5] = LNG->SWFri;
    gsweekday[6] = LNG->SWSat;

    glweekday[0] = LNG->LWSunday;
    glweekday[1] = LNG->LWMonday;
    glweekday[2] = LNG->LWTuesday;
    glweekday[3] = LNG->LWWednesday;
    glweekday[4] = LNG->LWThursday;
    glweekday[5] = LNG->LWFriday;
    glweekday[6] = LNG->LWSaturday;

    gsmonth[0]  = LNG->SMJan;
    gsmonth[1]  = LNG->SMFeb;
    gsmonth[2]  = LNG->SMMar;
    gsmonth[3]  = LNG->SMApr;
    gsmonth[4]  = LNG->SMMay;
    gsmonth[5]  = LNG->SMJun;
    gsmonth[6]  = LNG->SMJul;
    gsmonth[7]  = LNG->SMAug;
    gsmonth[8]  = LNG->SMSep;
    gsmonth[9]  = LNG->SMOct;
    gsmonth[10] = LNG->SMNov;
    gsmonth[11] = LNG->SMDec;

    glmonth[0]  = LNG->LMJanuary;
    glmonth[1]  = LNG->LMFebruary;
    glmonth[2]  = LNG->LMMarch;
    glmonth[3]  = LNG->LMApril;
    glmonth[4]  = LNG->LMMay;
    glmonth[5]  = LNG->LMJune;
    glmonth[6]  = LNG->LMJuly;
    glmonth[7]  = LNG->LMAugust;
    glmonth[8]  = LNG->LMSeptember;
    glmonth[9]  = LNG->LMOctober;
    glmonth[10] = LNG->LMNovember;
    glmonth[11] = LNG->LMDecember;
}


//  ------------------------------------------------------------------
//  Load a GoldED language file

void LoadLanguage(const char* file)
{
    char* ptr;
    char* str;
    int line = 0;
    char buf[256];

    if (file==NULL || *file==0)
    {
        return;
    }
    gfile fp(AddPath(CFG->goldpath, file), "rt", CFG->sharemode);
    if (fp.isopen())
    {
        fp.SetvBuf(NULL, _IOFBF, BUFSIZ);
        while (fp.Fgets((ptr=buf), sizeof(buf)))
        {
            line++;
            ptr = strskip_wht(ptr);
            if(g_isalpha(*ptr))
            {
                str = ptr;
                strtrim(str);
                str = strskip_txt(str);
                if(*str)
                {
                    *str++ = NUL;
                    str = strskip_wht(str);
                    strschg(str, "\\n", "\n");
                    strschg(str, "\\r", "\r");
                    strschg(str, "\\\"", "\"");
                }
                if(SwitchLanguage(strCrc16(strupr(ptr)), str))
                {
                    if(cmdlineoldkeyw == false)
                    {
                        w_infof(" %s line %u: \"%s\" is obsolete or unknown ", file, line, ptr);
                        SayBibi();
                        waitkeyt(10000);
                        w_info(NULL);
                        cfgerrors++;
                    }
                }
            }
        }

        // Assign weekday/month names
        AssignDateNames();
    }
    else
        LOG.printf("? Can't load language file \"%s\", OS reports: %s!", file, strerror(errno));
}


//  ------------------------------------------------------------------
//  Read the main language definition file

bool ReadLangCfg()
{
    char* ptr;
    char* str;
    long size;
    char buf[1024];
    LangCrc* lngptr;
    int line = 0;

    // Read the GOLDLANG.CFG if there is one
    const char* cfgname = AddPath(CFG->goldpath, CFG->langcfg);

    gfile fpi(cfgname, "rt", CFG->sharemode);
    if (fpi.isopen())
    {
        fpi.SetvBuf(NULL, _IOFBF, BUFSIZ);

        if (not quiet)
            STD_PRINTNL("* Reading " << cfgname);

        cfgname = CleanFilename(cfgname);

        while (fpi.Fgets((ptr=buf), sizeof(buf)))
        {
            line++;
            ptr = strskip_wht(ptr);
            if(g_isalpha(*ptr))
            {
                str = ptr;
                strtrim(str);
                str = strskip_txt(str);
                if(*str)
                {
                    *str++ = NUL;
                    str = strskip_wht(str);
                    strschg(str, "\\n", "\n");
                    strschg(str, "\\r", "\r");
                    strschg(str, "\\\"", "\"");
                }

                if (SwitchLanguage(strCrc16(strupr(ptr)), str))
                {
                    if (cmdlineoldkeyw == false)
                    {
                        STD_PRINTNL("* " << cfgname << " line " << line << ": \"" << ptr << "\" is obsolete or unknown.");
                        SayBibi();
                        cfgerrors++;
                    }
                }
            }
        }
    }

    // Fill in the defaults if there are "holes"
    size = 0;
    lngptr = LangCrcs;
    for(; lngptr->crc < CRC_LAST_CRC; lngptr++)
    {
        if(lngptr->langptr != NULL)
        {
            if(*(lngptr->langptr) == NULL)
                *(lngptr->langptr) = throw_strdup(lngptr->langdef);
            size += strlen(*(lngptr->langptr)) + 1;
        }
    }

    AssignDateNames();

    return true;
}


//  ------------------------------------------------------------------
