Ticket #3829: localekit_base.patch

File localekit_base.patch, 311.5 KB (added by pulkomandy, 11 years ago)

*fixed* patch adding the localekit to the Haiku tree.

  • build/jam/HaikuImage

     
    4747    uptime urlwrapper useradd uudecode uuencode
    4848    vdir version vim vmstat waitfor wc wget whoami xargs xres yes
    4949    zdiff zforce zgrep zip zipcloak <bin>zipgrep zipnote zipsplit zmore znew
     50    collectcatkeys linkcatkeys dumpcatalog genprops
    5051;
    5152
    5253SYSTEM_APPS = AboutSystem ActivityMonitor CharacterMap CodyCam DeskCalc DiskProbe
     
    5657    StyledEdit Terminal TextSearch TV Workspaces
    5758;
    5859SYSTEM_PREFERENCES = Appearance Backgrounds CPUFrequency DataTranslations E-mail
    59     FileTypes Fonts Keyboard Keymap Media Menu Mouse Network Printers Screen
     60    FileTypes Fonts Keyboard Keymap Locale Media Menu Mouse Network Printers Screen
    6061    ScreenSaver Sounds Time Touchpad <preference>Tracker VirtualMemory
    6162;
    6263SYSTEM_DEMOS = BSnow Chart Clock Cortex FontDemo
     
    6869    libmail.so libtextencoding.so libz.so libfreetype.so libpng.so libmidi.so
    6970    libmidi2.so libdevice.so libgame.so libscreensaver.so <revisioned>libroot.so
    7071    libGL.so libfluidsynth.so liblpsolve55.so liblinprog.so libalm.so
    71     libilmimf.so libiconv.so
     72    libilmimf.so libiconv.so liblocale.so
    7273;
    7374SYSTEM_SERVERS = registrar debug_server syslog_daemon media_server
    7475    net_server media_addon_server input_server app_server fake_app_server
     
    273274# TODO/NOTE: Cannot use $(SYSTEM_PREFERENCES) here since there is
    274275# "<preferences>Tracker"...
    275276DESKBAR_PREFERENCES = Appearance Backgrounds CPUFrequency DataTranslations
    276     E-mail FileTypes Fonts Keyboard Keymap Media Menu Mouse Network Printers
     277    E-mail FileTypes Fonts Keyboard Keymap Locale Media Menu Mouse Network Printers
    277278    Screen ScreenSaver Sounds Time Touchpad Tracker VirtualMemory
    278279;
    279280for linkTarget in $(DESKBAR_PREFERENCES) {
     
    328329    = [ FDirName $(HAIKU_TOP) src apps mail ] ;
    329330AddFilesToHaikuImage system etc word_dictionary : $(spellFiles) ;
    330331
     332# Locale kit system-wide catalogs
     333local catalogs = deutsch français ;
     334catalogs = $(catalogs:G=catalogs).language ;
     335SEARCH on $(catalogs)
     336    = [ FDirName $(HAIKU_TOP) data etc locale languages ] ;
     337AddFilesToHaikuImage system etc locale languages : $(catalogs) ;
     338
    331339local etcFiles = bash_completion inputrc profile teapot.data ;
    332340etcFiles = $(etcFiles:G=etc) ;
    333341SEARCH on $(etcFiles) = [ FDirName $(HAIKU_TOP) data etc ] ;
  • src/preferences/locale/Locale.cpp

     
     1/*
     2 * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
     3 * Distributed under the terms of the MIT License.
     4 */
     5
     6
     7#include "Locale.h"
     8#include "LocaleWindow.h"
     9
     10#include <Application.h>
     11#include <Alert.h>
     12#include <TextView.h>
     13#include <FindDirectory.h>
     14#include <File.h>
     15#include <Path.h>
     16
     17#include <stdio.h>
     18#include <string.h>
     19
     20
     21const char *kSignature = "application/x-vnd.Haiku-Locale";
     22
     23static const uint32 kMsgLocaleSettings = 'LCst';
     24
     25
     26class Settings {
     27    public:
     28        Settings();
     29        ~Settings();
     30
     31        const BMessage &Message() const { return fMessage; }
     32        void UpdateFrom(BMessage *message);
     33
     34    private:
     35        status_t Open(BFile *file, int32 mode);
     36
     37        BMessage    fMessage;
     38        bool        fUpdated;
     39};
     40
     41
     42class Locale : public BApplication {
     43    public:
     44        Locale();
     45        virtual ~Locale();
     46
     47        virtual void ReadyToRun();
     48        virtual void MessageReceived(BMessage *message);
     49
     50        virtual void AboutRequested();
     51        virtual bool QuitRequested();
     52
     53    private:
     54        Settings    fSettings;
     55        BWindow     *fOpenWindow;
     56        BRect       fWindowFrame;
     57};
     58
     59
     60//-----------------
     61
     62
     63Settings::Settings()
     64    :
     65    fMessage(kMsgLocaleSettings),
     66    fUpdated(false)
     67{
     68    BFile file;
     69    if (Open(&file, B_READ_ONLY) != B_OK
     70        || fMessage.Unflatten(&file) != B_OK) {
     71        // set default prefs
     72        fMessage.AddRect("window_frame", BRect(50, 50, 550, 500));
     73        return;
     74    }
     75}
     76
     77
     78Settings::~Settings()
     79{
     80    // only save the settings if something has changed
     81    if (!fUpdated)
     82        return;
     83
     84    BFile file;
     85    if (Open(&file, B_CREATE_FILE | B_WRITE_ONLY) != B_OK)
     86        return;
     87
     88    fMessage.Flatten(&file);
     89}
     90
     91
     92status_t
     93Settings::Open(BFile *file, int32 mode)
     94{
     95    BPath path;
     96    if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
     97        return B_ERROR;
     98
     99    path.Append("Locale settings");
     100
     101    return file->SetTo(path.Path(), mode);
     102}
     103
     104
     105void
     106Settings::UpdateFrom(BMessage *message)
     107{
     108    BRect frame;
     109    if (message->FindRect("window_frame", &frame) == B_OK)
     110        fMessage.ReplaceRect("window_frame", frame);
     111
     112    fUpdated = true;
     113}
     114
     115
     116//  #pragma mark -
     117
     118
     119Locale::Locale()
     120    : BApplication(kSignature)
     121{
     122    fWindowFrame = fSettings.Message().FindRect("window_frame");
     123
     124    BWindow* window = new LocaleWindow(fWindowFrame);
     125    window->Show();
     126}
     127
     128
     129Locale::~Locale()
     130{
     131}
     132
     133
     134void
     135Locale::ReadyToRun()
     136{
     137    // are there already windows open?
     138    if (CountWindows() != 1)
     139        return;
     140
     141    // if not, ask the user to open a file
     142    PostMessage(kMsgOpenOpenWindow);
     143}
     144
     145
     146void
     147Locale::MessageReceived(BMessage *message)
     148{
     149    switch (message->what) {
     150        case kMsgSettingsChanged:
     151            fSettings.UpdateFrom(message);
     152            break;
     153
     154        default:
     155            BApplication::MessageReceived(message);
     156            break;
     157    }
     158}
     159
     160
     161void
     162Locale::AboutRequested()
     163{
     164    BAlert *alert = new BAlert("about", "Locale\n"
     165        "\twritten by Axel Dörfler\n"
     166        "\tCopyright 2005, Haiku.\n\n", "Ok");
     167    BTextView *view = alert->TextView();
     168    BFont font;
     169
     170    view->SetStylable(true);
     171
     172    view->GetFont(&font);
     173    font.SetSize(18);
     174    font.SetFace(B_BOLD_FACE);         
     175    view->SetFontAndColor(0, 7, &font);
     176
     177    alert->Go();
     178}
     179
     180
     181bool
     182Locale::QuitRequested()
     183{
     184    return true;
     185}
     186
     187
     188//  #pragma mark -
     189
     190
     191int
     192main(int argc, char **argv)
     193{
     194    Locale app;
     195
     196    app.Run();
     197    return 0;
     198}
  • src/preferences/locale/Locale.h

     
     1/*
     2 * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
     3 * Distributed under the terms of the MIT License.
     4 */
     5#ifndef LOCALE_H
     6#define LOCALE_H
     7
     8
     9#include <SupportDefs.h>
     10
     11
     12extern const char *kSignature;
     13
     14static const uint32 kMsgOpenFilePanel = 'opFp';
     15static const uint32 kMsgOpenOpenWindow = 'opOw';
     16static const uint32 kMsgOpenWindowClosed = 'clOw';
     17static const uint32 kMsgWindowClosed = 'WiCl';
     18static const uint32 kMsgSettingsChanged = 'SeCh';
     19
     20static const uint32 kMsgOpenFindWindow = 'OpFw';
     21static const uint32 kMsgFindWindowClosed = 'clFw';
     22static const uint32 kMsgFindTarget = 'FTgt';
     23static const uint32 kMsgFind = 'find';
     24
     25#endif  /* LOCALE_H */
  • src/preferences/locale/Jamfile

    Impossible d'afficher : fichier considéré comme binaire.
    svn:mime-type = application/octet-stream
    
    Modification de propriétés sur src/preferences/locale/Locale.rsrc
    ___________________________________________________________________
    Ajouté : svn:mime-type
       + application/octet-stream
    
     
     1SubDir HAIKU_TOP src preferences locale ;
     2
     3AddResources Locale : Locale.rsrc ;
     4
     5Preference Locale :
     6    Locale.cpp
     7    LocaleWindow.cpp
     8    : be liblocale.so ;
  • src/preferences/locale/LocaleWindow.cpp

     
     1/*
     2 * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
     3 * Distributed under the terms of the MIT License.
     4 */
     5
     6
     7#include "Locale.h"
     8#include "LocaleWindow.h"
     9
     10#include <Application.h>
     11#include <Screen.h>
     12#include <TabView.h>
     13#include <ScrollView.h>
     14#include <ListView.h>
     15#include <Button.h>
     16
     17
     18const static uint32 kMsgSelectLanguage = 'slng';
     19const static uint32 kMsgDefaults = 'dflt';
     20const static uint32 kMsgRevert = 'revt';
     21
     22
     23LocaleWindow::LocaleWindow(BRect rect)
     24    : BWindow(rect, "Locale", B_TITLED_WINDOW,
     25        B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS)
     26{
     27    rect = Bounds();
     28    BView *view = new BView(rect, "view", B_FOLLOW_ALL, 0);
     29    view->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
     30    AddChild(view);
     31
     32    BButton *button = new BButton(rect, "defaults", "Defaults",
     33        new BMessage(kMsgDefaults), B_FOLLOW_NONE);
     34    button->ResizeToPreferred();
     35    button->MoveTo(10, rect.bottom - 10 - button->Bounds().Height());
     36    view->AddChild(button);
     37
     38    fRevertButton = new BButton(rect, "revert", "Revert",
     39        new BMessage(kMsgRevert), B_FOLLOW_NONE);
     40    fRevertButton->ResizeToPreferred();
     41    fRevertButton->MoveTo(20 + button->Bounds().Width(), button->Frame().top);
     42    fRevertButton->SetEnabled(false);
     43    view->AddChild(fRevertButton);
     44
     45    rect.InsetBy(10, 10);
     46    rect.bottom -= 10 + button->Bounds().Height();
     47    BTabView *tabView = new BTabView(rect, "tabview");
     48
     49    rect = tabView->ContainerView()->Bounds();
     50    rect.InsetBy(2, 2);
     51    BView *tab = new BView(rect, "Language", B_FOLLOW_NONE, B_WILL_DRAW);
     52    tab->SetViewColor(tabView->ViewColor());
     53    tabView->AddTab(tab);
     54
     55    {
     56        BRect frame = rect;
     57        frame.InsetBy(12, 12);
     58        frame.right = 100 + B_V_SCROLL_BAR_WIDTH;
     59        frame.bottom = 150;
     60
     61        BListView *listView = new BListView(frame, "preferred", B_SINGLE_SELECTION_LIST,
     62            B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP);
     63        listView->SetSelectionMessage(new BMessage(kMsgSelectLanguage));
     64
     65        BScrollView *scrollView = new BScrollView("scroller", listView,
     66            B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, 0, false, true, B_FANCY_BORDER);
     67        tab->AddChild(scrollView);
     68    }
     69
     70    tab = new BView(rect, "Country", B_FOLLOW_NONE, B_WILL_DRAW);
     71    tab->SetViewColor(tabView->ViewColor());
     72    tabView->AddTab(tab);
     73
     74    tab = new BView(rect, "Keyboard", B_FOLLOW_NONE, B_WILL_DRAW);
     75    tab->SetViewColor(tabView->ViewColor());
     76    tabView->AddTab(tab);
     77
     78    view->AddChild(tabView);
     79
     80    // check if the window is on screen
     81
     82    rect = BScreen().Frame();
     83    rect.right -= 20;
     84    rect.bottom -= 20;
     85
     86    BPoint position = Frame().LeftTop();
     87    if (!rect.Contains(position)) {
     88        // center window on screen as it doesn't fit on the saved position
     89        position.x = (rect.Width() - Bounds().Width()) / 2;
     90        position.y = (rect.Height() - Bounds().Height()) / 2;
     91    }
     92    MoveTo(position);
     93}
     94
     95
     96bool
     97LocaleWindow::QuitRequested()
     98{
     99    BMessage update(kMsgSettingsChanged);
     100    update.AddRect("window_frame", Frame());
     101    be_app_messenger.SendMessage(&update);
     102
     103    be_app_messenger.SendMessage(B_QUIT_REQUESTED);
     104    return true;
     105}
     106
     107
     108void
     109LocaleWindow::MessageReceived(BMessage *message)
     110{
     111    switch (message->what) {
     112        case kMsgDefaults:
     113            // reset default settings
     114            break;
     115
     116        case kMsgRevert:
     117            // revert to last settings
     118            break;
     119
     120        default:
     121            BWindow::MessageReceived(message);
     122            break;
     123    }
     124}
     125
  • src/preferences/locale/LocaleWindow.h

     
     1/*
     2 * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
     3 * Distributed under the terms of the MIT License.
     4 */
     5#ifndef LOCALE_WINDOW_H
     6#define LOCALE_WINDOW_H
     7
     8
     9#include <Window.h>
     10
     11class BButton;
     12
     13
     14class LocaleWindow : public BWindow {
     15    public:
     16        LocaleWindow(BRect rect);
     17
     18        virtual bool QuitRequested();
     19        virtual void MessageReceived(BMessage *message);
     20
     21    private:
     22        BButton*    fRevertButton;
     23};
     24
     25#endif  /* LOCALE_WINDOW_H */
  • src/preferences/Jamfile

     
    1212SubInclude HAIKU_TOP src preferences joysticks ;
    1313SubInclude HAIKU_TOP src preferences keyboard ;
    1414SubInclude HAIKU_TOP src preferences keymap ;
     15SubInclude HAIKU_TOP src preferences locale ;
    1516SubInclude HAIKU_TOP src preferences mail ;
    1617SubInclude HAIKU_TOP src preferences media ;
    1718SubInclude HAIKU_TOP src preferences menu ;
  • src/bin/locale/RegExp.h

     
     1/*
     2Open Tracker License
     3
     4Terms and Conditions
     5
     6Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
     7
     8Permission is hereby granted, free of charge, to any person obtaining a copy of
     9this software and associated documentation files (the "Software"), to deal in
     10the Software without restriction, including without limitation the rights to
     11use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
     12of the Software, and to permit persons to whom the Software is furnished to do
     13so, subject to the following conditions:
     14
     15The above copyright notice and this permission notice applies to all licensees
     16and shall be included in all copies or substantial portions of the Software.
     17
     18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
     20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     21BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
     23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     24
     25Except as contained in this notice, the name of Be Incorporated shall not be
     26used in advertising or otherwise to promote the sale, use or other dealings in
     27this Software without prior written authorization from Be Incorporated.
     28
     29Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
     30of Be Incorporated in the United States and other countries. Other brand product
     31names are registered trademarks or trademarks of their respective holders.
     32All rights reserved.
     33*/
     34
     35
     36// This code is based on regexp.c, v.1.3 by Henry Spencer:
     37
     38// @(#)regexp.c 1.3 of 18 April 87
     39//
     40//  Copyright (c) 1986 by University of Toronto.
     41//  Written by Henry Spencer.  Not derived from licensed software.
     42//
     43//  Permission is granted to anyone to use this software for any
     44//  purpose on any computer system, and to redistribute it freely,
     45//  subject to the following restrictions:
     46//
     47//  1. The author is not responsible for the consequences of use of
     48//      this software, no matter how awful, even if they arise
     49//      from defects in it.
     50//
     51//  2. The origin of this software must not be misrepresented, either
     52//      by explicit claim or by omission.
     53//
     54//  3. Altered versions must be plainly marked as such, and must not
     55//      be misrepresented as being the original software.
     56//
     57// Beware that some of this code is subtly aware of the way operator
     58// precedence is structured in regular expressions.  Serious changes in
     59// regular-expression syntax might require a total rethink.
     60//
     61
     62// ALTERED VERSION: Adapted to ANSI C and C++ for the OpenTracker
     63// project (www.opentracker.org), Jul 11, 2000.
     64
     65#ifndef _REG_EXP_H
     66#define _REG_EXP_H
     67
     68#include <String.h>
     69
     70namespace BPrivate {
     71
     72enum {
     73    REGEXP_UNMATCHED_PARENTHESIS = B_ERRORS_END,
     74    REGEXP_TOO_BIG,
     75    REGEXP_TOO_MANY_PARENTHESIS,
     76    REGEXP_JUNK_ON_END,
     77    REGEXP_STAR_PLUS_OPERAND_EMPTY,
     78    REGEXP_NESTED_STAR_QUESTION_PLUS,
     79    REGEXP_INVALID_BRACKET_RANGE,
     80    REGEXP_UNMATCHED_BRACKET,
     81    REGEXP_INTERNAL_ERROR,
     82    REGEXP_QUESTION_PLUS_STAR_FOLLOWS_NOTHING,
     83    REGEXP_TRAILING_BACKSLASH,
     84    REGEXP_CORRUPTED_PROGRAM,
     85    REGEXP_MEMORY_CORRUPTION,
     86    REGEXP_CORRUPTED_POINTERS,
     87    REGEXP_CORRUPTED_OPCODE
     88};
     89
     90const int32 kSubExpressionMax = 10;
     91
     92struct regexp {
     93    const char *startp[kSubExpressionMax];
     94    const char *endp[kSubExpressionMax];
     95    char regstart;      /* Internal use only. See RegExp.cpp for details. */
     96    char reganch;       /* Internal use only. */
     97    const char *regmust;/* Internal use only. */
     98    int regmlen;        /* Internal use only. */
     99    char program[1];    /* Unwarranted chumminess with compiler. */
     100};
     101
     102class RegExp {
     103
     104public:
     105    RegExp();
     106    RegExp(const char *);
     107    RegExp(const BString &);
     108    ~RegExp();
     109   
     110    status_t InitCheck() const;
     111   
     112    status_t SetTo(const char*);
     113    status_t SetTo(const BString &);
     114   
     115    bool Matches(const char *string) const;
     116    bool Matches(const BString &) const;
     117
     118    int32 RunMatcher(regexp *, const char *) const;
     119    regexp *Compile(const char *);
     120    regexp *Expression() const;
     121    const char *ErrorString() const;
     122
     123#ifdef DEBUG
     124    void Dump();
     125#endif
     126
     127private:
     128
     129    void SetError(status_t error) const;
     130
     131    // Working functions for Compile():
     132    char *Reg(int32, int32 *);
     133    char *Branch(int32 *);
     134    char *Piece(int32 *);
     135    char *Atom(int32 *);
     136    char *Node(char);
     137    char *Next(char *);
     138    const char *Next(const char *) const;
     139    void Char(char);
     140    void Insert(char, char *);
     141    void Tail(char *, char *);
     142    void OpTail(char *, char *);
     143
     144    // Working functions for RunMatcher():
     145    int32 Try(regexp *, const char *) const;
     146    int32 Match(const char *) const;
     147    int32 Repeat(const char *) const;
     148
     149    // Utility functions:
     150#ifdef DEBUG
     151    char *Prop(const char *) const;
     152    void RegExpError(const char *) const;
     153#endif
     154    inline int32 UCharAt(const char *p) const;
     155    inline char *Operand(char* p) const;
     156    inline const char *Operand(const char* p) const;
     157    inline bool IsMult(char c) const;
     158
     159// --------- Variables -------------
     160
     161    mutable status_t fError;
     162    regexp *fRegExp;
     163
     164    // Work variables for Compile().
     165
     166    const char *fInputScanPointer;
     167    int32 fParenthesisCount;       
     168    char fDummy;
     169    char *fCodeEmitPointer;     // &fDummy = don't.
     170    long fCodeSize;     
     171
     172    // Work variables for RunMatcher().
     173
     174    mutable const char *fStringInputPointer;
     175    mutable const char *fRegBol;    // Beginning of input, for ^ check.
     176    mutable const char **fStartPArrayPointer;
     177    mutable const char **fEndPArrayPointer;
     178};
     179
     180} // namespace BPrivate
     181
     182using namespace BPrivate;
     183
     184#endif
  • src/bin/locale/dumpcatalog.cpp

     
     1/*
     2** Copyright 2003, Oliver Tappe, zooey@hirschkaefer.de. All rights reserved.
     3** Distributed under the terms of the OpenBeOS License.
     4*/
     5
     6#include <cstdio>
     7#include <cstdlib>
     8
     9#include <Catalog.h>
     10#include <DefaultCatalog.h>
     11#include <File.h>
     12#include <String.h>
     13
     14void
     15usage()
     16{
     17    fprintf(stderr, "usage: dumpcatalog <catalogFiles>\n");
     18    exit(-1);
     19}
     20
     21
     22int
     23main(int argc, char **argv)
     24{
     25    const char *inputFile = NULL;
     26    status_t res;
     27    if (!argv[1] || !strcmp(argv[1], "--help")) {
     28        usage();
     29    } else {
     30        inputFile = argv[1];
     31    }
     32    if (!inputFile || !strlen(inputFile))
     33        usage();
     34   
     35    EditableCatalog inputCatalog("Default", "dummy", "dummy");
     36    if ((res = inputCatalog.InitCheck()) != B_OK) {
     37        fprintf(stderr, "couldn't construct catalog %s - error: %s\n",
     38            inputFile, strerror(res));
     39        exit(-1);
     40    }
     41    if ((res = inputCatalog.ReadFromFile(inputFile)) != B_OK) {
     42        fprintf(stderr, "couldn't load input-catalog %s - error: %s\n",
     43            inputFile, strerror(res));
     44        exit(-1);
     45    }
     46    DefaultCatalog* inputCatImpl
     47        = dynamic_cast<DefaultCatalog*>(inputCatalog.CatalogAddOn());
     48    if (!inputCatImpl) {
     49        fprintf(stderr, "couldn't access impl of input-catalog %s\n",
     50            inputFile);
     51        exit(-1);
     52    }
     53    // now walk over all entries in input-catalog and dump them to
     54    // stdout
     55    DefaultCatalog::CatWalker walker;
     56    if ((res = inputCatImpl->GetWalker(&walker)) != B_OK) {
     57        fprintf(stderr, "couldn't get walker for input-catalog %s - error: %s\n",
     58            inputFile, strerror(res));
     59        exit(-1);
     60    }
     61    BString str, ctx, cmt;
     62    while(!walker.AtEnd()) {
     63        const CatKey &key(walker.GetKey());
     64        key.GetStringParts(&str, &ctx, &cmt);
     65        printf("Hash:\t\t%ld\nKey:\t\t<%s:%s:%s>\nTranslation:\t%s\n-----\n",
     66            key.fHashVal, str.String(), ctx.String(), cmt.String(),
     67            walker.GetValue());
     68        walker.Next();
     69    }
     70    int32 count = inputCatalog.CountItems();
     71    if (count)
     72        fprintf(stderr, "%ld entr%s dumped\n",  count, (count==1 ? "y": "ies"));
     73    else
     74        fprintf(stderr, "no entries found\n");
     75    return res;
     76}
  • src/bin/locale/linkcatkeys.cpp

    Impossible d'afficher : fichier considéré comme binaire.
    svn:mime-type = application/octet-stream
    
    Modification de propriétés sur src/bin/locale/collectcatkeys.rsrc
    ___________________________________________________________________
    Ajouté : svn:mime-type
       + application/octet-stream
    
     
     1/*
     2** Copyright 2003, Oliver Tappe, zooey@hirschkaefer.de. All rights reserved.
     3** Distributed under the terms of the OpenBeOS License.
     4*/
     5
     6#include <cstdio>
     7#include <cstdlib>
     8#include <vector>
     9
     10#include <Catalog.h>
     11#include <DefaultCatalog.h>
     12#include <Entry.h>
     13#include <File.h>
     14#include <String.h>
     15
     16void
     17usage()
     18{
     19    fprintf(stderr,
     20        "usage: linkcatkeys [-v] [-t(a|f|r)] [-o <outfile>] [-l <catalogLang>]\n"
     21        "                   -s <catalogSig> <catalogFiles>\n"
     22        "options:\n"
     23        "  -l <catalogLang>\tlanguage of the target-catalog (default is English)\n"
     24        "  -o <outfile>\t\texplicitly specifies the name of the output-file\n"
     25        "  -s <catalogSig>\tsignature of the target-catalog\n"
     26        "  -t(a|f|r)\t\tspecifies target of resulting catalog (-tf is default)\n"
     27        "           \t\ta => write catalog as an attribute (to output-file)\n"
     28        "           \t\tf => write catalog into the output-file\n"
     29        "           \t\tr => write catalog as a resource (to output-file)\n"
     30        "  -v\t\t\tbe verbose, show summary\n");
     31    exit(-1);
     32}
     33
     34
     35int
     36main(int argc, char **argv)
     37{
     38    bool showSummary = false;
     39    bool showWarnings = false;
     40    vector<const char *> inputFiles;
     41    BString outputFile("default.catalog");
     42    enum TargetType {
     43        TARGET_ATTRIBUTE,
     44        TARGET_FILE,
     45        TARGET_RESOURCE
     46    };
     47    TargetType outputTarget = TARGET_FILE;
     48    const char *catalogSig = NULL;
     49    const char *catalogLang = "English";
     50    status_t res;
     51    while ((++argv)[0]) {
     52        if (argv[0][0] == '-' && argv[0][1] != '-') {
     53            char *arg = argv[0] + 1;
     54            char c;
     55            while ((c = *arg++) != '\0') {
     56                if (c == 's')
     57                    catalogSig = (++argv)[0];
     58                else if (c == 'v')
     59                    showSummary = true;
     60                else if (c == 'w')
     61                    showWarnings = true;
     62                else if (c == 'o') {
     63                    outputFile = (++argv)[0];
     64                    break;
     65                }
     66                else if (c == 't') {
     67                    switch(*arg) {
     68                        case 'a': outputTarget = TARGET_ATTRIBUTE; break;
     69                        case 'f': outputTarget = TARGET_FILE; break;
     70                        case 'r': outputTarget = TARGET_RESOURCE; break;
     71                        default: usage();
     72                    }
     73                }
     74            }
     75        } else if (!strcmp(argv[0], "--help")) {
     76            usage();
     77        } else {
     78            inputFiles.push_back(argv[0]);
     79        }
     80    }
     81    if (inputFiles.empty() || !catalogSig || !outputFile.Length())
     82        usage();
     83   
     84    EditableCatalog targetCatalog("Default", catalogSig, catalogLang);
     85    if ((res = targetCatalog.InitCheck()) != B_OK) {
     86        fprintf(stderr, "couldn't construct target-catalog %s - error: %s\n",
     87            outputFile.String(), strerror(res));
     88        exit(-1);
     89    }
     90    DefaultCatalog* targetCatImpl
     91        = dynamic_cast<DefaultCatalog*>(targetCatalog.CatalogAddOn());
     92    if (!targetCatImpl) {
     93        fprintf(stderr, "couldn't access impl of target-catalog %s\n",
     94            outputFile.String());
     95        exit(-1);
     96    }
     97
     98    uint32 count = inputFiles.size();
     99    for( uint32 i=0; i<count; ++i) {
     100        EditableCatalog inputCatalog("Default", catalogSig, "native");
     101        if ((res = inputCatalog.ReadFromFile(inputFiles[i])) != B_OK) {
     102            fprintf(stderr, "couldn't load target-catalog %s - error: %s\n",
     103                inputFiles[i], strerror(res));
     104            exit(-1);
     105        }
     106        DefaultCatalog* inputCatImpl
     107            = dynamic_cast<DefaultCatalog*>(inputCatalog.CatalogAddOn());
     108        if (!inputCatImpl) {
     109            fprintf(stderr, "couldn't access impl of input-catalog %s\n",
     110                inputFiles[i]);
     111            exit(-1);
     112        }
     113        // now walk over all entries in input-catalog and add them to
     114        // target catalog, unless they already exist there.
     115        // (This could be improved by simply inserting the hashmaps,
     116        // but this should be fast enough).
     117        DefaultCatalog::CatWalker walker;
     118        if ((res = inputCatImpl->GetWalker(&walker)) != B_OK) {
     119            fprintf(stderr, "couldn't get walker for input-catalog %s - error: %s\n",
     120                inputFiles[i], strerror(res));
     121            exit(-1);
     122        }
     123        while(!walker.AtEnd()) {
     124            const CatKey &key(walker.GetKey());
     125            if (!targetCatImpl->GetString(key))
     126                targetCatImpl->SetString(key, walker.GetValue());
     127            walker.Next();
     128        }
     129    }
     130
     131    switch(outputTarget) {
     132        case TARGET_ATTRIBUTE: {
     133            BEntry entry(outputFile.String());
     134            entry_ref eref;
     135            entry.GetRef(&eref);
     136            res = targetCatalog.WriteToAttribute(&eref);
     137            if (res != B_OK) {
     138                fprintf(stderr, "couldn't write target-attribute to %s - error: %s\n",
     139                    outputFile.String(), strerror(res));
     140                exit(-1);
     141            }
     142            break;
     143        }
     144        case TARGET_RESOURCE: {
     145            BEntry entry(outputFile.String());
     146            entry_ref eref;
     147            entry.GetRef(&eref);
     148            res = targetCatalog.WriteToResource(&eref);
     149            if (res != B_OK) {
     150                fprintf(stderr, "couldn't write target-resource to %s - error: %s\n",
     151                    outputFile.String(), strerror(res));
     152                exit(-1);
     153            }
     154        }
     155        default: {
     156            res = targetCatalog.WriteToFile(outputFile.String());
     157            if (res != B_OK) {
     158                fprintf(stderr, "couldn't write target-catalog to %s - error: %s\n",
     159                    outputFile.String(), strerror(res));
     160                exit(-1);
     161            }
     162        }
     163    }
     164    if (showSummary) {
     165        int32 count = targetCatalog.CountItems();
     166        if (count)
     167            fprintf(stderr, "%ld key%s found and written to %s\n",
     168                count, (count==1 ? "": "s"), outputFile.String());
     169        else
     170            fprintf(stderr, "no keys found\n");
     171    }
     172
     173    return res;
     174}
  • src/bin/locale/Jamfile

     
     1SubDir HAIKU_TOP src bin locale ;
     2
     3UseHeaders [ FDirName $(HAIKU_TOP) headers os locale ] : true ;
     4
     5AddResources collectcatkeys : collectcatkeys.rsrc ;
     6Application collectcatkeys : collectcatkeys.cpp RegExp.cpp : be liblocale.so ;
     7
     8AddResources linkcatkeys : linkcatkeys.rsrc ;
     9Application linkcatkeys : linkcatkeys.cpp : be liblocale.so ;
     10
     11AddResources dumpcatalog ;
     12Application dumpcatalog : dumpcatalog.cpp : be liblocale.so ;
  • src/bin/locale/collectcatkeys.cpp

    Impossible d'afficher : fichier considéré comme binaire.
    svn:mime-type = application/octet-stream
    
    Modification de propriétés sur src/bin/locale/dumpcatalog.rsrc
    ___________________________________________________________________
    Ajouté : svn:mime-type
       + application/octet-stream
    
    Impossible d'afficher : fichier considéré comme binaire.
    svn:mime-type = application/octet-stream
    
    Modification de propriétés sur src/bin/locale/linkcatkeys.rsrc
    ___________________________________________________________________
    Ajouté : svn:mime-type
       + application/octet-stream
    
     
     1/*
     2** Copyright 2003, Oliver Tappe, zooey@hirschkaefer.de. All rights reserved.
     3** Distributed under the terms of the OpenBeOS License.
     4*/
     5
     6#include <cctype>
     7#include <cerrno>
     8#include <cstdio>
     9#include <cstdlib>
     10
     11#include <Catalog.h>
     12using namespace BPrivate;
     13#include <Entry.h>
     14#include <File.h>
     15#include "RegExp.h"
     16#include <String.h>
     17
     18bool showKeys = false;
     19bool showSummary = false;
     20bool showWarnings = false;
     21const char *inputFile = NULL;
     22BString outputFile;
     23const char *catalogSig = NULL;
     24const char *catalogLang = "English";
     25BString rxString("be_catalog\\s*->\\s*GetString\\s*");
     26
     27
     28BString str, ctx, cmt;
     29bool haveID;
     30int32 id;
     31
     32
     33EditableCatalog *catalog = NULL;
     34
     35
     36void
     37usage()
     38{
     39    fprintf(stderr,
     40        "usage: collectcatkeys [-pvw] [-r <regex>] [-o <outfile>] [-l <catalogLanguage>]\n"
     41        "                      -s <catalogSig> <prepCppFile>\n"
     42        "options:\n"
     43        "  -l <catalogLang>\tlanguage of the target-catalog (default is English)\n"
     44        "  -o <outfile>\t\texplicitly specifies the name of the output-file\n"
     45        "  -p\t\t\tprint keys as they are found\n"
     46        "  -r <regex>\t\tchanges the regex used by the key-scanner to the one given,\n"
     47        "      \t\t\tthe default is:   be_catalog\\s*->\\s*GetString\\s*\n"
     48        "  -s <catalogSig>\tsignature of the target-catalog\n"
     49        "  -v\t\t\tbe verbose, show summary\n"
     50        "  -w\t\t\tshow warnings about catalog-accesses that couldn't be resolved completely\n");
     51    exit(-1);
     52}
     53
     54
     55bool
     56fetchStr(const char *&in, BString &str, bool lookForID)
     57{
     58    int parLevel = 0;
     59    while(isspace(*in) || *in == '(') {
     60        if (*in == '(')
     61            parLevel++;
     62        in++;
     63    }
     64    if (*in == '"') {
     65        in++;
     66        bool quoted = false;
     67        while (*in != '"' || quoted) {
     68            if (quoted) {
     69                if (*in == 'n')
     70                    str.Append("\n",1);
     71                else if (*in == 't')
     72                    str.Append("\t",1);
     73                else if (*in == '"')
     74                    str.Append("\"",1);
     75                else
     76                    // dump quote from unknown quoting-sequence:
     77                    str.Append(in,1);
     78                quoted = false;
     79            } else {
     80                quoted = (*in == '\\');
     81                if (!quoted)
     82                    str.Append(in,1);
     83            }
     84            in++;
     85        }
     86        in++;
     87    } else if (!memcmp(in, "__null", 6)) {
     88        // NULL is preprocessed into __null, which we parse as ""
     89        in += 6;
     90    } else if (lookForID && (isdigit(*in) || *in == '-' || *in == '+')) {
     91        // try to parse an ID (a long):
     92        errno = 0;
     93        char *next;
     94        id = strtol(in, &next, 10);
     95        if (id != 0 || errno == 0) {
     96            haveID = true;
     97            in = next;
     98        }
     99    } else
     100        return false;
     101    while(isspace(*in) || *in == ')') {
     102        if (*in == ')') {
     103            if (!parLevel)
     104                return true;
     105            parLevel--;
     106        }
     107        in++;
     108    }
     109    return true;
     110}
     111
     112
     113bool
     114fetchKey(const char *&in)
     115{
     116    str = ctx = cmt = "";
     117    haveID = false;
     118    // fetch native string or id:
     119    if (!fetchStr(in, str, true))
     120        return false;
     121    if (*in == ',') {
     122        in++;
     123        // fetch context:
     124        if (!fetchStr(in, ctx, false))
     125            return false;
     126        if (*in == ',') {
     127            in++;
     128            // fetch comment:
     129            if (!fetchStr(in, cmt, false))
     130                return false;
     131        }
     132    }
     133    return true;
     134}
     135
     136
     137void
     138collectAllCatalogKeys(BString& inputStr)
     139{
     140    RegExp rx;
     141    struct regexp *rxprg = rx.Compile(rxString.String());
     142    if (rx.InitCheck() != B_OK) {
     143        fprintf(stderr, "regex-compilation error %s\n", rx.ErrorString());
     144        return;
     145    }
     146    status_t res;
     147    const char *in = inputStr.String();
     148    while(rx.RunMatcher(rxprg, in)) {
     149        const char *start = rxprg->startp[0];
     150        in = rxprg->endp[0];
     151        if (fetchKey(in)) {
     152            if (haveID) {
     153                if (showKeys)
     154                    printf("CatKey(%ld)\n", id);
     155                res = catalog->SetString(id, "");
     156                if (res != B_OK) {
     157                    fprintf(stderr, "couldn't add key %ld - error: %s\n",
     158                        id, strerror(res));
     159                    exit(-1);
     160                }
     161            } else {
     162                if (showKeys)
     163                    printf("CatKey(\"%s\", \"%s\", \"%s\")\n", str.String(),
     164                        ctx.String(), cmt.String());
     165                res = catalog->SetString(str.String(), str.String(), ctx.String(), cmt.String());
     166                if (res != B_OK) {
     167                    fprintf(stderr, "couldn't add key %s,%s,%s - error: %s\n",
     168                        str.String(), ctx.String(), cmt.String(), strerror(res));
     169                    exit(-1);
     170                }
     171            }
     172        } else if (showWarnings) {
     173            const char *end = strchr(in, ';');
     174            BString match;
     175            if (end)
     176                match.SetTo(start, end-start+1);
     177            else
     178                // can't determine end of statement, we output next 40 characters
     179                match.SetTo(start, 40);
     180            fprintf(stderr, "Warning: couldn't resolve catalog-access:\n\t%s\n",
     181                match.String());
     182        }
     183    }
     184}
     185
     186
     187int
     188main(int argc, char **argv)
     189{
     190    while ((++argv)[0]) {
     191        if (argv[0][0] == '-' && argv[0][1] != '-') {
     192            char *arg = argv[0] + 1;
     193            char c;
     194            while ((c = *arg++) != '\0') {
     195                if (c == 'p')
     196                    showKeys = true;
     197                else if (c == 'l')
     198                    catalogLang = (++argv)[0];
     199                else if (c == 's')
     200                    catalogSig = (++argv)[0];
     201                else if (c == 'v')
     202                    showSummary = true;
     203                else if (c == 'w')
     204                    showWarnings = true;
     205                else if (c == 'o') {
     206                    outputFile = (++argv)[0];
     207                    break;
     208                }
     209                else if (c == 'r') {
     210                    rxString = (++argv)[0];
     211                    break;
     212                }
     213            }
     214        } else if (!strcmp(argv[0], "--help")) {
     215            usage();
     216        } else {
     217            if (!inputFile)
     218                inputFile = argv[0];
     219            else
     220                usage();
     221        }
     222    }
     223    if (!outputFile.Length() && inputFile) {
     224        // generate default output-file from input-file by replacing
     225        // the extension with '.catkeys':
     226        outputFile = inputFile;
     227        int32 dot = outputFile.FindLast('.');
     228        if (dot >= B_OK)
     229            outputFile.Truncate(dot);
     230        outputFile << ".catkeys";
     231    }
     232    if (!inputFile || !catalogSig || !outputFile.Length() || !catalogLang)
     233        usage();
     234   
     235    BFile inFile;
     236    status_t res = inFile.SetTo(inputFile, B_READ_ONLY);
     237    if (res != B_OK) {
     238        fprintf(stderr, "unable to open inputfile %s - error: %s\n", inputFile,
     239            strerror(res));
     240        exit(-1);
     241    }
     242    off_t sz;
     243    inFile.GetSize(&sz);
     244    if (sz > 0) {
     245        BString inputStr;
     246        char *buf = inputStr.LockBuffer(sz);
     247        off_t rsz = inFile.Read(buf, sz);
     248        if (rsz < sz) {
     249            fprintf(stderr, "couldn't read %Ld bytes from %s (got only %Ld)\n",
     250                sz, inputFile, rsz);
     251            exit(-1);
     252        }
     253        inputStr.UnlockBuffer(rsz);
     254        catalog = new EditableCatalog("Default", catalogSig, catalogLang);
     255        collectAllCatalogKeys(inputStr);
     256        res = catalog->WriteToFile(outputFile.String());
     257        if (res != B_OK) {
     258            fprintf(stderr, "couldn't write catalog to %s - error: %s\n",
     259                outputFile.String(), strerror(res));
     260            exit(-1);
     261        }
     262        if (showSummary) {
     263            int32 count = catalog->CountItems();
     264            if (count)
     265                fprintf(stderr, "%ld key%s found and written to %s\n",
     266                    count, (count==1 ? "": "s"), outputFile.String());
     267            else
     268                fprintf(stderr, "no keys found\n");
     269        }
     270        delete catalog;
     271    }
     272
     273//  BEntry inEntry(inputFile);
     274//  inEntry.Remove();
     275   
     276    return res;
     277}
  • src/bin/locale/RegExp.cpp

     
     1/*
     2Open Tracker License
     3
     4Terms and Conditions
     5
     6Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
     7
     8Permission is hereby granted, free of charge, to any person obtaining a copy of
     9this software and associated documentation files (the "Software"), to deal in
     10the Software without restriction, including without limitation the rights to
     11use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
     12of the Software, and to permit persons to whom the Software is furnished to do
     13so, subject to the following conditions:
     14
     15The above copyright notice and this permission notice applies to all licensees
     16and shall be included in all copies or substantial portions of the Software.
     17
     18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
     20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     21BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
     23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     24
     25Except as contained in this notice, the name of Be Incorporated shall not be
     26used in advertising or otherwise to promote the sale, use or other dealings in
     27this Software without prior written authorization from Be Incorporated.
     28
     29Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
     30of Be Incorporated in the United States and other countries. Other brand product
     31names are registered trademarks or trademarks of their respective holders.
     32All rights reserved.
     33*/
     34
     35// This code is based on regexp.c, v.1.3 by Henry Spencer:
     36
     37// @(#)regexp.c 1.3 of 18 April 87
     38//
     39//  Copyright (c) 1986 by University of Toronto.
     40//  Written by Henry Spencer.  Not derived from licensed software.
     41//
     42//  Permission is granted to anyone to use this software for any
     43//  purpose on any computer system, and to redistribute it freely,
     44//  subject to the following restrictions:
     45//
     46//  1. The author is not responsible for the consequences of use of
     47//      this software, no matter how awful, even if they arise
     48//      from defects in it.
     49//
     50//  2. The origin of this software must not be misrepresented, either
     51//      by explicit claim or by omission.
     52//
     53//  3. Altered versions must be plainly marked as such, and must not
     54//      be misrepresented as being the original software.
     55//
     56// Beware that some of this code is subtly aware of the way operator
     57// precedence is structured in regular expressions.  Serious changes in
     58// regular-expression syntax might require a total rethink.
     59//
     60
     61// ALTERED VERSION: Adapted to ANSI C and C++ for the OpenTracker
     62// project (www.opentracker.org), Jul 11, 2000.
     63
     64#include <malloc.h>
     65#include <stdio.h>
     66#include <string.h>
     67
     68#include <Errors.h>
     69
     70#include "RegExp.h"
     71
     72// The first byte of the regexp internal "program" is actually this magic
     73// number; the start node begins in the second byte.
     74
     75const uint8 kRegExpMagic = 0234;
     76
     77// The "internal use only" fields in RegExp.h are present to pass info from
     78// compile to execute that permits the execute phase to run lots faster on
     79// simple cases.  They are:
     80//
     81// regstart char that must begin a match; '\0' if none obvious
     82// reganch  is the match anchored (at beginning-of-line only)?
     83// regmust  string (pointer into program) that match must include, or NULL
     84// regmlen  length of regmust string
     85//
     86// Regstart and reganch permit very fast decisions on suitable starting points
     87// for a match, cutting down the work a lot.  Regmust permits fast rejection
     88// of lines that cannot possibly match.  The regmust tests are costly enough
     89// that Compile() supplies a regmust only if the r.e. contains something
     90// potentially expensive (at present, the only such thing detected is * or +
     91// at the start of the r.e., which can involve a lot of backup).  Regmlen is
     92// supplied because the test in RunMatcher() needs it and Compile() is computing
     93// it anyway.
     94//
     95//
     96//
     97// Structure for regexp "program".  This is essentially a linear encoding
     98// of a nondeterministic finite-state machine (aka syntax charts or
     99// "railroad normal form" in parsing technology).  Each node is an opcode
     100// plus a "next" pointer, possibly plus an operand.  "Next" pointers of
     101// all nodes except kRegExpBranch implement concatenation; a "next" pointer with
     102// a kRegExpBranch on both ends of it is connecting two alternatives.  (Here we
     103// have one of the subtle syntax dependencies:  an individual kRegExpBranch (as
     104// opposed to a collection of them) is never concatenated with anything
     105// because of operator precedence.)  The operand of some types of node is
     106// a literal string; for others, it is a node leading into a sub-FSM.  In
     107// particular, the operand of a kRegExpBranch node is the first node of the branch.
     108// (NB this is *not* a tree structure:  the tail of the branch connects
     109// to the thing following the set of kRegExpBranches.)  The opcodes are:
     110//
     111
     112// definition   number  opnd?   meaning
     113enum {
     114    kRegExpEnd = 0,     // no   End of program.
     115    kRegExpBol = 1,     // no   Match "" at beginning of line.
     116    kRegExpEol = 2,     // no   Match "" at end of line.
     117    kRegExpAny = 3,     // no   Match any one character.
     118    kRegExpAnyOf = 4,   // str  Match any character in this string.
     119    kRegExpAnyBut = 5,  // str  Match any character not in this string.
     120    kRegExpBranch = 6,  // node Match this alternative, or the next...
     121    kRegExpBack = 7,    // no   Match "", "next" ptr points backward.
     122    kRegExpExactly = 8, // str  Match this string.
     123    kRegExpNothing = 9, // no   Match empty string.
     124    kRegExpStar = 10,   // node Match this (simple) thing 0 or more times.
     125    kRegExpPlus = 11,   // node Match this (simple) thing 1 or more times.
     126    kRegExpOpen = 20,   // no   Mark this point in input as start of #n.
     127                            //  kRegExpOpen + 1 is number 1, etc.
     128    kRegExpClose = 30   // no   Analogous to kRegExpOpen.
     129};
     130
     131//
     132// Opcode notes:
     133//
     134// kRegExpBranch    The set of branches constituting a single choice are hooked
     135//      together with their "next" pointers, since precedence prevents
     136//      anything being concatenated to any individual branch.  The
     137//      "next" pointer of the last kRegExpBranch in a choice points to the
     138//      thing following the whole choice.  This is also where the
     139//      final "next" pointer of each individual branch points; each
     140//      branch starts with the operand node of a kRegExpBranch node.
     141//
     142// kRegExpBack      Normal "next" pointers all implicitly point forward; kRegExpBack
     143//      exists to make loop structures possible.
     144//
     145// kRegExpStar,kRegExpPlus  '?', and complex '*' and '+', are implemented as circular
     146//      kRegExpBranch structures using kRegExpBack.  Simple cases (one character
     147//      per match) are implemented with kRegExpStar and kRegExpPlus for speed
     148//      and to minimize recursive plunges.
     149//
     150// kRegExpOpen,kRegExpClose ...are numbered at compile time.
     151//
     152//
     153//
     154// A node is one char of opcode followed by two chars of "next" pointer.
     155// "Next" pointers are stored as two 8-bit pieces, high order first.  The
     156// value is a positive offset from the opcode of the node containing it.
     157// An operand, if any, simply follows the node.  (Note that much of the
     158// code generation knows about this implicit relationship.)
     159//
     160// Using two bytes for the "next" pointer is vast overkill for most things,
     161// but allows patterns to get big without disasters.
     162//
     163
     164const char *kMeta = "^$.[()|?+*\\";
     165const int32 kMaxSize = 32767L;      // Probably could be 65535L.
     166
     167// Flags to be passed up and down:
     168enum {
     169    kHasWidth = 01, // Known never to match null string.
     170    kSimple = 02,   // Simple enough to be kRegExpStar/kRegExpPlus operand.
     171    kSPStart = 04,  // Starts with * or +.
     172    kWorst = 0  // Worst case.
     173};
     174
     175const char *kRegExpErrorStringArray[] = {
     176    "Unmatched parenthesis.",
     177    "Expression too long.",
     178    "Too many parenthesis.",
     179    "Junk on end.",
     180    "*+? operand may be empty.",
     181    "Nested *?+.",
     182    "Invalid bracket range.",
     183    "Unmatched brackets.",
     184    "Internal error.",
     185    "?+* follows nothing.",
     186    "Trailing \\.",
     187    "Corrupted expression.",
     188    "Memory corruption.",
     189    "Corrupted pointers.",
     190    "Corrupted opcode."
     191};
     192
     193#ifdef DEBUG
     194int32 regnarrate = 0;
     195#endif
     196
     197RegExp::RegExp()
     198    :   fError(B_OK),
     199        fRegExp(NULL)
     200{
     201}
     202
     203RegExp::RegExp(const char *pattern)
     204    :   fError(B_OK),
     205        fRegExp(NULL)
     206{
     207    fRegExp = Compile(pattern);
     208}
     209
     210RegExp::RegExp(const BString &pattern)
     211    :   fError(B_OK),
     212        fRegExp(NULL)
     213{
     214    fRegExp = Compile(pattern.String());
     215}
     216
     217RegExp::~RegExp()
     218{
     219    free(fRegExp);
     220}
     221
     222
     223
     224status_t
     225RegExp::InitCheck() const
     226{
     227    return fError;
     228}
     229
     230status_t
     231RegExp::SetTo(const char *pattern)
     232{
     233    fError = B_OK;
     234    free(fRegExp);
     235    fRegExp = Compile(pattern);
     236    return fError;
     237}
     238
     239status_t
     240RegExp::SetTo(const BString &pattern)
     241{
     242    fError = B_OK;
     243    free(fRegExp);
     244    fRegExp = Compile(pattern.String());
     245    return fError;
     246}
     247
     248bool
     249RegExp::Matches(const char *string) const
     250{
     251    if (!fRegExp || !string)
     252        return false;
     253       
     254    return RunMatcher(fRegExp, string) == 1;
     255}
     256
     257bool
     258RegExp::Matches(const BString &string) const
     259{
     260    if (!fRegExp)
     261        return false;
     262
     263    return RunMatcher(fRegExp, string.String()) == 1;
     264}
     265
     266
     267//
     268// - Compile - compile a regular expression into internal code
     269//
     270// We can't allocate space until we know how big the compiled form will be,
     271// but we can't compile it (and thus know how big it is) until we've got a
     272// place to put the code.  So we cheat:  we compile it twice, once with code
     273// generation turned off and size counting turned on, and once "for real".
     274// This also means that we don't allocate space until we are sure that the
     275// thing really will compile successfully, and we never have to move the
     276// code and thus invalidate pointers into it.  (Note that it has to be in
     277// one piece because free() must be able to free it all.)
     278//
     279// Beware that the optimization-preparation code in here knows about some
     280// of the structure of the compiled regexp.
     281
     282regexp *
     283RegExp::Compile(const char *exp)
     284{
     285    regexp *r;
     286    const char *scan;
     287    const char *longest;
     288    int32 len;
     289    int32 flags;
     290
     291    if (exp == NULL) {
     292        SetError(B_BAD_VALUE);
     293        return NULL;
     294    }
     295
     296    // First pass: determine size, legality.
     297    fInputScanPointer = exp;
     298    fParenthesisCount = 1;
     299    fCodeSize = 0L;
     300    fCodeEmitPointer = &fDummy;
     301    Char(kRegExpMagic);
     302    if (Reg(0, &flags) == NULL)
     303        return NULL;
     304
     305    // Small enough for pointer-storage convention?
     306    if (fCodeSize >= kMaxSize) {
     307        SetError(REGEXP_TOO_BIG);
     308        return NULL;
     309    }
     310
     311    // Allocate space.
     312    r = (regexp *)malloc(sizeof(regexp) + fCodeSize);
     313
     314    if (!r) {
     315        SetError(B_NO_MEMORY);
     316        return NULL;
     317    }
     318
     319    // Second pass: emit code.
     320    fInputScanPointer = exp;
     321    fParenthesisCount = 1;
     322    fCodeEmitPointer = r->program;
     323    Char(kRegExpMagic);
     324    if (Reg(0, &flags) == NULL) {
     325        free(r);
     326        return NULL;
     327    }
     328   
     329    // Dig out information for optimizations.
     330    r->regstart = '\0'; // Worst-case defaults.
     331    r->reganch = 0;
     332    r->regmust = NULL;
     333    r->regmlen = 0;
     334    scan = r->program + 1;          // First kRegExpBranch.
     335    if (*Next((char *)scan) == kRegExpEnd) {        // Only one top-level choice.
     336        scan = Operand(scan);
     337
     338        // Starting-point info.
     339        if (*scan == kRegExpExactly)
     340            r->regstart = *Operand(scan);
     341        else if (*scan == kRegExpBol)
     342            r->reganch++;
     343
     344        //
     345        // If there's something expensive in the r.e., find the
     346        // longest literal string that must appear and make it the
     347        // regmust.  Resolve ties in favor of later strings, since
     348        // the regstart check works with the beginning of the r.e.
     349        // and avoiding duplication strengthens checking.  Not a
     350        // strong reason, but sufficient in the absence of others.
     351        //
     352        if (flags&kSPStart) {
     353            longest = NULL;
     354            len = 0;
     355            for (; scan != NULL; scan = Next((char *)scan))
     356                if (*scan == kRegExpExactly && (int32)strlen(Operand(scan)) >= len) {
     357                    longest = Operand(scan);
     358                    len = (int32)strlen(Operand(scan));
     359                }
     360            r->regmust = longest;
     361            r->regmlen = len;
     362        }
     363    }
     364
     365    return r;
     366}
     367
     368regexp *
     369RegExp::Expression() const
     370{
     371    return fRegExp;
     372}
     373
     374const char *
     375RegExp::ErrorString() const
     376{
     377    if (fError >= REGEXP_UNMATCHED_PARENTHESIS
     378        && fError <= REGEXP_CORRUPTED_OPCODE)
     379        return kRegExpErrorStringArray[fError - B_ERRORS_END];
     380
     381    return strerror(fError);
     382}
     383
     384
     385void
     386RegExp::SetError(status_t error) const
     387{
     388    fError = error;
     389}
     390
     391
     392//
     393// - Reg - regular expression, i.e. main body or parenthesized thing
     394//
     395// Caller must absorb opening parenthesis.
     396//
     397// Combining parenthesis handling with the base level of regular expression
     398// is a trifle forced, but the need to tie the tails of the branches to what
     399// follows makes it hard to avoid.
     400//
     401char *
     402RegExp::Reg(int32 paren, int32 *flagp)
     403{
     404    char *ret;
     405    char *br;
     406    char *ender;
     407    int32 parno = 0;
     408    int32 flags;
     409
     410    *flagp = kHasWidth; // Tentatively.
     411
     412    // Make an kRegExpOpen node, if parenthesized.
     413    if (paren) {
     414        if (fParenthesisCount >= kSubExpressionMax) {
     415            SetError(REGEXP_TOO_MANY_PARENTHESIS);
     416            return NULL;
     417        }
     418        parno = fParenthesisCount;
     419        fParenthesisCount++;
     420        ret = Node((char)(kRegExpOpen + parno));
     421    } else
     422        ret = NULL;
     423
     424    // Pick up the branches, linking them together.
     425    br = Branch(&flags);
     426    if (br == NULL)
     427        return NULL;
     428    if (ret != NULL)
     429        Tail(ret, br);  // kRegExpOpen -> first
     430    else
     431        ret = br;
     432    if (!(flags & kHasWidth))
     433        *flagp &= ~kHasWidth;
     434    *flagp |= flags&kSPStart;
     435    while (*fInputScanPointer == '|') {
     436        fInputScanPointer++;
     437        br = Branch(&flags);
     438        if (br == NULL)
     439            return NULL;
     440        Tail(ret, br);  // kRegExpBranch -> kRegExpBranch.
     441        if (!(flags & kHasWidth))
     442            *flagp &= ~kHasWidth;
     443        *flagp |= flags&kSPStart;
     444    }
     445
     446    // Make a closing node, and hook it on the end.
     447    ender = Node(paren ? (char)(kRegExpClose + parno) : (char)kRegExpEnd); 
     448    Tail(ret, ender);
     449
     450    // Hook the tails of the branches to the closing node.
     451    for (br = ret; br != NULL; br = Next(br))
     452        OpTail(br, ender);
     453
     454    // Check for proper termination.
     455    if (paren && *fInputScanPointer++ != ')') {
     456        SetError(REGEXP_UNMATCHED_PARENTHESIS);
     457        return NULL;
     458    } else if (!paren && *fInputScanPointer != '\0') {
     459        if (*fInputScanPointer == ')') {
     460            SetError(REGEXP_UNMATCHED_PARENTHESIS);
     461            return NULL;
     462        } else {
     463            SetError(REGEXP_JUNK_ON_END);
     464            return NULL;    //  "Can't happen".
     465        }
     466        // NOTREACHED
     467    }
     468
     469    return ret;
     470}
     471
     472//
     473// - Branch - one alternative of an | operator
     474//
     475// Implements the concatenation operator.
     476//
     477char *
     478RegExp::Branch(int32 *flagp)
     479{
     480    char *ret;
     481    char *chain;
     482    char *latest;
     483    int32 flags;
     484
     485    *flagp = kWorst;        // Tentatively.
     486
     487    ret = Node(kRegExpBranch);
     488    chain = NULL;
     489    while (*fInputScanPointer != '\0'
     490        && *fInputScanPointer != '|'
     491        && *fInputScanPointer != ')') {
     492        latest = Piece(&flags);
     493        if (latest == NULL)
     494            return NULL;
     495        *flagp |= flags & kHasWidth;
     496        if (chain == NULL)  // First piece.
     497            *flagp |= flags & kSPStart;
     498        else
     499            Tail(chain, latest);
     500        chain = latest;
     501    }
     502    if (chain == NULL)  // Loop ran zero times.
     503        Node(kRegExpNothing);
     504
     505    return ret;
     506}
     507
     508//
     509// - Piece - something followed by possible [*+?]
     510//
     511// Note that the branching code sequences used for ? and the general cases
     512// of * and + are somewhat optimized:  they use the same kRegExpNothing node as
     513// both the endmarker for their branch list and the body of the last branch.
     514// It might seem that this node could be dispensed with entirely, but the
     515// endmarker role is not redundant.
     516//
     517char *
     518RegExp::Piece(int32 *flagp)
     519{
     520    char *ret;
     521    char op;
     522    char *next;
     523    int32 flags;
     524
     525    ret = Atom(&flags);
     526    if (ret == NULL)
     527        return NULL;
     528
     529    op = *fInputScanPointer;
     530    if (!IsMult(op)) {
     531        *flagp = flags;
     532        return ret;
     533    }
     534
     535    if (!(flags & kHasWidth) && op != '?') {
     536        SetError(REGEXP_STAR_PLUS_OPERAND_EMPTY);
     537        return NULL;
     538    }
     539    *flagp = op != '+' ? kWorst | kSPStart :  kWorst | kHasWidth;
     540
     541    if (op == '*' && (flags & kSimple))
     542        Insert(kRegExpStar, ret);
     543    else if (op == '*') {
     544        // Emit x* as (x&|), where & means "self".
     545        Insert(kRegExpBranch, ret);             // Either x
     546        OpTail(ret, Node(kRegExpBack));     // and loop
     547        OpTail(ret, ret);               // back
     548        Tail(ret, Node(kRegExpBranch));     // or
     549        Tail(ret, Node(kRegExpNothing));        // null.
     550    } else if (op == '+' && (flags & kSimple))
     551        Insert(kRegExpPlus, ret);
     552    else if (op == '+') {
     553        // Emit x+ as x(&|), where & means "self".
     554        next = Node(kRegExpBranch);             // Either
     555        Tail(ret, next);
     556        Tail(Node(kRegExpBack), ret);       // loop back
     557        Tail(next, Node(kRegExpBranch));        // or
     558        Tail(ret, Node(kRegExpNothing));        // null.
     559    } else if (op == '?') {
     560        // Emit x? as (x|)
     561        Insert(kRegExpBranch, ret);         // Either x
     562        Tail(ret, Node(kRegExpBranch)); // or
     563        next = Node(kRegExpNothing);        // null.
     564        Tail(ret, next);
     565        OpTail(ret, next);
     566    }
     567    fInputScanPointer++;
     568    if (IsMult(*fInputScanPointer)) {
     569        SetError(REGEXP_NESTED_STAR_QUESTION_PLUS);
     570        return NULL;
     571    }
     572    return ret;
     573}
     574
     575//
     576// - Atom - the lowest level
     577//
     578// Optimization:  gobbles an entire sequence of ordinary characters so that
     579// it can turn them into a single node, which is smaller to store and
     580// faster to run.  Backslashed characters are exceptions, each becoming a
     581// separate node; the code is simpler that way and it's not worth fixing.
     582//
     583char *
     584RegExp::Atom(int32 *flagp)
     585{
     586    char *ret;
     587    int32 flags;
     588
     589    *flagp = kWorst;        // Tentatively.
     590
     591    switch (*fInputScanPointer++) {
     592        case '^':
     593            ret = Node(kRegExpBol);
     594            break;
     595        case '$':
     596            ret = Node(kRegExpEol);
     597            break;
     598        case '.':
     599            ret = Node(kRegExpAny);
     600            *flagp |= kHasWidth|kSimple;
     601            break;
     602        case '[':
     603            {
     604                int32 cclass;
     605                int32 classend;
     606   
     607                if (*fInputScanPointer == '^') {    // Complement of range.
     608                    ret = Node(kRegExpAnyBut);
     609                    fInputScanPointer++;
     610                } else
     611                    ret = Node(kRegExpAnyOf);
     612                if (*fInputScanPointer == ']' || *fInputScanPointer == '-')
     613                    Char(*fInputScanPointer++);
     614                while (*fInputScanPointer != '\0' && *fInputScanPointer != ']') {
     615                    if (*fInputScanPointer == '-') {
     616                        fInputScanPointer++;
     617                        if (*fInputScanPointer == ']' || *fInputScanPointer == '\0')
     618                            Char('-');
     619                        else {
     620                            cclass = UCharAt(fInputScanPointer - 2) + 1;
     621                            classend = UCharAt(fInputScanPointer);
     622                            if (cclass > classend + 1) {
     623                                SetError(REGEXP_INVALID_BRACKET_RANGE);
     624                                return NULL;
     625                            }
     626                            for (; cclass <= classend; cclass++)
     627                                Char((char)cclass);
     628                            fInputScanPointer++;
     629                        }
     630                    } else
     631                        Char(*fInputScanPointer++);
     632                }
     633                Char('\0');
     634                if (*fInputScanPointer != ']') {
     635                    SetError(REGEXP_UNMATCHED_BRACKET);
     636                    return NULL;
     637                }
     638                fInputScanPointer++;
     639                *flagp |= kHasWidth | kSimple;
     640            }
     641            break;
     642        case '(':
     643            ret = Reg(1, &flags);
     644            if (ret == NULL)
     645                return NULL;
     646            *flagp |= flags & (kHasWidth | kSPStart);
     647            break;
     648        case '\0':
     649        case '|':
     650        case ')':
     651            SetError(REGEXP_INTERNAL_ERROR);
     652            return NULL; //  Supposed to be caught earlier.
     653        case '?':
     654        case '+':
     655        case '*':
     656            SetError(REGEXP_QUESTION_PLUS_STAR_FOLLOWS_NOTHING);
     657            return NULL;
     658        case '\\':
     659            if (*fInputScanPointer == '\0') {
     660                SetError(REGEXP_TRAILING_BACKSLASH);
     661                return NULL;
     662            }
     663            ret = Node(kRegExpExactly);
     664            Char(*fInputScanPointer++);
     665            Char('\0');
     666            *flagp |= kHasWidth|kSimple;
     667            break;
     668        default:
     669            {
     670                int32 len;
     671                char ender;
     672   
     673                fInputScanPointer--;
     674                len = (int32)strcspn(fInputScanPointer, kMeta);
     675                if (len <= 0) {
     676                    SetError(REGEXP_INTERNAL_ERROR);
     677                    return NULL;
     678                }
     679                ender = *(fInputScanPointer + len);
     680                if (len > 1 && IsMult(ender))
     681                    len--;      // Back off clear of ?+* operand.
     682                *flagp |= kHasWidth;
     683                if (len == 1)
     684                    *flagp |= kSimple;
     685                ret = Node(kRegExpExactly);
     686                while (len > 0) {
     687                    Char(*fInputScanPointer++);
     688                    len--;
     689                }
     690                Char('\0');
     691            }
     692            break;
     693    }
     694
     695    return ret;
     696}
     697
     698//
     699// - Node - emit a node
     700//
     701char *          // Location.
     702RegExp::Node(char op)
     703{
     704    char *ret;
     705    char *ptr;
     706
     707    ret = fCodeEmitPointer;
     708    if (ret == &fDummy) {
     709        fCodeSize += 3;
     710        return ret;
     711    }
     712
     713    ptr = ret;
     714    *ptr++ = op;
     715    *ptr++ = '\0';      // Null "next" pointer.
     716    *ptr++ = '\0';
     717    fCodeEmitPointer = ptr;
     718
     719    return ret;
     720}
     721
     722//
     723// - Char - emit (if appropriate) a byte of code
     724//
     725void
     726RegExp::Char(char b)
     727{
     728    if (fCodeEmitPointer != &fDummy)
     729        *fCodeEmitPointer++ = b;
     730    else
     731        fCodeSize++;
     732}
     733
     734//
     735// - Insert - insert an operator in front of already-emitted operand
     736//
     737// Means relocating the operand.
     738//
     739void
     740RegExp::Insert(char op, char *opnd)
     741{
     742    char *src;
     743    char *dst;
     744    char *place;
     745
     746    if (fCodeEmitPointer == &fDummy) {
     747        fCodeSize += 3;
     748        return;
     749    }
     750
     751    src = fCodeEmitPointer;
     752    fCodeEmitPointer += 3;
     753    dst = fCodeEmitPointer;
     754    while (src > opnd)
     755        *--dst = *--src;
     756
     757    place = opnd;       // Op node, where operand used to be.
     758    *place++ = op;
     759    *place++ = '\0';
     760    *place++ = '\0';
     761}
     762
     763//
     764// - Tail - set the next-pointer at the end of a node chain
     765//
     766void
     767RegExp::Tail(char *p, char *val)
     768{
     769    char *scan;
     770    char *temp;
     771    int32 offset;
     772
     773    if (p == &fDummy)
     774        return;
     775
     776    // Find last node.
     777    scan = p;
     778    for (;;) {
     779        temp = Next(scan);
     780        if (temp == NULL)
     781            break;
     782        scan = temp;
     783    }
     784
     785    if (scan[0] == kRegExpBack)
     786        offset = scan - val;
     787    else
     788        offset = val - scan;
     789
     790    scan[1] = (char)((offset >> 8) & 0377);
     791    scan[2] = (char)(offset & 0377);
     792}
     793
     794//
     795// - OpTail - Tail on operand of first argument; nop if operandless
     796//
     797void
     798RegExp::OpTail(char *p, char *val)
     799{
     800    // "Operandless" and "op != kRegExpBranch" are synonymous in practice.
     801    if (p == NULL || p == &fDummy || *p != kRegExpBranch)
     802        return;
     803    Tail(Operand(p), val);
     804}
     805
     806//
     807// RunMatcher and friends
     808//
     809
     810//
     811// - RunMatcher - match a regexp against a string
     812//
     813int32
     814RegExp::RunMatcher(regexp *prog, const char *string) const
     815{
     816    const char *s;
     817
     818    // Be paranoid...
     819    if (prog == NULL || string == NULL) {
     820        SetError(B_BAD_VALUE);
     821        return 0;
     822    }
     823
     824    // Check validity of program.
     825    if (UCharAt(prog->program) != kRegExpMagic) {
     826        SetError(REGEXP_CORRUPTED_PROGRAM);
     827        return 0;
     828    }
     829
     830    // If there is a "must appear" string, look for it.
     831    if (prog->regmust != NULL) {
     832        s = string;
     833        while ((s = strchr(s, prog->regmust[0])) != NULL) {
     834            if (strncmp(s, prog->regmust, (size_t)prog->regmlen) == 0)
     835                break;  // Found it.
     836            s++;
     837        }
     838        if (s == NULL)  // Not present.
     839            return 0;
     840    }
     841
     842    // Mark beginning of line for ^ .
     843    fRegBol = string;
     844
     845    // Simplest case:  anchored match need be tried only once.
     846    if (prog->reganch)
     847        return Try(prog, (char*)string);
     848
     849    // Messy cases:  unanchored match.
     850    s = string;
     851    if (prog->regstart != '\0')
     852        // We know what char it must start with.
     853        while ((s = strchr(s, prog->regstart)) != NULL) {
     854            if (Try(prog, (char*)s))
     855                return 1;
     856            s++;
     857        }
     858    else
     859        // We don't -- general case.
     860        do {
     861            if (Try(prog, (char*)s))
     862                return 1;
     863        } while (*s++ != '\0');
     864
     865    // Failure.
     866    return 0;
     867}
     868
     869//
     870// - Try - try match at specific point
     871//
     872int32           // 0 failure, 1 success
     873RegExp::Try(regexp *prog, const char *string) const
     874{
     875    int32 i;
     876    const char **sp;
     877    const char **ep;
     878
     879    fStringInputPointer = string;
     880    fStartPArrayPointer = prog->startp;
     881    fEndPArrayPointer = prog->endp;
     882
     883    sp = prog->startp;
     884    ep = prog->endp;
     885    for (i = kSubExpressionMax; i > 0; i--) {
     886        *sp++ = NULL;
     887        *ep++ = NULL;
     888    }
     889    if (Match(prog->program + 1)) {
     890        prog->startp[0] = string;
     891        prog->endp[0] = fStringInputPointer;
     892        return 1;
     893    } else
     894        return 0;
     895}
     896
     897//
     898// - Match - main matching routine
     899//
     900// Conceptually the strategy is simple:  check to see whether the current
     901// node matches, call self recursively to see whether the rest matches,
     902// and then act accordingly.  In practice we make some effort to avoid
     903// recursion, in particular by going through "ordinary" nodes (that don't
     904// need to know whether the rest of the match failed) by a loop instead of
     905// by recursion.
     906///
     907int32           // 0 failure, 1 success
     908RegExp::Match(const char *prog) const
     909{
     910    const char *scan;   // Current node.
     911    const char *next;       // Next node.
     912
     913    scan = prog;
     914#ifdef DEBUG
     915    if (scan != NULL && regnarrate)
     916        fprintf(stderr, "%s(\n", Prop(scan));
     917#endif
     918    while (scan != NULL) {
     919#ifdef DEBUG
     920        if (regnarrate)
     921            fprintf(stderr, "%s...\n", Prop(scan));
     922#endif
     923        next = Next(scan);
     924
     925        switch (*scan) {
     926            case kRegExpBol:
     927                if (fStringInputPointer != fRegBol)
     928                    return 0;
     929                break;
     930            case kRegExpEol:
     931                if (*fStringInputPointer != '\0')
     932                    return 0;
     933                break;
     934            case kRegExpAny:
     935                if (*fStringInputPointer == '\0')
     936                    return 0;
     937                fStringInputPointer++;
     938                break;
     939            case kRegExpExactly:
     940                {
     941                    const char *opnd = Operand(scan);
     942                    // Inline the first character, for speed.
     943                    if (*opnd != *fStringInputPointer)
     944                        return 0;
     945
     946                    uint32 len = strlen(opnd);
     947                    if (len > 1 && strncmp(opnd, fStringInputPointer, len) != 0)
     948                        return 0;
     949
     950                    fStringInputPointer += len;
     951                }
     952                break;
     953            case kRegExpAnyOf:
     954                if (*fStringInputPointer == '\0'
     955                    || strchr(Operand(scan), *fStringInputPointer) == NULL)
     956                    return 0;
     957                fStringInputPointer++;
     958                break;
     959            case kRegExpAnyBut:
     960                if (*fStringInputPointer == '\0'
     961                    || strchr(Operand(scan), *fStringInputPointer) != NULL)
     962                    return 0;
     963                fStringInputPointer++;
     964                break;
     965            case kRegExpNothing:
     966                break;
     967            case kRegExpBack:
     968                break;
     969            case kRegExpOpen + 1:
     970            case kRegExpOpen + 2:
     971            case kRegExpOpen + 3:
     972            case kRegExpOpen + 4:
     973            case kRegExpOpen + 5:
     974            case kRegExpOpen + 6:
     975            case kRegExpOpen + 7:
     976            case kRegExpOpen + 8:
     977            case kRegExpOpen + 9:
     978                {
     979                    int32 no;
     980                    const char *save;
     981   
     982                    no = *scan - kRegExpOpen;
     983                    save = fStringInputPointer;
     984   
     985                    if (Match(next)) {
     986                        //
     987                        // Don't set startp if some later
     988                        // invocation of the same parentheses
     989                        // already has.
     990                        //
     991                        if (fStartPArrayPointer[no] == NULL)
     992                            fStartPArrayPointer[no] = save;
     993                        return 1;
     994                    } else
     995                        return 0;
     996                }
     997                break;
     998            case kRegExpClose + 1:
     999            case kRegExpClose + 2:
     1000            case kRegExpClose + 3:
     1001            case kRegExpClose + 4:
     1002            case kRegExpClose + 5:
     1003            case kRegExpClose + 6:
     1004            case kRegExpClose + 7:
     1005            case kRegExpClose + 8:
     1006            case kRegExpClose + 9:
     1007                {
     1008                    int32 no;
     1009                    const char *save;
     1010   
     1011                    no = *scan - kRegExpClose;
     1012                    save = fStringInputPointer;
     1013   
     1014                    if (Match(next)) {
     1015                        //
     1016                        // Don't set endp if some later
     1017                        // invocation of the same parentheses
     1018                        // already has.
     1019                        //
     1020                        if (fEndPArrayPointer[no] == NULL)
     1021                            fEndPArrayPointer[no] = save;
     1022                        return 1;
     1023                    } else
     1024                        return 0;
     1025                }
     1026                break;
     1027            case kRegExpBranch:
     1028                {
     1029                    const char *save;
     1030   
     1031                    if (*next != kRegExpBranch)     // No choice.
     1032                        next = Operand(scan);   // Avoid recursion.
     1033                    else {
     1034                        do {
     1035                            save = fStringInputPointer;
     1036                            if (Match(Operand(scan)))
     1037                                return 1;
     1038                            fStringInputPointer = save;
     1039                            scan = Next(scan);
     1040                        } while (scan != NULL && *scan == kRegExpBranch);
     1041                        return 0;
     1042                        // NOTREACHED/
     1043                    }
     1044                }
     1045                break;
     1046            case kRegExpStar:
     1047            case kRegExpPlus:
     1048                {
     1049                    char nextch;
     1050                    int32 no;
     1051                    const char *save;
     1052                    int32 min;
     1053   
     1054                    //
     1055                    //Lookahead to avoid useless match attempts
     1056                    // when we know what character comes next.
     1057                    //
     1058                    nextch = '\0';
     1059                    if (*next == kRegExpExactly)
     1060                        nextch = *Operand(next);
     1061                    min = (*scan == kRegExpStar) ? 0 : 1;
     1062                    save = fStringInputPointer;
     1063                    no = Repeat(Operand(scan));
     1064                    while (no >= min) {
     1065                        // If it could work, try it.
     1066                        if (nextch == '\0' || *fStringInputPointer == nextch)
     1067                            if (Match(next))
     1068                                return 1;
     1069                        // Couldn't or didn't -- back up.
     1070                        no--;
     1071                        fStringInputPointer = save + no;
     1072                    }
     1073                    return 0;
     1074                }
     1075                break;
     1076            case kRegExpEnd:
     1077                return 1;   // Success!
     1078
     1079            default:
     1080                SetError(REGEXP_MEMORY_CORRUPTION);
     1081                return 0;
     1082            }
     1083
     1084        scan = next;
     1085    }
     1086
     1087    //
     1088    // We get here only if there's trouble -- normally "case kRegExpEnd" is
     1089    // the terminating point.
     1090    //
     1091    SetError(REGEXP_CORRUPTED_POINTERS);
     1092    return 0;
     1093}
     1094
     1095//
     1096// - Repeat - repeatedly match something simple, report how many
     1097//
     1098int32
     1099RegExp::Repeat(const char *p) const
     1100{
     1101    int32 count = 0;
     1102    const char *scan;
     1103    const char *opnd;
     1104
     1105    scan = fStringInputPointer;
     1106    opnd = Operand(p);
     1107    switch (*p) {
     1108        case kRegExpAny:
     1109            count = (int32)strlen(scan);
     1110            scan += count;
     1111            break;
     1112
     1113        case kRegExpExactly:
     1114            while (*opnd == *scan) {
     1115                count++;
     1116                scan++;
     1117            }
     1118            break;
     1119
     1120        case kRegExpAnyOf:
     1121            while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
     1122                count++;
     1123                scan++;
     1124            }
     1125            break;
     1126
     1127        case kRegExpAnyBut:
     1128            while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
     1129                count++;
     1130                scan++;
     1131            }
     1132            break;
     1133
     1134        default:        // Oh dear.  Called inappropriately.
     1135            SetError(REGEXP_INTERNAL_ERROR);
     1136            count = 0;  // Best compromise.
     1137            break;
     1138    }
     1139    fStringInputPointer = scan;
     1140
     1141    return count;
     1142}
     1143
     1144//
     1145// - Next - dig the "next" pointer out of a node
     1146//
     1147char *
     1148RegExp::Next(char *p)
     1149{
     1150    int32 offset;
     1151
     1152    if (p == &fDummy)
     1153        return NULL;
     1154
     1155    offset = ((*(p + 1) & 0377) << 8) + (*(p + 2) & 0377);
     1156    if (offset == 0)
     1157        return NULL;
     1158
     1159    if (*p == kRegExpBack)
     1160        return p - offset;
     1161    else
     1162        return p + offset;
     1163}
     1164
     1165const char *
     1166RegExp::Next(const char *p) const
     1167{
     1168    int32 offset;
     1169
     1170    if (p == &fDummy)
     1171        return NULL;
     1172
     1173    offset = ((*(p + 1) & 0377) << 8) + (*(p + 2) & 0377);
     1174    if (offset == 0)
     1175        return NULL;
     1176
     1177    if (*p == kRegExpBack)
     1178        return p - offset;
     1179    else
     1180        return p + offset;
     1181}
     1182
     1183inline int32
     1184RegExp::UCharAt(const char *p) const
     1185{
     1186    return (int32)*(unsigned char *)p;
     1187}
     1188
     1189inline char *
     1190RegExp::Operand(char* p) const
     1191{
     1192    return p + 3;
     1193}
     1194
     1195inline const char *
     1196RegExp::Operand(const char* p) const
     1197{
     1198    return p + 3;
     1199}
     1200
     1201inline bool
     1202RegExp::IsMult(char c) const
     1203{
     1204    return c == '*' || c == '+' || c == '?';
     1205}
     1206
     1207
     1208#ifdef DEBUG
     1209
     1210//
     1211// - Dump - dump a regexp onto stdout in vaguely comprehensible form
     1212//
     1213void
     1214RegExp::Dump()
     1215{
     1216    char *s;
     1217    char op = kRegExpExactly;   // Arbitrary non-kRegExpEnd op.
     1218    char *next;
     1219
     1220    s = fRegExp->program + 1;
     1221    while (op != kRegExpEnd) {  // While that wasn't kRegExpEnd last time...
     1222        op = *s;
     1223        printf("%2ld%s", s - fRegExp->program, Prop(s));    // Where, what.
     1224        next = this->Next(s);
     1225        if (next == NULL)       // Next ptr.
     1226            printf("(0)");
     1227        else
     1228            printf("(%ld)", (s - fRegExp->program) + (next - s));
     1229        s += 3;
     1230        if (op == kRegExpAnyOf || op == kRegExpAnyBut || op == kRegExpExactly) {
     1231            // Literal string, where present.
     1232            while (*s != '\0') {
     1233                putchar(*s);
     1234                s++;
     1235            }
     1236            s++;
     1237        }
     1238        putchar('\n');
     1239    }
     1240
     1241    // Header fields of interest.
     1242    if (fRegExp->regstart != '\0')
     1243        printf("start `%c' ", fRegExp->regstart);
     1244    if (fRegExp->reganch)
     1245        printf("anchored ");
     1246    if (fRegExp->regmust != NULL)
     1247        printf("must have \"%s\"", fRegExp->regmust);
     1248    printf("\n");
     1249}
     1250
     1251//
     1252// - Prop - printable representation of opcode
     1253//
     1254char *
     1255RegExp::Prop(const char *op) const
     1256{
     1257    char *p = NULL;
     1258    static char buf[50];
     1259
     1260    (void) strcpy(buf, ":");
     1261
     1262    switch (*op) {
     1263        case kRegExpBol:
     1264            p = "kRegExpBol";
     1265            break;
     1266        case kRegExpEol:
     1267            p = "kRegExpEol";
     1268            break;
     1269        case kRegExpAny:
     1270            p = "kRegExpAny";
     1271            break;
     1272        case kRegExpAnyOf:
     1273            p = "kRegExpAnyOf";
     1274            break;
     1275        case kRegExpAnyBut:
     1276            p = "kRegExpAnyBut";
     1277            break;
     1278        case kRegExpBranch:
     1279            p = "kRegExpBranch";
     1280            break;
     1281        case kRegExpExactly:
     1282            p = "kRegExpExactly";
     1283            break;
     1284        case kRegExpNothing:
     1285            p = "kRegExpNothing";
     1286            break;
     1287        case kRegExpBack:
     1288            p = "kRegExpBack";
     1289            break;
     1290        case kRegExpEnd:
     1291            p = "kRegExpEnd";
     1292            break;
     1293        case kRegExpOpen + 1:
     1294        case kRegExpOpen + 2:
     1295        case kRegExpOpen + 3:
     1296        case kRegExpOpen + 4:
     1297        case kRegExpOpen + 5:
     1298        case kRegExpOpen + 6:
     1299        case kRegExpOpen + 7:
     1300        case kRegExpOpen + 8:
     1301        case kRegExpOpen + 9:
     1302            sprintf(buf + strlen(buf), "kRegExpOpen%d", *op - kRegExpOpen);
     1303            p = NULL;
     1304            break;
     1305        case kRegExpClose + 1:
     1306        case kRegExpClose + 2:
     1307        case kRegExpClose + 3:
     1308        case kRegExpClose + 4:
     1309        case kRegExpClose + 5:
     1310        case kRegExpClose + 6:
     1311        case kRegExpClose + 7:
     1312        case kRegExpClose + 8:
     1313        case kRegExpClose + 9:
     1314            sprintf(buf + strlen(buf), "kRegExpClose%d", *op - kRegExpClose);
     1315            p = NULL;
     1316            break;
     1317        case kRegExpStar:
     1318            p = "kRegExpStar";
     1319            break;
     1320        case kRegExpPlus:
     1321            p = "kRegExpPlus";
     1322            break;
     1323        default:
     1324            RegExpError("corrupted opcode");
     1325            break;
     1326    }
     1327
     1328    if (p != NULL)
     1329        strcat(buf, p);
     1330
     1331    return buf;
     1332}
     1333
     1334void
     1335RegExp::RegExpError(const char *) const
     1336{
     1337    // does nothing now, perhaps it should printf?
     1338}
     1339
     1340#endif
  • src/bin/Jamfile

     
    222222# Network command line tools
    223223SubInclude HAIKU_TOP src bin network ;
    224224
     225# Locale kit tools
     226SubInclude HAIKU_TOP src bin locale ;
     227
    225228# Compression command line tools
    226229SubInclude HAIKU_TOP src bin unzip ;
    227230SubInclude HAIKU_TOP src bin zip ;
  • src/kits/locale/GenericNumberFormat.cpp

     
     1#include <algorithm>
     2#include <float.h>
     3#include <math.h>
     4#include <new>
     5#include <stdlib.h>
     6
     7#include <GenericNumberFormat.h>
     8#include <String.h>
     9#include <UnicodeChar.h>
     10
     11// constants (more below the helper classes)
     12
     13static const int kMaxIntDigitCount = 20;    // int64: 19 + sign, uint64: 20
     14static const int kMaxFloatDigitCount = DBL_DIG + 2;
     15    // double: mantissa precision + 2
     16
     17
     18// Symbol
     19
     20// constructor
     21BGenericNumberFormat::Symbol::Symbol(const char *symbol)
     22    : symbol(NULL),
     23      length(0),
     24      char_count(0)
     25{
     26    SetTo(symbol);
     27}
     28
     29// destructor
     30BGenericNumberFormat::Symbol::~Symbol()
     31{
     32    Unset();
     33}
     34
     35// SetTo
     36status_t
     37BGenericNumberFormat::Symbol::SetTo(const char *symbol)
     38{
     39    // unset old
     40    if (this->symbol) {
     41        free(this->symbol);
     42        length = 0;
     43        char_count = 0;
     44    }
     45    // set new
     46    if (symbol) {
     47        this->symbol = strdup(symbol);
     48        if (!this->symbol)
     49            return B_NO_MEMORY;
     50        length = strlen(this->symbol);
     51        char_count = BUnicodeChar::UTF8StringLength(this->symbol);
     52    }
     53    return B_OK;
     54}
     55
     56
     57// SpecialNumberSymbols
     58struct BGenericNumberFormat::SpecialNumberSymbols {
     59    const Symbol    *nan;
     60    const Symbol    *infinity;
     61    const Symbol    *negative_infinity;
     62};
     63
     64
     65// GroupingInfo
     66class BGenericNumberFormat::GroupingInfo {
     67    public:
     68        GroupingInfo()
     69            : fSeparators(NULL),
     70              fSeparatorCount(0),
     71              fSizes(NULL),
     72              fSizeCount(0),
     73              fSumSizes(NULL),
     74              fSumSeparators(NULL)
     75        {
     76        }
     77
     78        GroupingInfo(const char **separators, int32 separatorCount,
     79                     const size_t *sizes, int32 sizeCount)
     80            : fSeparators(NULL),
     81              fSeparatorCount(0),
     82              fSizes(NULL),
     83              fSizeCount(0),
     84              fSumSizes(NULL),
     85              fSumSeparators(NULL)
     86        {
     87            SetTo(separators, separatorCount, sizes, sizeCount);
     88        }
     89
     90        ~GroupingInfo()
     91        {
     92            Unset();
     93        }
     94
     95        status_t SetTo(const char **separators, int32 separatorCount,
     96                       const size_t *sizes, int32 sizeCount)
     97        {
     98            // unset old
     99            Unset();
     100            // set new
     101            if (!separators && separatorCount <= 0 || !sizes && sizeCount <= 0)
     102                return B_OK;
     103            // allocate arrays
     104            fSeparators = new(std::nothrow) Symbol[separatorCount];
     105            fSizes = new(std::nothrow) int32[sizeCount];
     106            fSumSizes = new(std::nothrow) int32[sizeCount];
     107            fSumSeparators = new(std::nothrow) Symbol*[separatorCount];
     108            if (!fSeparators || !fSizes || !fSumSizes || !fSumSeparators) {
     109                Unset();
     110                return B_NO_MEMORY;
     111            }
     112            fSeparatorCount = separatorCount;
     113            fSizeCount = sizeCount;
     114            // separators
     115            for (int i = 0; i < separatorCount; i++) {
     116                status_t error = fSeparators[i].SetTo(separators[i]);
     117                if (error != B_OK) {
     118                    Unset();
     119                    return error;
     120                }
     121            }
     122            // sizes and sum arrays
     123            int32 sumSize = -1;
     124            for (int32 i = 0; i < sizeCount; i++) {
     125                fSizes[i] = (int32)sizes[i];
     126                sumSize += fSizes[i];
     127                fSumSizes[i] = sumSize;
     128                fSumSeparators[i] = &fSeparators[std::min(i, fSeparatorCount)];
     129            }
     130            return B_OK;
     131        }
     132
     133        void Unset()
     134        {
     135            if (fSeparators) {
     136                delete[] fSeparators;
     137                fSeparators = NULL;
     138            }
     139            fSeparatorCount = 0;
     140            if (fSizes) {
     141                delete[] fSizes;
     142                fSizes = NULL;
     143            }
     144            fSizeCount = 0;
     145            if (fSumSizes) {
     146                delete[] fSumSizes;
     147                fSumSizes = NULL;
     148            }
     149            if (fSumSeparators) {
     150                delete[] fSumSeparators;
     151                fSumSeparators = NULL;
     152            }
     153        }
     154
     155        const Symbol *SeparatorForDigit(int32 position) const
     156        {
     157            for (int i = fSizeCount - 1; i >= 0; i--) {
     158                if (fSumSizes[i] <= position) {
     159                    if (fSumSizes[i] == position
     160                        || i == fSizeCount - 1
     161                           && (position - fSumSizes[i]) % fSizes[i] == 0) {
     162                        return fSumSeparators[i];
     163                    }
     164                    return NULL;
     165                }
     166            }
     167            return NULL;
     168        }
     169
     170    private:
     171        Symbol  *fSeparators;
     172        int32   fSeparatorCount;
     173        int32   *fSizes;
     174        int32   fSizeCount;
     175        int32   *fSumSizes;
     176        Symbol  **fSumSeparators;
     177};
     178
     179
     180// SignSymbols
     181class BGenericNumberFormat::SignSymbols {
     182    public:
     183        SignSymbols()
     184            : fPlusPrefix(),
     185              fMinusPrefix(),
     186              fPadPlusPrefix(),
     187              fNoForcePlusPrefix(),
     188              fPlusSuffix(),
     189              fMinusSuffix(),
     190              fPadPlusSuffix(),
     191              fNoForcePlusSuffix()
     192        {
     193        }
     194
     195        SignSymbols(const char *plusPrefix, const char *minusPrefix,
     196            const char *padPlusPrefix, const char *noForcePlusPrefix,
     197            const char *plusSuffix, const char *minusSuffix,
     198            const char *padPlusSuffix, const char *noForcePlusSuffix)
     199            : fPlusPrefix(plusPrefix),
     200              fMinusPrefix(minusPrefix),
     201              fPadPlusPrefix(padPlusPrefix),
     202              fNoForcePlusPrefix(noForcePlusPrefix),
     203              fPlusSuffix(plusSuffix),
     204              fMinusSuffix(minusSuffix),
     205              fPadPlusSuffix(padPlusSuffix),
     206              fNoForcePlusSuffix(noForcePlusSuffix)
     207        {
     208        }
     209
     210        ~SignSymbols()
     211        {
     212        }
     213
     214        status_t SetTo(const char *plusPrefix, const char *minusPrefix,
     215            const char *padPlusPrefix, const char *noForcePlusPrefix,
     216            const char *plusSuffix, const char *minusSuffix,
     217            const char *padPlusSuffix, const char *noForcePlusSuffix)
     218        {
     219            status_t error = B_OK;
     220            if (error == B_OK)
     221                error = fPlusPrefix.SetTo(plusPrefix);
     222            if (error == B_OK)
     223                error = fMinusPrefix.SetTo(minusPrefix);
     224            if (error == B_OK)
     225                error = fPadPlusPrefix.SetTo(noForcePlusPrefix);
     226            if (error == B_OK)
     227                error = fNoForcePlusPrefix.SetTo(noForcePlusPrefix);
     228            if (error == B_OK)
     229                error = fPlusSuffix.SetTo(plusSuffix);
     230            if (error == B_OK)
     231                error = fMinusSuffix.SetTo(minusSuffix);
     232            if (error == B_OK)
     233                error = fPadPlusSuffix.SetTo(noForcePlusSuffix);
     234            if (error == B_OK)
     235                error = fNoForcePlusSuffix.SetTo(noForcePlusSuffix);
     236            if (error != B_OK)
     237                Unset();
     238            return error;
     239        }
     240
     241        void Unset()
     242        {
     243            fPlusPrefix.Unset();
     244            fMinusPrefix.Unset();
     245            fNoForcePlusPrefix.Unset();
     246            fPadPlusPrefix.Unset();
     247            fPlusSuffix.Unset();
     248            fMinusSuffix.Unset();
     249            fNoForcePlusSuffix.Unset();
     250            fPadPlusSuffix.Unset();
     251        }
     252
     253        const Symbol *PlusPrefix() const
     254        {
     255            return &fPlusPrefix;
     256        }
     257
     258        const Symbol *MinusPrefix() const
     259        {
     260            return &fMinusPrefix;
     261        }
     262
     263        const Symbol *PadPlusPrefix() const
     264        {
     265            return &fPadPlusPrefix;
     266        }
     267
     268        const Symbol *NoForcePlusPrefix() const
     269        {
     270            return &fNoForcePlusPrefix;
     271        }
     272
     273        const Symbol *PlusSuffix() const
     274        {
     275            return &fPlusSuffix;
     276        }
     277
     278        const Symbol *MinusSuffix() const
     279        {
     280            return &fMinusSuffix;
     281        }
     282
     283        const Symbol *PadPlusSuffix() const
     284        {
     285            return &fPadPlusSuffix;
     286        }
     287
     288        const Symbol *NoForcePlusSuffix() const
     289        {
     290            return &fNoForcePlusSuffix;
     291        }
     292
     293    private:
     294        Symbol  fPlusPrefix;
     295        Symbol  fMinusPrefix;
     296        Symbol  fPadPlusPrefix;
     297        Symbol  fNoForcePlusPrefix;
     298        Symbol  fPlusSuffix;
     299        Symbol  fMinusSuffix;
     300        Symbol  fPadPlusSuffix;
     301        Symbol  fNoForcePlusSuffix;
     302};
     303
     304
     305// BufferWriter
     306class BGenericNumberFormat::BufferWriter {
     307    public:
     308        BufferWriter(char *buffer = NULL, int32 bufferSize = 0)
     309        {
     310            SetTo(buffer, bufferSize);
     311        }
     312
     313        void SetTo(char *buffer = NULL, int32 bufferSize = 0)
     314        {
     315            fBuffer = buffer;
     316            fBufferSize = bufferSize;
     317            fPosition = 0;
     318            fCharCount = 0;
     319            fDryRun = (!fBuffer || (fBufferSize == 0));
     320            if (!fDryRun)
     321                fBuffer[0] = '\0';
     322        }
     323
     324        int32 StringLength() const
     325        {
     326            return fPosition;
     327        }
     328
     329        int32 CharCount() const
     330        {
     331            return fCharCount;
     332        }
     333
     334        bool IsOverflow() const
     335        {
     336            return (fPosition >= fBufferSize);
     337        }
     338
     339        void Append(const char *bytes, size_t length, size_t charCount)
     340        {
     341            int32 newPosition = fPosition + length;
     342            fDryRun |= (newPosition >= fBufferSize);
     343            if (!fDryRun && length > 0) {
     344                memcpy(fBuffer + fPosition, bytes, length);
     345                fBuffer[newPosition] = '\0';
     346            }
     347            fPosition = newPosition;
     348            fCharCount += charCount;
     349        }
     350
     351        void Append(const Symbol &symbol)
     352        {
     353            Append(symbol.symbol, symbol.length, symbol.char_count);
     354        }
     355
     356        void Append(const Symbol *symbol)
     357        {
     358            if (symbol)
     359                Append(*symbol);
     360        }
     361
     362        void Append(char c, int32 count)    // ASCII 128 chars only!
     363        {
     364            if (count <= 0)
     365                return;
     366            int32 newPosition = fPosition + count;
     367            fDryRun |= (newPosition >= fBufferSize);
     368            if (!fDryRun && count > 0) {
     369                memset(fBuffer + fPosition, c, count);
     370                fBuffer[newPosition] = '\0';
     371            }
     372            fPosition = newPosition;
     373            fCharCount += count;
     374        }
     375
     376        void Append(const Symbol &symbol, int32 count)
     377        {
     378            if (count <= 0)
     379                return;
     380            int32 bytes = count * symbol.length;
     381            int32 newPosition = fPosition + bytes;
     382            fDryRun |= (newPosition >= fBufferSize);
     383            if (!fDryRun && count > 0) {
     384                for (int i = 0; i < count * symbol.length; i++)
     385                    fBuffer[i] = symbol.symbol[i % symbol.length];
     386                fBuffer[newPosition] = '\0';
     387            }
     388            fPosition = newPosition;
     389            fCharCount += count * symbol.char_count;
     390        }
     391
     392        void Append(const Symbol *symbol, int32 count)
     393        {
     394            if (symbol)
     395                Append(*symbol, count);
     396        }
     397
     398    private:
     399        char    *fBuffer;
     400        int32   fBufferSize;
     401        int32   fPosition;
     402        int32   fCharCount;
     403        bool    fDryRun;
     404};
     405
     406
     407// constants
     408
     409// digit symbols
     410static const BGenericNumberFormat::Symbol kDefaultDigitSymbols[] = {
     411    "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
     412};
     413
     414// decimal separator symbol
     415static const BGenericNumberFormat::Symbol kDefaultFractionSeparator = ".";
     416
     417// grouping separator symbols
     418static const char *kDefaultGroupingSeparators[] = { "," };
     419static const int32 kDefaultGroupingSeparatorCount
     420    = sizeof(kDefaultGroupingSeparators) / sizeof(const char*);
     421static const char *kNoGroupingSeparators[] = { NULL };  // to please mwcc
     422static const int32 kNoGroupingSeparatorCount = 0;
     423
     424// grouping sizes
     425static const size_t kDefaultGroupingSizes[] = { 3 };
     426static const int32 kDefaultGroupingSizeCount
     427    = sizeof(kDefaultGroupingSizes) / sizeof(size_t);
     428static const size_t kNoGroupingSizes[] = { 0 };         // to please mwcc
     429static const int32 kNoGroupingSizeCount = 0;
     430
     431// grouping info
     432static const BGenericNumberFormat::GroupingInfo kDefaultGroupingInfo(
     433    kDefaultGroupingSeparators, kDefaultGroupingSeparatorCount,
     434    kDefaultGroupingSizes, kDefaultGroupingSizeCount
     435);
     436static const BGenericNumberFormat::GroupingInfo kNoGroupingInfo(
     437    kNoGroupingSeparators, kNoGroupingSeparatorCount,
     438    kNoGroupingSizes, kNoGroupingSizeCount
     439);
     440
     441// exponent symbol
     442static const BGenericNumberFormat::Symbol kDefaultExponentSymbol = "e";
     443static const BGenericNumberFormat::Symbol kDefaultUpperCaseExponentSymbol
     444    = "E";
     445
     446// NaN symbol
     447static const BGenericNumberFormat::Symbol kDefaultNaNSymbol = "NaN";
     448static const BGenericNumberFormat::Symbol kDefaultUpperCaseNaNSymbol = "NaN";
     449
     450// infinity symbol
     451static const BGenericNumberFormat::Symbol kDefaultInfinitySymbol
     452    = "infinity";
     453static const BGenericNumberFormat::Symbol kDefaultUpperCaseInfinitySymbol
     454    = "INFINITY";
     455
     456// negative infinity symbol
     457static const BGenericNumberFormat::Symbol kDefaultNegativeInfinitySymbol
     458    = "-infinity";
     459static const BGenericNumberFormat::Symbol
     460    kDefaultUpperCaseNegativeInfinitySymbol = "-INFINITY";
     461
     462// sign symbols
     463static const BGenericNumberFormat::SignSymbols kDefaultSignSymbols(
     464    "+", "-", " ", "",  // prefixes
     465    "", "", "", ""      // suffixes
     466);
     467
     468// mantissa sign symbols
     469static const BGenericNumberFormat::SignSymbols kDefaultMantissaSignSymbols(
     470    "", "", "", "", // prefixes
     471    "", "", "", ""      // suffixes
     472);
     473
     474// exponent sign symbols
     475static const BGenericNumberFormat::SignSymbols kDefaultExponentSignSymbols(
     476    "+", "-", " ", "",  // prefixes
     477    "", "", "", ""      // suffixes
     478);
     479
     480
     481// Integer
     482class BGenericNumberFormat::Integer {
     483    public:
     484        Integer(int64 number)
     485            : fDigitCount(0),
     486              fNegative(number < 0)
     487        {
     488            if (fNegative)
     489                Init(0ULL - (uint64)number);
     490            else
     491                Init(number);
     492        }
     493
     494        Integer(uint64 number)
     495            : fDigitCount(0),
     496              fNegative(false)
     497        {
     498            Init(number);
     499        }
     500
     501        int DigitCount() const
     502        {
     503            return fDigitCount;
     504        }
     505
     506        bool IsNegative() const
     507        {
     508            return fNegative;
     509        }
     510
     511        char *ToString(char *str) const
     512        {
     513            if (fDigitCount == 0) {
     514                str[0] = '0';
     515                str[1] = '\0';
     516            } else if (fNegative) {
     517                str[0] = '-';
     518                for (int i = 0; i < fDigitCount; i++)
     519                    str[i + 1] = '0' + fDigits[fDigitCount - i - 1];
     520                str[fDigitCount + 1] = '\0';
     521            } else {
     522                for (int i = 0; i < fDigitCount; i++)
     523                    str[i] = '0' + fDigits[fDigitCount - i - 1];
     524                str[fDigitCount] = '\0';
     525            }
     526            return str;
     527        }
     528
     529        void Format(BufferWriter &writer, const Symbol *digitSymbols,
     530            const SignSymbols *signSymbols,
     531            number_format_sign_policy signPolicy,
     532            const GroupingInfo *groupingInfo, int32 minDigits)  const
     533        {
     534            const Symbol *suffix = NULL;
     535            // write sign prefix
     536            if (fNegative) {
     537                writer.Append(signSymbols->MinusPrefix());
     538                suffix = signSymbols->MinusSuffix();
     539            } else {
     540                switch (signPolicy) {
     541                    case B_USE_NEGATIVE_SIGN_ONLY:
     542                        writer.Append(signSymbols->NoForcePlusPrefix());
     543                        suffix = signSymbols->NoForcePlusSuffix();
     544                        break;
     545                    case B_USE_SPACE_FOR_POSITIVE_SIGN:
     546                        writer.Append(signSymbols->PadPlusPrefix());
     547                        suffix = signSymbols->PadPlusSuffix();
     548                        break;
     549                    case B_USE_POSITIVE_SIGN:
     550                        writer.Append(signSymbols->PlusPrefix());
     551                        suffix = signSymbols->PlusSuffix();
     552                        break;
     553                }
     554            }
     555            // the digits
     556            if (fDigitCount == 0 && minDigits < 1) {
     557                // special case for zero and less the one minimal digit
     558                writer.Append(digitSymbols[0]);
     559            } else {
     560                // not zero or at least one minimal digit
     561                if (groupingInfo) {
     562                    // use grouping
     563                    // pad with zeros up to minDigits
     564                    int32 digitCount = std::max(fDigitCount, minDigits);
     565                    for (int i = minDigits - 1; i >= fDigitCount; i--) {
     566                        if (i != digitCount - 1)
     567                            writer.Append(groupingInfo->SeparatorForDigit(i));
     568                        writer.Append(digitSymbols[0]);
     569                    }
     570                    // write digits
     571                    for (int i = fDigitCount - 1; i >= 0; i--) {
     572                        if (i != digitCount - 1)
     573                            writer.Append(groupingInfo->SeparatorForDigit(i));
     574                        writer.Append(digitSymbols[fDigits[i]]);
     575                    }
     576                } else {
     577                    // no grouping
     578                    // pad with zeros up to minDigits
     579                    if (fDigitCount < minDigits)
     580                        writer.Append(digitSymbols, minDigits - fDigitCount);
     581                    // write digits
     582                    for (int i = fDigitCount - 1; i >= 0; i--)
     583                        writer.Append(digitSymbols[fDigits[i]]);
     584                }
     585            }
     586            // append suffix
     587            writer.Append(suffix);
     588        }
     589
     590    private:
     591        void Init(uint64 number)
     592        {
     593            fDigitCount = 0;
     594            while (number) {
     595                fDigits[fDigitCount] = number % 10;
     596                number /= 10;
     597                fDigitCount++;
     598            }
     599        }
     600
     601    private:
     602        uchar   fDigits[kMaxIntDigitCount];
     603        int32   fDigitCount;
     604        bool    fNegative;
     605};
     606
     607
     608// Float
     609class BGenericNumberFormat::Float {
     610    public:
     611        Float(double number)
     612            : fNegative(signbit(number)),
     613              fClass(fpclassify(number)),
     614              fExponent(0),
     615              fDigitCount(0)
     616        {
     617            // filter special cases
     618            switch (fClass) {
     619                case FP_NAN:
     620                case FP_INFINITE:
     621                    return;
     622                case FP_ZERO:
     623                    fDigits[0] = 0;
     624                    fDigitCount = 1;
     625                    return;
     626                case FP_NORMAL:
     627                case FP_SUBNORMAL:
     628                    break;
     629            }
     630            if (fNegative)
     631                number = -number;
     632            // We start with an exponent great enough to make
     633            // number / 10^fExponent < 10. It may even be < 1 or 0.1.
     634            // We simply cut those digits later.
     635            fExponent = (int)ceil(log10(number));
     636            int shiftBy = kMaxFloatDigitCount - fExponent - 1;
     637            // We don't multiply with 10^shiftBy not in one go, since for
     638            // subnormal numbers 10^shiftBy will not be representable. Maybe
     639            // also for normal numbers close to the limit -- so don't risk
     640            // anything, for the time being. TODO: Optimize later.
     641            double mantissa = number * pow(10, shiftBy / 2);
     642            mantissa *= pow(10, shiftBy - shiftBy / 2);
     643            // get the mantissa's digits -- we drop trailing zeros
     644            int32 firstNonNull = -1;
     645            for (int i = 0; i < kMaxFloatDigitCount; i++) {
     646                char digit = (char)fmod(mantissa, 10);
     647                if (firstNonNull < 0 && digit > 0)
     648                    firstNonNull = i;
     649                if (firstNonNull >= 0)
     650                    fDigits[i - firstNonNull] = digit;
     651                mantissa /= 10;
     652            }
     653            if (firstNonNull >= 0)
     654                fDigitCount = kMaxFloatDigitCount - firstNonNull;
     655            else
     656                fDigitCount = 0;
     657            // drop leading zeros
     658            while (fDigitCount > 0 && fDigits[fDigitCount - 1] == 0) {
     659                fDigitCount--;
     660                fExponent--;
     661            }
     662            // due to rounding effects we may end up with zero: switch to its
     663            // canaonical representation then
     664            if (fDigitCount == 0) {
     665                fExponent = 0;
     666                fDigits[0] = 0;
     667                fDigitCount = 1;
     668            }
     669        }
     670
     671        void Format(BufferWriter &writer, const Symbol *digitSymbols,
     672            const SpecialNumberSymbols *specialNumbers,
     673            const Symbol *fractionSeparator,
     674            const Symbol *exponentSymbol,
     675            const SignSymbols *signSymbols,
     676            const SignSymbols *mantissaSignSymbols,
     677            const SignSymbols *exponentSignSymbols,
     678            float_format_type formatType,
     679            number_format_sign_policy signPolicy,
     680            const GroupingInfo *groupingInfo,
     681            int32 minIntegerDigits, int32 minFractionDigits,
     682            int32 maxFractionDigits, bool forceFractionSeparator,
     683            bool keepTrailingFractionZeros) const
     684        {
     685            // deal with special numbers
     686            switch (fClass) {
     687                case FP_NAN:
     688                    writer.Append(specialNumbers->nan);
     689                    return;
     690                case FP_INFINITE:
     691                    if (fNegative)
     692                        writer.Append(specialNumbers->negative_infinity);
     693                    else
     694                        writer.Append(specialNumbers->infinity);
     695                    return;
     696                case FP_ZERO:
     697                case FP_NORMAL:
     698                case FP_SUBNORMAL:
     699                    break;
     700            }
     701            // format according to the specified format type
     702            bool scientific = false;
     703            switch (formatType) {
     704                case B_FIXED_POINT_FLOAT_FORMAT:
     705                    break;
     706                case B_SCIENTIFIC_FLOAT_FORMAT:
     707                    scientific = true;
     708                    break;
     709                case B_AUTO_FLOAT_FORMAT:
     710                    // the criterion printf() uses:
     711                    scientific = (fExponent >= maxFractionDigits
     712                                  || fExponent < -4);
     713                    break;
     714            }
     715            // finally invoke the respective method that does the formatting
     716            if (scientific) {
     717                FormatScientific(writer, digitSymbols, fractionSeparator,
     718                    exponentSymbol, signSymbols, mantissaSignSymbols,
     719                    exponentSignSymbols, signPolicy, minIntegerDigits,
     720                    minFractionDigits, maxFractionDigits,
     721                    forceFractionSeparator, keepTrailingFractionZeros);
     722            } else {
     723                FormatFixedPoint(writer, digitSymbols, fractionSeparator,
     724                    signSymbols, mantissaSignSymbols, signPolicy, groupingInfo,
     725                    minIntegerDigits, minFractionDigits, maxFractionDigits,
     726                    forceFractionSeparator, keepTrailingFractionZeros);
     727            }
     728        }
     729
     730        void FormatScientific(BufferWriter &writer, const Symbol *digitSymbols,
     731            const Symbol *fractionSeparator,
     732            const Symbol *exponentSymbol,
     733            const SignSymbols *signSymbols,
     734            const SignSymbols *mantissaSignSymbols,
     735            const SignSymbols *exponentSignSymbols,
     736            number_format_sign_policy signPolicy,
     737            int32 minIntegerDigits, int32 minFractionDigits,
     738            int32 maxFractionDigits, bool forceFractionSeparator,
     739            bool keepTrailingFractionZeros) const
     740        {
     741            const Symbol *suffix = NULL;
     742            const Symbol *mantissaSuffix = NULL;
     743            // write sign prefix
     744            if (fNegative) {
     745                writer.Append(signSymbols->MinusPrefix());
     746                writer.Append(mantissaSignSymbols->MinusPrefix());
     747                suffix = signSymbols->MinusSuffix();
     748                mantissaSuffix = mantissaSignSymbols->MinusSuffix();
     749            } else {
     750                switch (signPolicy) {
     751                    case B_USE_NEGATIVE_SIGN_ONLY:
     752                        writer.Append(signSymbols->NoForcePlusPrefix());
     753                        writer.Append(mantissaSignSymbols->NoForcePlusPrefix());
     754                        suffix = signSymbols->NoForcePlusSuffix();
     755                        mantissaSuffix
     756                            = mantissaSignSymbols->NoForcePlusSuffix();
     757                        break;
     758                    case B_USE_SPACE_FOR_POSITIVE_SIGN:
     759                        writer.Append(signSymbols->PadPlusPrefix());
     760                        writer.Append(mantissaSignSymbols->PadPlusPrefix());
     761                        suffix = signSymbols->PadPlusSuffix();
     762                        mantissaSuffix = mantissaSignSymbols->PadPlusSuffix();
     763                        break;
     764                    case B_USE_POSITIVE_SIGN:
     765                        writer.Append(signSymbols->PlusPrefix());
     766                        writer.Append(mantissaSignSymbols->PlusPrefix());
     767                        suffix = signSymbols->PlusSuffix();
     768                        mantissaSuffix = mantissaSignSymbols->PlusSuffix();
     769                        break;
     770                }
     771            }
     772            // round
     773            int32 exponent = fExponent;
     774            char digits[kMaxFloatDigitCount];
     775            int32 integerDigits = std::max(minIntegerDigits, 1L);
     776            int32 fractionDigits
     777                = std::max(fDigitCount - integerDigits, minFractionDigits);
     778            fractionDigits = std::min(fractionDigits, maxFractionDigits);
     779            int32 digitCount
     780                = _Round(digits, integerDigits + fractionDigits, exponent);
     781            fractionDigits = digitCount - integerDigits;
     782            if (keepTrailingFractionZeros)
     783                fractionDigits = std::max(fractionDigits, minFractionDigits);
     784            fractionDigits = std::min(fractionDigits, maxFractionDigits);
     785            // the mantissa
     786            // integer part
     787            int32 existingIntegerDigits = std::min(integerDigits, digitCount);
     788            for (int i = 0; i < existingIntegerDigits; i++)
     789                writer.Append(digitSymbols[digits[digitCount - i - 1]]);
     790            // pad with zeros to get the desired number of integer digits
     791            if (existingIntegerDigits < integerDigits) {
     792                writer.Append(digitSymbols,
     793                              integerDigits - existingIntegerDigits);
     794            }
     795            // unless the number is 0, adjust the exponent
     796            if (!_IsZero(digits, digitCount))
     797                exponent -= integerDigits - 1;
     798            // fraction part
     799            if (fractionDigits > 0 || forceFractionSeparator)
     800                writer.Append(fractionSeparator);
     801            int32 existingFractionDigits
     802                = std::min(digitCount - integerDigits, fractionDigits);
     803            for (int i = existingFractionDigits - 1; i >= 0; i--)
     804                writer.Append(digitSymbols[digits[i]]);
     805            // pad with zeros to get the desired number of fraction digits
     806            if (fractionDigits > existingFractionDigits) {
     807                writer.Append(digitSymbols,
     808                              fractionDigits - existingFractionDigits);
     809            }
     810            writer.Append(mantissaSuffix);
     811            // the exponent
     812            writer.Append(exponentSymbol);
     813
     814            Integer(static_cast<int64>(exponent)).Format(writer, digitSymbols,
     815                exponentSignSymbols, B_USE_POSITIVE_SIGN, &kNoGroupingInfo, 2);
     816            // sign suffix
     817            writer.Append(suffix);
     818        }
     819
     820        void FormatFixedPoint(BufferWriter &writer, const Symbol *digitSymbols,
     821            const Symbol *fractionSeparator,
     822            const SignSymbols *signSymbols,
     823            const SignSymbols *mantissaSignSymbols,
     824            number_format_sign_policy signPolicy,
     825            const GroupingInfo *groupingInfo,
     826            int32 minIntegerDigits, int32 minFractionDigits,
     827            int32 maxFractionDigits, bool forceFractionSeparator,
     828            bool keepTrailingFractionZeros) const
     829        {
     830            const Symbol *suffix = NULL;
     831            const Symbol *mantissaSuffix = NULL;
     832            // write sign prefix
     833            if (fNegative) {
     834                writer.Append(signSymbols->MinusPrefix());
     835                writer.Append(mantissaSignSymbols->MinusPrefix());
     836                suffix = signSymbols->MinusSuffix();
     837                mantissaSuffix = mantissaSignSymbols->MinusSuffix();
     838            } else {
     839                switch (signPolicy) {
     840                    case B_USE_NEGATIVE_SIGN_ONLY:
     841                        writer.Append(signSymbols->NoForcePlusPrefix());
     842                        writer.Append(mantissaSignSymbols->NoForcePlusPrefix());
     843                        suffix = signSymbols->NoForcePlusSuffix();
     844                        mantissaSuffix
     845                            = mantissaSignSymbols->NoForcePlusSuffix();
     846                        break;
     847                    case B_USE_SPACE_FOR_POSITIVE_SIGN:
     848                        writer.Append(signSymbols->PadPlusPrefix());
     849                        writer.Append(mantissaSignSymbols->PadPlusPrefix());
     850                        suffix = signSymbols->PadPlusSuffix();
     851                        mantissaSuffix = mantissaSignSymbols->PadPlusSuffix();
     852                        break;
     853                    case B_USE_POSITIVE_SIGN:
     854                        writer.Append(signSymbols->PlusPrefix());
     855                        writer.Append(mantissaSignSymbols->PlusPrefix());
     856                        suffix = signSymbols->PlusSuffix();
     857                        mantissaSuffix = mantissaSignSymbols->PlusSuffix();
     858                        break;
     859                }
     860            }
     861            // round
     862            int32 exponent = fExponent;
     863            char digits[kMaxFloatDigitCount];
     864            int32 integerDigits = std::max(minIntegerDigits, exponent + 1L);
     865            int32 fractionDigits
     866                = std::max(fDigitCount - integerDigits, minFractionDigits);
     867            fractionDigits = std::min(fractionDigits, maxFractionDigits);
     868            int32 digitCount
     869                = _Round(digits, integerDigits + fractionDigits, exponent);
     870            fractionDigits = digitCount - integerDigits;
     871            if (keepTrailingFractionZeros)
     872                fractionDigits = std::max(fractionDigits, minFractionDigits);
     873            fractionDigits = std::min(fractionDigits, maxFractionDigits);
     874            // integer part
     875            int32 existingIntegerDigits = std::min(integerDigits, exponent + 1);
     876            existingIntegerDigits = std::max(existingIntegerDigits, 0L);
     877            if (groupingInfo) {
     878                // use grouping
     879                // pad with zeros up to minDigits
     880                for (int i = integerDigits - 1;
     881                     i >= existingIntegerDigits;
     882                     i--) {
     883                    if (i != integerDigits - 1)
     884                        writer.Append(groupingInfo->SeparatorForDigit(i));
     885                    writer.Append(digitSymbols[0]);
     886                }
     887                // write digits
     888                for (int i = existingIntegerDigits - 1; i >= 0; i--) {
     889                    if (i != integerDigits - 1)
     890                        writer.Append(groupingInfo->SeparatorForDigit(i));
     891                    writer.Append(digitSymbols[digits[
     892                        digitCount - existingIntegerDigits + i]]);
     893                }
     894            } else {
     895                // no grouping
     896                // pad with zeros to get the desired number of integer digits
     897                if (existingIntegerDigits < integerDigits) {
     898                    writer.Append(digitSymbols[0],
     899                                  integerDigits - existingIntegerDigits);
     900                }
     901                // write digits
     902                for (int i = 0; i < existingIntegerDigits; i++)
     903                    writer.Append(digitSymbols[digits[digitCount - i - 1]]);
     904            }
     905            // fraction part
     906            if (fractionDigits > 0 || forceFractionSeparator)
     907                writer.Append(fractionSeparator);
     908            int32 existingFractionDigits
     909                = std::min(digitCount - existingIntegerDigits, fractionDigits);
     910            for (int i = existingFractionDigits - 1; i >= 0; i--)
     911                writer.Append(digitSymbols[digits[i]]);
     912            // pad with zeros to get the desired number of fraction digits
     913            if (fractionDigits > existingFractionDigits) {
     914                writer.Append(digitSymbols,
     915                              fractionDigits - existingFractionDigits);
     916            }
     917            // sign suffixes
     918            writer.Append(mantissaSuffix);
     919            writer.Append(suffix);
     920        }
     921
     922    private:
     923        int32 _Round(char *digits, int32 count, int32 &exponent) const
     924        {
     925            if (count > fDigitCount)
     926                count = fDigitCount;
     927            int firstNonNull = -1;
     928// TODO: Non-hardcoded base-independent rounding.
     929            bool carry = false;
     930            if (count < fDigitCount)
     931                carry = (fDigits[fDigitCount - count - 1] >= 5);
     932            for (int i = 0; i < count; i++) {
     933                char digit =  fDigits[fDigitCount - count + i];
     934                if (carry) {
     935                    digit++;
     936                    if (digit == 10)    // == base
     937                        digit = 0;
     938                    else
     939                        carry = false;
     940                }
     941                if (firstNonNull < 0 && digit > 0)
     942                    firstNonNull = i;
     943                if (firstNonNull >= 0)
     944                    digits[i - firstNonNull] = digit;
     945            }
     946            if (firstNonNull < 0) {
     947                if (carry) {
     948                    // 9.999999... -> 10
     949                    digits[0] = 1;
     950                    exponent++;
     951                } else {
     952                    // 0.0000...1 -> 0
     953                    exponent = 0;
     954                    digits[0] = 0;
     955                }
     956                count = 1;
     957            } else
     958                count -= firstNonNull;
     959            return count;
     960        }
     961
     962        static bool _IsZero(const char *digits, int32 digitCount)
     963        {
     964            return (digitCount == 1 && digits[0] == 0);
     965        }
     966
     967    private:
     968        bool    fNegative;
     969        int     fClass;
     970        int32   fExponent;
     971        char    fDigits[kMaxFloatDigitCount];
     972        int32   fDigitCount;
     973};
     974
     975
     976// constructor
     977BGenericNumberFormat::BGenericNumberFormat()
     978    : fIntegerParameters(),
     979      fFloatParameters(),
     980      fDigitSymbols(NULL),
     981      fFractionSeparator(NULL),
     982      fGroupingInfo(NULL),
     983      fExponentSymbol(NULL),
     984      fUpperCaseExponentSymbol(NULL),
     985      fNaNSymbol(NULL),
     986      fUpperCaseNaNSymbol(NULL),
     987      fInfinitySymbol(NULL),
     988      fUpperCaseInfinitySymbol(NULL),
     989      fNegativeInfinitySymbol(NULL),
     990      fUpperCaseNegativeInfinitySymbol(NULL),
     991      fSignSymbols(NULL),
     992      fMantissaSignSymbols(NULL),
     993      fExponentSignSymbols(NULL)
     994{
     995}
     996
     997// destructor
     998BGenericNumberFormat::~BGenericNumberFormat()
     999{
     1000}
     1001
     1002// FormatInteger
     1003status_t
     1004BGenericNumberFormat::FormatInteger(
     1005    const BIntegerFormatParameters *parameters, int64 number, BString *buffer,
     1006    format_field_position *positions, int32 positionCount, int32 *fieldCount,
     1007    bool allFieldPositions) const
     1008{
     1009    if (!buffer)
     1010        return B_BAD_VALUE;
     1011    char localBuffer[1024];
     1012    status_t error = FormatInteger(parameters, number, localBuffer,
     1013        sizeof(localBuffer), positions, positionCount, fieldCount,
     1014        allFieldPositions);
     1015    if (error == B_OK) {
     1016        buffer->Append(localBuffer);
     1017        // TODO: Check, if the allocation succeeded.
     1018    }
     1019    return error;
     1020}
     1021
     1022// FormatInteger
     1023status_t
     1024BGenericNumberFormat::FormatInteger(
     1025    const BIntegerFormatParameters *parameters, uint64 number, BString *buffer,
     1026    format_field_position *positions, int32 positionCount, int32 *fieldCount,
     1027    bool allFieldPositions) const
     1028{
     1029    if (!buffer)
     1030        return B_BAD_VALUE;
     1031    char localBuffer[1024];
     1032    status_t error = FormatInteger(parameters, number, localBuffer,
     1033        sizeof(localBuffer), positions, positionCount, fieldCount,
     1034        allFieldPositions);
     1035    if (error == B_OK) {
     1036        buffer->Append(localBuffer);
     1037        // TODO: Check, if the allocation succeeded.
     1038    }
     1039    return error;
     1040}
     1041
     1042// FormatInteger
     1043status_t
     1044BGenericNumberFormat::FormatInteger(
     1045    const BIntegerFormatParameters *parameters, int64 number, char *buffer,
     1046    size_t bufferSize, format_field_position *positions, int32 positionCount,
     1047    int32 *fieldCount, bool allFieldPositions) const
     1048{
     1049    Integer integer(number);
     1050    return FormatInteger(parameters, integer, buffer, bufferSize, positions,
     1051                         positionCount, fieldCount, allFieldPositions);
     1052}
     1053
     1054// FormatInteger
     1055status_t
     1056BGenericNumberFormat::FormatInteger(
     1057    const BIntegerFormatParameters *parameters, uint64 number, char *buffer,
     1058    size_t bufferSize, format_field_position *positions, int32 positionCount,
     1059    int32 *fieldCount, bool allFieldPositions) const
     1060{
     1061    Integer integer(number);
     1062    return FormatInteger(parameters, integer, buffer, bufferSize, positions,
     1063                         positionCount, fieldCount, allFieldPositions);
     1064}
     1065
     1066// FormatFloat
     1067status_t
     1068BGenericNumberFormat::FormatFloat(const BFloatFormatParameters *parameters,
     1069    double number, BString *buffer, format_field_position *positions,
     1070    int32 positionCount, int32 *fieldCount, bool allFieldPositions) const
     1071{
     1072    if (!buffer)
     1073        return B_BAD_VALUE;
     1074    // TODO: How to ensure that this is enough?
     1075    char localBuffer[1024];
     1076    status_t error = FormatFloat(parameters, number, localBuffer,
     1077        sizeof(localBuffer), positions, positionCount, fieldCount,
     1078        allFieldPositions);
     1079    if (error == B_OK) {
     1080        buffer->Append(localBuffer);
     1081        // TODO: Check, if the allocation succeeded.
     1082    }
     1083    return error;
     1084}
     1085
     1086// FormatFloat
     1087status_t
     1088BGenericNumberFormat::FormatFloat(const BFloatFormatParameters *parameters,
     1089    double number, char *buffer, size_t bufferSize,
     1090    format_field_position *positions, int32 positionCount, int32 *fieldCount,
     1091    bool allFieldPositions) const
     1092{
     1093    // TODO: Check parameters.
     1094    if (!parameters)
     1095        parameters = DefaultFloatFormatParameters();
     1096    if (bufferSize <= parameters->FormatWidth())
     1097        return EOVERFLOW;
     1098    Float floatNumber(number);
     1099    // prepare some parameters
     1100    const GroupingInfo *groupingInfo = NULL;
     1101    if (parameters->UseGrouping())
     1102        groupingInfo = GetGroupingInfo();
     1103    bool upperCase = parameters->UseUpperCase();
     1104    SpecialNumberSymbols specialSymbols;
     1105    GetSpecialNumberSymbols(upperCase, &specialSymbols);
     1106    // compute the length of the formatted string
     1107    BufferWriter writer;
     1108    floatNumber.Format(writer, DigitSymbols(), &specialSymbols,
     1109        FractionSeparator(), ExponentSymbol(), GetSignSymbols(),
     1110        MantissaSignSymbols(), ExponentSignSymbols(),
     1111        parameters->FloatFormatType(), parameters->SignPolicy(), groupingInfo,
     1112        parameters->MinimalIntegerDigits(), parameters->MinimalFractionDigits(),
     1113        parameters->MaximalFractionDigits(),
     1114        parameters->AlwaysUseFractionSeparator(),
     1115        parameters->KeepTrailingFractionZeros());
     1116    int32 stringLength = writer.StringLength();
     1117    int32 charCount = writer.CharCount();
     1118    // consider alignment and check the available space in the buffer
     1119    int32 padding = std::max(0L, (int32)parameters->FormatWidth() - charCount);
     1120// TODO: Padding with zeros.
     1121    if ((int32)bufferSize <= stringLength + padding)
     1122        return EOVERFLOW;
     1123    // prepare for writing
     1124    writer.SetTo(buffer, bufferSize);
     1125    // write padding for right field alignment
     1126    if (parameters->Alignment() == B_ALIGN_FORMAT_RIGHT && padding > 0)
     1127        writer.Append(' ', padding);
     1128    // write the number
     1129    floatNumber.Format(writer,  DigitSymbols(), &specialSymbols,
     1130        FractionSeparator(), ExponentSymbol(), GetSignSymbols(),
     1131        MantissaSignSymbols(), ExponentSignSymbols(),
     1132        parameters->FloatFormatType(), parameters->SignPolicy(), groupingInfo,
     1133        parameters->MinimalIntegerDigits(), parameters->MinimalFractionDigits(),
     1134        parameters->MaximalFractionDigits(),
     1135        parameters->AlwaysUseFractionSeparator(),
     1136        parameters->KeepTrailingFractionZeros());
     1137    // write padding for left field alignment
     1138    if (parameters->Alignment() == B_ALIGN_FORMAT_LEFT && padding > 0)
     1139        writer.Append(' ', padding);
     1140    return B_OK;
     1141}
     1142
     1143// SetDefaultIntegerFormatParameters
     1144status_t
     1145BGenericNumberFormat::SetDefaultIntegerFormatParameters(
     1146    const BIntegerFormatParameters *parameters)
     1147{
     1148    if (!parameters)
     1149        return B_BAD_VALUE;
     1150    fIntegerParameters = *parameters;
     1151    return B_OK;
     1152}
     1153
     1154// DefaultIntegerFormatParameters
     1155BIntegerFormatParameters *
     1156BGenericNumberFormat::DefaultIntegerFormatParameters()
     1157{
     1158    return &fIntegerParameters;
     1159}
     1160
     1161// DefaultIntegerFormatParameters
     1162const BIntegerFormatParameters *
     1163BGenericNumberFormat::DefaultIntegerFormatParameters() const
     1164{
     1165    return &fIntegerParameters;
     1166}
     1167
     1168// SetDefaultFloatFormatParameters
     1169status_t
     1170BGenericNumberFormat::SetDefaultFloatFormatParameters(
     1171    const BFloatFormatParameters *parameters)
     1172{
     1173    if (!parameters)
     1174        return B_BAD_VALUE;
     1175    fFloatParameters = *parameters;
     1176    return B_OK;
     1177}
     1178
     1179// DefaultFloatFormatParameters
     1180BFloatFormatParameters *
     1181BGenericNumberFormat::DefaultFloatFormatParameters()
     1182{
     1183    return &fFloatParameters;
     1184}
     1185
     1186// DefaultFloatFormatParameters
     1187const BFloatFormatParameters *
     1188BGenericNumberFormat::DefaultFloatFormatParameters() const
     1189{
     1190    return &fFloatParameters;
     1191}
     1192
     1193// SetDigitSymbols
     1194status_t
     1195BGenericNumberFormat::SetDigitSymbols(const char **digits)
     1196{
     1197    // check parameters
     1198    if (digits) {
     1199        for (int i = 0; i < 10; i++) {
     1200            if (!digits[i])
     1201                return B_BAD_VALUE;
     1202        }
     1203    }
     1204    // unset old
     1205    if (fDigitSymbols) {
     1206        delete[] fDigitSymbols;
     1207        fDigitSymbols = NULL;
     1208    }
     1209    // set new
     1210    if (digits) {
     1211        fDigitSymbols = new(std::nothrow) Symbol[10];
     1212        if (!fDigitSymbols)
     1213            return B_NO_MEMORY;
     1214        for (int i = 0; i < 10; i++) {
     1215            status_t error = fDigitSymbols[i].SetTo(digits[i]);
     1216            if (error != B_OK) {
     1217                SetDigitSymbols(NULL);
     1218                return error;
     1219            }
     1220        }
     1221    }
     1222    return B_OK;
     1223}
     1224
     1225// SetFractionSeparator
     1226status_t
     1227BGenericNumberFormat::SetFractionSeparator(const char *decimalSeparator)
     1228{
     1229    return _SetSymbol(&fFractionSeparator, decimalSeparator);
     1230}
     1231
     1232// SetGroupingInfo
     1233status_t
     1234BGenericNumberFormat::SetGroupingInfo(const char **groupingSeparators,
     1235    size_t separatorCount, size_t *groupingSizes, size_t sizeCount)
     1236{
     1237    // check parameters
     1238    if (groupingSeparators && separatorCount > 0 && groupingSizes
     1239        && sizeCount) {
     1240        for (int i = 0; i < (int)separatorCount; i++) {
     1241            if (!groupingSeparators[i])
     1242                return B_BAD_VALUE;
     1243        }
     1244    }
     1245    // unset old
     1246    if (fGroupingInfo) {
     1247        delete fGroupingInfo;
     1248        fGroupingInfo = NULL;
     1249    }
     1250    // set new
     1251    if (groupingSeparators && separatorCount > 0 && groupingSizes
     1252        && sizeCount) {
     1253        fGroupingInfo = new GroupingInfo;
     1254        if (!fGroupingInfo)
     1255            return B_NO_MEMORY;
     1256        status_t error = fGroupingInfo->SetTo(groupingSeparators,
     1257            separatorCount, groupingSizes, sizeCount);
     1258        if (error != B_OK) {
     1259            delete fGroupingInfo;
     1260            fGroupingInfo = NULL;
     1261            return error;
     1262        }
     1263    }
     1264    return B_OK;
     1265}
     1266
     1267// SetExponentSymbol
     1268status_t
     1269BGenericNumberFormat::SetExponentSymbol(const char *exponentSymbol,
     1270    const char *upperCaseExponentSymbol)
     1271{
     1272    status_t error = _SetSymbol(&fExponentSymbol, exponentSymbol);
     1273    if (error == B_OK)
     1274        error = _SetSymbol(&fUpperCaseExponentSymbol, upperCaseExponentSymbol);
     1275    if (error != B_OK)
     1276        SetExponentSymbol(NULL, NULL);
     1277    return error;
     1278}
     1279
     1280// SetSpecialNumberSymbols
     1281status_t
     1282BGenericNumberFormat::SetSpecialNumberSymbols(const char *nan,
     1283    const char *infinity, const char *negativeInfinity,
     1284    const char *upperCaseNaN, const char *upperCaseInfinity,
     1285    const char *upperCaseNegativeInfinity)
     1286{
     1287    status_t error = _SetSymbol(&fNaNSymbol, nan);
     1288    if (error == B_OK)
     1289        error = _SetSymbol(&fInfinitySymbol, infinity);
     1290    if (error == B_OK)
     1291        error = _SetSymbol(&fNegativeInfinitySymbol, negativeInfinity);
     1292    if (error == B_OK)
     1293        error = _SetSymbol(&fUpperCaseNaNSymbol, upperCaseNaN);
     1294    if (error == B_OK)
     1295        error = _SetSymbol(&fUpperCaseInfinitySymbol, upperCaseInfinity);
     1296    if (error == B_OK) {
     1297        error = _SetSymbol(&fUpperCaseNegativeInfinitySymbol,
     1298            upperCaseNegativeInfinity);
     1299    }
     1300    if (error != B_OK)
     1301        SetSpecialNumberSymbols(NULL, NULL, NULL, NULL, NULL, NULL);
     1302    return error;
     1303}
     1304
     1305// SetSignSymbols
     1306status_t
     1307BGenericNumberFormat::SetSignSymbols(const char *plusPrefix,
     1308    const char *minusPrefix, const char *padPlusPrefix,
     1309    const char *noForcePlusPrefix, const char *plusSuffix,
     1310    const char *minusSuffix, const char *padPlusSuffix,
     1311    const char *noForcePlusSuffix)
     1312{
     1313    if (!fSignSymbols) {
     1314        fSignSymbols = new(std::nothrow) SignSymbols;
     1315        if (!fSignSymbols)
     1316            return B_NO_MEMORY;
     1317    }
     1318    return fSignSymbols->SetTo(plusPrefix, minusPrefix, padPlusPrefix,
     1319        noForcePlusPrefix, plusSuffix, minusSuffix, padPlusSuffix,
     1320        noForcePlusSuffix);
     1321}
     1322
     1323// SetMantissaSignSymbols
     1324status_t
     1325BGenericNumberFormat::SetMantissaSignSymbols(const char *plusPrefix,
     1326    const char *minusPrefix, const char *padPlusPrefix,
     1327    const char *noForcePlusPrefix, const char *plusSuffix,
     1328    const char *minusSuffix, const char *padPlusSuffix,
     1329    const char *noForcePlusSuffix)
     1330{
     1331    if (!fMantissaSignSymbols) {
     1332        fMantissaSignSymbols = new(std::nothrow) SignSymbols;
     1333        if (!fMantissaSignSymbols)
     1334            return B_NO_MEMORY;
     1335    }
     1336    return fMantissaSignSymbols->SetTo(plusPrefix, minusPrefix, padPlusPrefix,
     1337        noForcePlusPrefix, plusSuffix, minusSuffix, padPlusSuffix,
     1338        noForcePlusSuffix);
     1339}
     1340
     1341// SetExponentSignSymbols
     1342status_t
     1343BGenericNumberFormat::SetExponentSignSymbols(const char *plusPrefix,
     1344    const char *minusPrefix, const char *plusSuffix, const char *minusSuffix)
     1345{
     1346    if (!fExponentSignSymbols) {
     1347        fExponentSignSymbols = new(std::nothrow) SignSymbols;
     1348        if (!fExponentSignSymbols)
     1349            return B_NO_MEMORY;
     1350    }
     1351    return fExponentSignSymbols->SetTo(plusPrefix, minusPrefix, plusPrefix,
     1352        plusPrefix, plusSuffix, minusSuffix, plusSuffix, plusSuffix);
     1353}
     1354
     1355// FormatInteger
     1356status_t
     1357BGenericNumberFormat::FormatInteger(
     1358    const BIntegerFormatParameters *parameters, const Integer &integer,
     1359    char *buffer, size_t bufferSize, format_field_position *positions,
     1360    int32 positionCount, int32 *fieldCount, bool allFieldPositions) const
     1361{
     1362    // TODO: Check parameters.
     1363    if (!parameters)
     1364        parameters = DefaultIntegerFormatParameters();
     1365    if (bufferSize <= parameters->FormatWidth())
     1366        return EOVERFLOW;
     1367    // prepare some parameters
     1368    const GroupingInfo *groupingInfo = NULL;
     1369    if (parameters->UseGrouping())
     1370        groupingInfo = GetGroupingInfo();
     1371    // compute the length of the formatted string
     1372    BufferWriter writer;
     1373    integer.Format(writer, DigitSymbols(),
     1374        GetSignSymbols(), parameters->SignPolicy(), groupingInfo,
     1375        parameters->MinimalIntegerDigits());
     1376    int32 stringLength = writer.StringLength();
     1377    int32 charCount = writer.CharCount();
     1378    // consider alignment and check the available space in the buffer
     1379    int32 padding = std::max(0L, (int32)parameters->FormatWidth() - charCount);
     1380// TODO: Padding with zeros.
     1381    if ((int32)bufferSize <= stringLength + padding)
     1382        return EOVERFLOW;
     1383    // prepare for writing
     1384    writer.SetTo(buffer, bufferSize);
     1385    // write padding for right field alignment
     1386    if (parameters->Alignment() == B_ALIGN_FORMAT_RIGHT && padding > 0)
     1387        writer.Append(' ', padding);
     1388    // write the number
     1389    integer.Format(writer, DigitSymbols(),
     1390        GetSignSymbols(), parameters->SignPolicy(), groupingInfo,
     1391        parameters->MinimalIntegerDigits());
     1392    // write padding for left field alignment
     1393    if (parameters->Alignment() == B_ALIGN_FORMAT_LEFT && padding > 0)
     1394        writer.Append(' ', padding);
     1395    return B_OK;
     1396}
     1397
     1398// DigitSymbols
     1399const BGenericNumberFormat::Symbol *
     1400BGenericNumberFormat::DigitSymbols() const
     1401{
     1402    return (fDigitSymbols ? fDigitSymbols : kDefaultDigitSymbols);
     1403}
     1404
     1405// FractionSeparator
     1406const BGenericNumberFormat::Symbol *
     1407BGenericNumberFormat::FractionSeparator() const
     1408{
     1409    return (fFractionSeparator ? fFractionSeparator
     1410                               : &kDefaultFractionSeparator);
     1411}
     1412
     1413// GetGroupingInfo
     1414const BGenericNumberFormat::GroupingInfo *
     1415BGenericNumberFormat::GetGroupingInfo() const
     1416{
     1417    return (fGroupingInfo ? fGroupingInfo : &kDefaultGroupingInfo);
     1418}
     1419
     1420// ExponentSymbol
     1421const BGenericNumberFormat::Symbol *
     1422BGenericNumberFormat::ExponentSymbol(bool upperCase) const
     1423{
     1424    if (fExponentSymbol) {
     1425        return (upperCase && fUpperCaseExponentSymbol ? fUpperCaseExponentSymbol
     1426                                                      : fExponentSymbol);
     1427    }
     1428    return (upperCase ? &kDefaultUpperCaseExponentSymbol
     1429                      : &kDefaultExponentSymbol);
     1430}
     1431
     1432// NaNSymbol
     1433const BGenericNumberFormat::Symbol *
     1434BGenericNumberFormat::NaNSymbol(bool upperCase) const
     1435{
     1436    if (fNaNSymbol) {
     1437        return (upperCase && fUpperCaseNaNSymbol ? fUpperCaseNaNSymbol
     1438                                                 : fNaNSymbol);
     1439    }
     1440    return (upperCase ? &kDefaultUpperCaseNaNSymbol
     1441                      : &kDefaultNaNSymbol);
     1442}
     1443
     1444// InfinitySymbol
     1445const BGenericNumberFormat::Symbol *
     1446BGenericNumberFormat::InfinitySymbol(bool upperCase) const
     1447{
     1448    if (fInfinitySymbol) {
     1449        return (upperCase && fUpperCaseInfinitySymbol ? fUpperCaseInfinitySymbol
     1450                                                      : fInfinitySymbol);
     1451    }
     1452    return (upperCase ? &kDefaultUpperCaseInfinitySymbol
     1453                      : &kDefaultInfinitySymbol);
     1454}
     1455
     1456// NegativeInfinitySymbol
     1457const BGenericNumberFormat::Symbol *
     1458BGenericNumberFormat::NegativeInfinitySymbol(bool upperCase) const
     1459{
     1460    if (fNegativeInfinitySymbol) {
     1461        return (upperCase && fUpperCaseNegativeInfinitySymbol
     1462            ? fUpperCaseNegativeInfinitySymbol : fNegativeInfinitySymbol);
     1463    }
     1464    return (upperCase ? &kDefaultUpperCaseNegativeInfinitySymbol
     1465                      : &kDefaultNegativeInfinitySymbol);
     1466}
     1467
     1468// GetSpecialNumberSymbols
     1469void
     1470BGenericNumberFormat::GetSpecialNumberSymbols(bool upperCase,
     1471    SpecialNumberSymbols *symbols) const
     1472{
     1473    symbols->nan = NaNSymbol(upperCase);
     1474    symbols->infinity = InfinitySymbol(upperCase);
     1475    symbols->negative_infinity = NegativeInfinitySymbol(upperCase);
     1476}
     1477
     1478// GetSignSymbols
     1479const BGenericNumberFormat::SignSymbols *
     1480BGenericNumberFormat::GetSignSymbols() const
     1481{
     1482    return (fSignSymbols ? fSignSymbols : &kDefaultSignSymbols);
     1483}
     1484
     1485// MantissaSignSymbols
     1486const BGenericNumberFormat::SignSymbols *
     1487BGenericNumberFormat::MantissaSignSymbols() const
     1488{
     1489    return (fMantissaSignSymbols ? fMantissaSignSymbols
     1490                                 : &kDefaultMantissaSignSymbols);
     1491}
     1492
     1493// ExponentSignSymbols
     1494const BGenericNumberFormat::SignSymbols *
     1495BGenericNumberFormat::ExponentSignSymbols() const
     1496{
     1497    return (fExponentSignSymbols ? fExponentSignSymbols
     1498                                 : &kDefaultExponentSignSymbols);
     1499}
     1500
     1501// _SetSymbol
     1502status_t
     1503BGenericNumberFormat::_SetSymbol(Symbol **symbol, const char *str)
     1504{
     1505    if (!str) {
     1506        // no symbol -- unset old
     1507        if (*symbol) {
     1508            delete *symbol;
     1509            symbol = NULL;
     1510        }
     1511    } else {
     1512        // allocate if not existing
     1513        if (!*symbol) {
     1514            *symbol = new(std::nothrow) Symbol;
     1515            if (!*symbol)
     1516                return B_NO_MEMORY;
     1517        }
     1518        // set symbol
     1519        status_t error = (*symbol)->SetTo(str);
     1520        if (error != B_OK) {
     1521            delete *symbol;
     1522            *symbol = NULL;
     1523            return B_NO_MEMORY;
     1524        }
     1525    }
     1526    return B_OK;
     1527}
     1528
  • src/kits/locale/FloatFormatImpl.cpp

     
     1#include <FloatFormatImpl.h>
     2#include <FloatFormatParameters.h>
     3
     4// constructor
     5BFloatFormatImpl::BFloatFormatImpl()
     6    : BNumberFormatImpl()
     7{
     8}
     9
     10// destructor
     11BFloatFormatImpl::~BFloatFormatImpl()
     12{
     13}
     14
     15// DefaultNumberFormatParameters
     16BNumberFormatParameters *
     17BFloatFormatImpl::DefaultNumberFormatParameters()
     18{
     19    return DefaultFloatFormatParameters();
     20}
     21
     22// DefaultNumberFormatParameters
     23const BNumberFormatParameters *
     24BFloatFormatImpl::DefaultNumberFormatParameters() const
     25{
     26    return DefaultFloatFormatParameters();
     27}
     28
  • src/kits/locale/FloatFormatParameters.cpp

     
     1#include <FloatFormatParameters.h>
     2
     3// defaults
     4static const size_t kDefaultMinimalFractionDigits = 0;
     5static const size_t kDefaultMaximalFractionDigits = 6;
     6static const bool kDefaultUseUpperCase = false;
     7static const float_format_type kDefaultFloatFormatType = B_AUTO_FLOAT_FORMAT;
     8static const bool kDefaultAlwaysUseFractionSeparator = false;
     9static const bool kDefaultKeepTrailingFractionZeros = false;
     10
     11
     12// flags
     13enum {
     14    MINIMAL_FRACTION_DIGITS_SET         = 0x01,
     15    MAXIMAL_FRACTION_DIGITS_SET         = 0x02,
     16    USE_UPPER_CASE_SET                  = 0x04,
     17    FLOAT_FORMAT_TYPE_SET               = 0x08,
     18    ALWAYS_USE_FRACTION_SEPARATOR_SET   = 0x10,
     19    KEEP_TRAILING_FRACTION_ZEROS_SET    = 0x20,
     20};
     21
     22// constructor
     23BFloatFormatParameters::BFloatFormatParameters(
     24    const BFloatFormatParameters *parent)
     25    : BNumberFormatParameters(parent),
     26      fParent(parent),
     27      fFlags(0)
     28{
     29}
     30
     31// copy constructor
     32BFloatFormatParameters::BFloatFormatParameters(
     33    const BFloatFormatParameters &other)
     34    : BNumberFormatParameters(other),
     35      fParent(other.fParent),
     36      fMinimalFractionDigits(other.fMinimalFractionDigits),
     37      fMaximalFractionDigits(other.fMaximalFractionDigits),
     38      fUseUpperCase(other.fUseUpperCase),
     39      fFloatFormatType(other.fFloatFormatType),
     40      fAlwaysUseFractionSeparator(other.fAlwaysUseFractionSeparator),
     41      fKeepTrailingFractionZeros(other.fKeepTrailingFractionZeros),
     42      fFlags(other.fFlags)
     43{
     44}
     45
     46// destructor
     47BFloatFormatParameters::~BFloatFormatParameters()
     48{
     49}
     50
     51// SetMinimalFractionDigits
     52void
     53BFloatFormatParameters::SetMinimalFractionDigits(size_t minFractionDigits)
     54{
     55    fMinimalFractionDigits = minFractionDigits;
     56    fFlags |= MINIMAL_FRACTION_DIGITS_SET;
     57}
     58
     59// MinimalFractionDigits
     60size_t
     61BFloatFormatParameters::MinimalFractionDigits() const
     62{
     63    if (fFlags & MINIMAL_FRACTION_DIGITS_SET)
     64        return fMinimalFractionDigits;
     65    if (fParent)
     66        return fParent->MinimalFractionDigits();
     67    return kDefaultMinimalFractionDigits;
     68}
     69
     70// SetMaximalFractionDigits
     71void
     72BFloatFormatParameters::SetMaximalFractionDigits(size_t maxFractionDigits)
     73{
     74    fMaximalFractionDigits = maxFractionDigits;
     75    fFlags |= MAXIMAL_FRACTION_DIGITS_SET;
     76}
     77
     78// MaximalFractionDigits
     79size_t
     80BFloatFormatParameters::MaximalFractionDigits() const
     81{
     82    if (fFlags & MAXIMAL_FRACTION_DIGITS_SET)
     83        return fMaximalFractionDigits;
     84    if (fParent)
     85        return fParent->MaximalFractionDigits();
     86    return kDefaultMaximalFractionDigits;
     87}
     88
     89// SetUseUpperCase
     90void
     91BFloatFormatParameters::SetUseUpperCase(bool useCapitals)
     92{
     93    fUseUpperCase = useCapitals;
     94    fFlags |= USE_UPPER_CASE_SET;
     95}
     96
     97// UseUpperCase
     98bool
     99BFloatFormatParameters::UseUpperCase() const
     100{
     101    if (fFlags & USE_UPPER_CASE_SET)
     102        return fUseUpperCase;
     103    if (fParent)
     104        return fParent->UseUpperCase();
     105    return kDefaultUseUpperCase;
     106}
     107
     108// SetFloatFormatType
     109void
     110BFloatFormatParameters::SetFloatFormatType(float_format_type type)
     111{
     112    fFloatFormatType = type;
     113    fFlags |= FLOAT_FORMAT_TYPE_SET;
     114}
     115
     116// FloatFormatType
     117float_format_type
     118BFloatFormatParameters::FloatFormatType() const
     119{
     120    if (fFlags & FLOAT_FORMAT_TYPE_SET)
     121        return fFloatFormatType;
     122    if (fParent)
     123        return fParent->FloatFormatType();
     124    return kDefaultFloatFormatType;
     125}
     126
     127// SetAlwaysUseFractionSeparator
     128void
     129BFloatFormatParameters::SetAlwaysUseFractionSeparator(
     130    bool alwaysUseFractionSeparator)
     131{
     132    fAlwaysUseFractionSeparator = alwaysUseFractionSeparator;
     133    fFlags |= ALWAYS_USE_FRACTION_SEPARATOR_SET;
     134}
     135
     136// AlwaysUseFractionSeparator
     137bool
     138BFloatFormatParameters::AlwaysUseFractionSeparator() const
     139{
     140    if (fFlags & ALWAYS_USE_FRACTION_SEPARATOR_SET)
     141        return fAlwaysUseFractionSeparator;
     142    if (fParent)
     143        return fParent->AlwaysUseFractionSeparator();
     144    return kDefaultAlwaysUseFractionSeparator;
     145}
     146
     147// SetKeepTrailingFractionZeros
     148void
     149BFloatFormatParameters::SetKeepTrailingFractionZeros(
     150    bool keepTrailingFractionZeros)
     151{
     152    fKeepTrailingFractionZeros = keepTrailingFractionZeros;
     153    fFlags |= KEEP_TRAILING_FRACTION_ZEROS_SET;
     154}
     155
     156// KeepTrailingFractionZeros
     157bool
     158BFloatFormatParameters::KeepTrailingFractionZeros() const
     159{
     160    if (fFlags & KEEP_TRAILING_FRACTION_ZEROS_SET)
     161        return fKeepTrailingFractionZeros;
     162    if (fParent)
     163        return fParent->KeepTrailingFractionZeros();
     164    return kDefaultKeepTrailingFractionZeros;
     165}
     166
     167// SetParentFloatParameters
     168void
     169BFloatFormatParameters::SetParentFloatParameters(
     170    const BFloatFormatParameters *parent)
     171{
     172    fParent = parent;
     173    SetParentNumberParameters(parent);
     174}
     175
     176// ParentFloatParameters
     177const BFloatFormatParameters *
     178BFloatFormatParameters::ParentFloatParameters() const
     179{
     180    return fParent;
     181}
     182
     183// =
     184BFloatFormatParameters &
     185BFloatFormatParameters::operator=(const BFloatFormatParameters &other)
     186{
     187    BNumberFormatParameters::operator=(other);
     188    fParent = other.fParent;
     189    fMinimalFractionDigits = other.fMinimalFractionDigits;
     190    fMaximalFractionDigits = other.fMaximalFractionDigits;
     191    fUseUpperCase = other.fUseUpperCase;
     192    fFloatFormatType = other.fFloatFormatType;
     193    fAlwaysUseFractionSeparator = other.fAlwaysUseFractionSeparator;
     194    fKeepTrailingFractionZeros = other.fKeepTrailingFractionZeros;
     195    fFlags = other.fFlags;
     196    return *this;
     197}
     198
  • src/kits/locale/Country.cpp

     
     1/*
     2** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
     3** Distributed under the terms of the OpenBeOS License.
     4*/
     5
     6
     7#include <Country.h>
     8#include <String.h>
     9
     10#include <monetary.h>
     11#include <stdarg.h>
     12
     13
     14const char *gStrings[] = {
     15    // date/time format
     16    "",
     17    "",
     18    "",
     19    "",
     20    // short date/time format
     21    "",
     22    "",
     23    "",
     24    "",
     25    // am/pm string
     26    "AM",
     27    "PM",
     28    // separators
     29    ".",
     30    ":",
     31    " ",
     32    ".",
     33    ",",
     34    // positive/negative sign
     35    "+",
     36    "-",
     37    // currency/monetary
     38    "US$"
     39    " "
     40    "."
     41    ","
     42};
     43
     44
     45BCountry::BCountry()
     46    :
     47    fStrings(gStrings)
     48{
     49}
     50
     51
     52BCountry::BCountry(const char **strings)
     53    :
     54    fStrings(strings)
     55{
     56}
     57
     58
     59BCountry::~BCountry()
     60{
     61}
     62
     63
     64const char *
     65BCountry::Name() const
     66{
     67    return "United States Of America";
     68}
     69
     70
     71const char *
     72BCountry::GetString(uint32 id) const
     73{
     74    if (id < B_COUNTRY_STRINGS_BASE || id >= B_NUM_COUNTRY_STRINGS)
     75        return NULL;
     76
     77    return gStrings[id - B_COUNTRY_STRINGS_BASE];
     78}
     79
     80
     81void
     82BCountry::FormatDate(char *string, size_t maxSize, time_t time, bool longFormat)
     83{
     84    // ToDo: implement us
     85}
     86
     87
     88void
     89BCountry::FormatDate(BString *string, time_t time, bool longFormat)
     90{
     91}
     92
     93
     94void
     95BCountry::FormatTime(char *string, size_t maxSize, time_t time, bool longFormat)
     96{
     97}
     98
     99
     100void
     101BCountry::FormatTime(BString *string, time_t time, bool longFormat)
     102{
     103}
     104
     105
     106const char *
     107BCountry::DateFormat(bool longFormat) const
     108{
     109    return fStrings[longFormat ? B_DATE_FORMAT : B_SHORT_DATE_FORMAT];
     110}
     111
     112
     113const char *
     114BCountry::TimeFormat(bool longFormat) const
     115{
     116    return fStrings[longFormat ? B_TIME_FORMAT : B_SHORT_TIME_FORMAT];
     117}
     118
     119
     120const char *
     121BCountry::DateSeparator() const
     122{
     123    return fStrings[B_DATE_SEPARATOR];
     124}
     125
     126
     127const char *
     128BCountry::TimeSeparator() const
     129{
     130    return fStrings[B_TIME_SEPARATOR];
     131}
     132
     133
     134void
     135BCountry::FormatNumber(char *string, size_t maxSize, double value)
     136{
     137}
     138
     139
     140void
     141BCountry::FormatNumber(BString *string, double value)
     142{
     143}
     144
     145
     146void
     147BCountry::FormatNumber(char *string, size_t maxSize, int32 value)
     148{
     149}
     150
     151
     152void
     153BCountry::FormatNumber(BString *string, int32 value)
     154{
     155}
     156
     157
     158const char *
     159BCountry::DecimalPoint() const
     160{
     161    return fStrings[B_DECIMAL_POINT];
     162}
     163
     164
     165const char *
     166BCountry::ThousandsSeparator() const
     167{
     168    return fStrings[B_THOUSANDS_SEPARATOR];
     169}
     170
     171
     172const char *
     173BCountry::Grouping() const
     174{
     175    return fStrings[B_GROUPING];
     176}
     177
     178
     179const char *
     180BCountry::PositiveSign() const
     181{
     182    return fStrings[B_POSITIVE_SIGN];
     183}
     184
     185
     186const char *
     187BCountry::NegativeSign() const
     188{
     189    return fStrings[B_NEGATIVE_SIGN];
     190}
     191
     192
     193int8
     194BCountry::Measurement() const
     195{
     196    return B_US;
     197}
     198
     199
     200ssize_t
     201BCountry::FormatMonetary(char *string, size_t maxSize, char *format, ...)
     202{
     203    va_list args;
     204    va_start(args,format);
     205
     206    ssize_t status = vstrfmon(string, maxSize, format, args);
     207
     208    va_end(args);
     209
     210    return status;
     211}
     212
     213
     214ssize_t
     215BCountry::FormatMonetary(BString *string, char *format, ...)
     216{
     217    return B_OK;
     218}
     219
     220
     221const char *
     222BCountry::CurrencySymbol() const
     223{
     224    return fStrings[B_CURRENCY_SYMBOL];
     225}
     226
     227
     228const char *
     229BCountry::InternationalCurrencySymbol() const
     230{
     231    return fStrings[B_INT_CURRENCY_SYMBOL];
     232}
     233
     234
     235const char *
     236BCountry::MonDecimalPoint() const
     237{
     238    return fStrings[B_MON_DECIMAL_POINT];
     239}
     240
     241
     242const char *
     243BCountry::MonThousandsSeparator() const
     244{
     245    return fStrings[B_MON_THOUSANDS_SEPARATOR];
     246}
     247
     248
     249const char *
     250BCountry::MonGrouping() const
     251{
     252    return fStrings[B_MON_GROUPING];
     253}
     254
     255
     256int32
     257BCountry::MonFracDigits() const
     258{
     259    return 2;
     260}
     261
  • src/kits/locale/IntegerFormat.cpp

     
     1#include <IntegerFormat.h>
     2#include <IntegerFormatImpl.h>
     3
     4// copy constructor
     5BIntegerFormat::BIntegerFormat(const BIntegerFormat &other)
     6    : BNumberFormat(other),
     7      BIntegerFormatParameters(other)
     8{
     9}
     10
     11// destructor
     12BIntegerFormat::~BIntegerFormat()
     13{
     14}
     15
     16// Format
     17status_t
     18BIntegerFormat::Format(int64 number, BString *buffer) const
     19{
     20    if (!fImpl)
     21        return B_NO_INIT;
     22    return IntegerFormatImpl()->Format(this, number, buffer);
     23}
     24
     25// Format
     26status_t
     27BIntegerFormat::Format(int64 number, BString *buffer,
     28                       format_field_position *positions, int32 positionCount,
     29                       int32 *fieldCount, bool allFieldPositions) const
     30{
     31    if (!fImpl)
     32        return B_NO_INIT;
     33    return IntegerFormatImpl()->Format(this,number, buffer, positions,
     34        positionCount, fieldCount, allFieldPositions);
     35}
     36
     37// =
     38BIntegerFormat &
     39BIntegerFormat::operator=(const BIntegerFormat &other)
     40{
     41    BNumberFormat::operator=(other);
     42    BIntegerFormatParameters::operator=(other);
     43    return *this;
     44}
     45
     46// constructor
     47BIntegerFormat::BIntegerFormat(BIntegerFormatImpl *impl)
     48    : BNumberFormat(impl),
     49      BIntegerFormatParameters(impl ? impl->DefaultIntegerFormatParameters()
     50                                    : NULL)
     51{
     52}
     53
     54// IntegerFormatImpl
     55inline
     56BIntegerFormatImpl *
     57BIntegerFormat::IntegerFormatImpl() const
     58{
     59    return static_cast<BIntegerFormatImpl*>(fImpl);
     60}
     61
  • src/kits/locale/cat.cpp

     
     1/*
     2** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
     3** Distributed under the terms of the OpenBeOS License.
     4*/
     5
     6
     7#include <nl_types.h>
     8
     9
     10nl_catd
     11catopen(const char *name, int oflag)
     12{
     13    return (nl_catd)1;
     14}
     15
     16
     17char *
     18catgets(nl_catd cat, int setID, int msgID, const char *defaultMessage)
     19{
     20    // should return "const char *"...
     21    return const_cast<char *>(defaultMessage);
     22}
     23
     24
     25int
     26catclose(nl_catd)
     27{
     28    return 0;
     29}
     30
  • src/kits/locale/UnicodeProperties.h

     
     1/*
     2** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
     3** Distributed under the terms of the OpenBeOS License.
     4*/
     5#ifndef _UNICODE_PROPERTIES_H_
     6#define _UNICODE_PROPERTIES_H_
     7
     8
     9#include <SupportDefs.h>
     10#include <ByteOrder.h>
     11
     12
     13#define PROPERTIES_DIRECTORY    "locale"
     14#define PROPERTIES_FILE_NAME    "unicode.properties"
     15#define PROPERTIES_FORMAT       'UPro'
     16
     17
     18typedef struct {
     19    uint8   size;
     20    uint8   isBigEndian;
     21    uint32  format;
     22    uint8   version[3];
     23} UnicodePropertiesHeader;
     24
     25#endif  /* _UNICODE_PROPERTIES_H_ */
  • src/kits/locale/Catalog.cpp

     
     1/*
     2** Distributed under the terms of the OpenBeOS License.
     3** Copyright 2003-2004. All rights reserved.
     4**
     5** Authors: Axel Dörfler, axeld@pinc-software.de
     6**          Oliver Tappe, zooey@hirschkaefer.de
     7*/
     8
     9#include <assert.h>
     10#include <syslog.h>
     11
     12#include <Application.h>
     13#include <Catalog.h>
     14#include <Locale.h>
     15#include <LocaleRoster.h>
     16#include <Node.h>
     17#include <Roster.h>
     18
     19
     20BCatalog* be_catalog = NULL;
     21    // catalog used by translation macros
     22BCatalog* be_app_catalog = NULL;
     23    // app-catalog (useful for accessing app's catalog from inside an add-on,
     24    // since in an add-on, be_catalog will hold the add-on's catalog.
     25
     26
     27//#pragma mark - BCatalog
     28BCatalog::BCatalog()
     29    :
     30    fCatalog(NULL)
     31{
     32}
     33
     34
     35BCatalog::BCatalog(const char *signature, const char *language,
     36    int32 fingerprint)
     37{
     38    fCatalog = be_locale_roster->LoadCatalog(signature, language, fingerprint);
     39}
     40
     41
     42BCatalog::~BCatalog()
     43{
     44    if (be_catalog == this)
     45        be_app_catalog = be_catalog = NULL;
     46    be_locale_roster->UnloadCatalog(fCatalog);
     47}
     48
     49
     50const char *
     51BCatalog::GetString(const char *string, const char *context, const char *comment)
     52{
     53    const char *translated;
     54    for (BCatalogAddOn* cat = fCatalog; cat != NULL; cat = cat->fNext) {
     55        translated = cat->GetString(string, context, comment);
     56        if (translated)
     57            return translated;
     58    }
     59    return string;
     60}
     61
     62
     63const char *
     64BCatalog::GetString(uint32 id)
     65{
     66    const char *translated;
     67    for (BCatalogAddOn* cat = fCatalog; cat != NULL; cat = cat->fNext) {
     68        translated = cat->GetString(id);
     69        if (translated)
     70            return translated;
     71    }
     72    return "";
     73}
     74
     75
     76status_t
     77BCatalog::GetData(const char *name, BMessage *msg)
     78{
     79    if (!fCatalog)
     80        return B_NO_INIT;
     81    status_t res;
     82    for (BCatalogAddOn* cat = fCatalog; cat != NULL; cat = cat->fNext) {
     83        res = cat->GetData(name, msg);
     84        if (res != B_NAME_NOT_FOUND && res != EOPNOTSUPP)
     85            return res;
     86                // return B_OK if found, or specific error-code
     87    }
     88    return B_NAME_NOT_FOUND;
     89}
     90
     91
     92status_t
     93BCatalog::GetData(uint32 id, BMessage *msg)
     94{
     95    if (!fCatalog)
     96        return B_NO_INIT;
     97    status_t res;
     98    for (BCatalogAddOn* cat = fCatalog; cat != NULL; cat = cat->fNext) {
     99        res = cat->GetData(id, msg);
     100        if (res != B_NAME_NOT_FOUND && res != EOPNOTSUPP)
     101            return res;
     102                // return B_OK if found, or specific error-code
     103    }
     104    return B_NAME_NOT_FOUND;
     105}
     106
     107
     108status_t
     109BCatalog::GetAppCatalog(BCatalog* catalog)
     110{
     111    app_info appInfo;
     112    if (!be_app || be_app->GetAppInfo(&appInfo) != B_OK)
     113        return B_ENTRY_NOT_FOUND;
     114    BString sig(appInfo.signature);
     115
     116    // drop supertype from mimetype (should be "application/"):
     117    int32 pos = sig.FindFirst('/');
     118    if (pos >= 0)
     119        sig.Remove(0, pos+1);
     120
     121    // try to fetch fingerprint from app-file (attribute):
     122    int32 fingerprint = 0;
     123    BNode appNode(&appInfo.ref);
     124    appNode.ReadAttr(BLocaleRoster::kCatFingerprintAttr, B_INT32_TYPE, 0,
     125        &fingerprint, sizeof(int32));
     126    // try to load catalog (with given fingerprint):
     127    catalog->fCatalog
     128        = be_locale_roster->LoadCatalog(sig.String(), NULL, fingerprint);
     129
     130    // load native embedded id-based catalog. If such a catalog exists,
     131    // we can fall back to native strings for id-based access, too.
     132    BCatalogAddOn *embeddedCatalog
     133        = be_locale_roster->LoadEmbeddedCatalog(&appInfo.ref);
     134    if (embeddedCatalog) {
     135        if (!catalog->fCatalog)
     136            // embedded catalog is the only catalog that was found:
     137            catalog->fCatalog = embeddedCatalog;
     138        else {
     139            // append embedded catalog to list of loaded catalogs:
     140            BCatalogAddOn *currCat = catalog->fCatalog;
     141            while (currCat->fNext)
     142                currCat = currCat->fNext;
     143            currCat->fNext = embeddedCatalog;
     144        }
     145    }
     146
     147    // make app-catalog the current catalog for translation-macros:
     148    be_app_catalog = be_catalog = catalog;
     149
     150    return catalog->InitCheck();
     151}
     152
     153
     154//#pragma mark - BCatalogAddOn
     155BCatalogAddOn::BCatalogAddOn(const char *signature, const char *language,
     156    int32 fingerprint)
     157    :
     158    fInitCheck(B_NO_INIT),
     159    fSignature(signature),
     160    fLanguageName(language),
     161    fFingerprint(fingerprint),
     162    fNext(NULL)
     163{
     164    fLanguageName.ToLower();
     165        // canonicalize language-name to lowercase
     166}
     167
     168
     169BCatalogAddOn::~BCatalogAddOn()
     170{
     171}
     172
     173
     174void
     175BCatalogAddOn::UpdateFingerprint()
     176{
     177    fFingerprint = 0;
     178        // base implementation always yields the same fingerprint,
     179        // which means that no version-mismatch detection is possible.
     180}
     181
     182
     183status_t
     184BCatalogAddOn::InitCheck() const
     185{
     186    return fInitCheck;
     187}
     188
     189
     190bool
     191BCatalogAddOn::CanHaveData() const
     192{
     193    return false;
     194}
     195
     196
     197status_t
     198BCatalogAddOn::GetData(const char *name, BMessage *msg)
     199{
     200    return EOPNOTSUPP;
     201}
     202
     203
     204status_t
     205BCatalogAddOn::GetData(uint32 id, BMessage *msg)
     206{
     207    return EOPNOTSUPP;
     208}
     209
     210
     211status_t
     212BCatalogAddOn::SetString(const char *string, const char *translated,
     213    const char *context, const char *comment)
     214{
     215    return EOPNOTSUPP;
     216}
     217
     218
     219status_t
     220BCatalogAddOn::SetString(int32 id, const char *translated)
     221{
     222    return EOPNOTSUPP;
     223}
     224
     225
     226bool
     227BCatalogAddOn::CanWriteData() const
     228{
     229    return false;
     230}
     231
     232
     233status_t
     234BCatalogAddOn::SetData(const char *name, BMessage *msg)
     235{
     236    return EOPNOTSUPP;
     237}
     238
     239
     240status_t
     241BCatalogAddOn::SetData(uint32 id, BMessage *msg)
     242{
     243    return EOPNOTSUPP;
     244}
     245
     246
     247status_t
     248BCatalogAddOn::ReadFromFile(const char *path)
     249{
     250    return EOPNOTSUPP;
     251}
     252
     253
     254status_t
     255BCatalogAddOn::ReadFromAttribute(entry_ref *appOrAddOnRef)
     256{
     257    return EOPNOTSUPP;
     258}
     259
     260
     261status_t
     262BCatalogAddOn::ReadFromResource(entry_ref *appOrAddOnRef)
     263{
     264    return EOPNOTSUPP;
     265}
     266
     267
     268status_t
     269BCatalogAddOn::WriteToFile(const char *path)
     270{
     271    return EOPNOTSUPP;
     272}
     273
     274
     275status_t
     276BCatalogAddOn::WriteToAttribute(entry_ref *appOrAddOnRef)
     277{
     278    return EOPNOTSUPP;
     279}
     280
     281
     282status_t
     283BCatalogAddOn::WriteToResource(entry_ref *appOrAddOnRef)
     284{
     285    assert(0);
     286    return EOPNOTSUPP;
     287}
     288
     289
     290void BCatalogAddOn::MakeEmpty()
     291{
     292}
     293
     294
     295int32
     296BCatalogAddOn::CountItems() const
     297{
     298    return 0;
     299}
     300
     301
     302//#pragma mark - EditableCatalog
     303namespace BPrivate {
     304EditableCatalog::EditableCatalog(const char *type, const char *signature,
     305    const char *language)
     306{
     307    fCatalog = be_locale_roster->CreateCatalog(type, signature, language);
     308}
     309
     310
     311EditableCatalog::~EditableCatalog()
     312{
     313}
     314
     315
     316status_t
     317EditableCatalog::SetString(const char *string, const char *translated,
     318    const char *context, const char *comment)
     319{
     320    if (!fCatalog)
     321        return B_NO_INIT;
     322    return fCatalog->SetString(string, translated, context, comment);
     323}
     324
     325
     326status_t
     327EditableCatalog::SetString(int32 id, const char *translated)
     328{
     329    if (!fCatalog)
     330        return B_NO_INIT;
     331    return fCatalog->SetString(id, translated);
     332}
     333
     334
     335bool
     336EditableCatalog::CanWriteData() const
     337{
     338    if (!fCatalog)
     339        return false;
     340    return fCatalog->CanWriteData();
     341}
     342
     343
     344status_t
     345EditableCatalog::SetData(const char *name, BMessage *msg)
     346{
     347    if (!fCatalog)
     348        return B_NO_INIT;
     349    return fCatalog->SetData(name, msg);
     350}
     351
     352
     353status_t
     354EditableCatalog::SetData(uint32 id, BMessage *msg)
     355{
     356    if (!fCatalog)
     357        return B_NO_INIT;
     358    return fCatalog->SetData(id, msg);
     359}
     360
     361
     362status_t
     363EditableCatalog::ReadFromFile(const char *path)
     364{
     365    if (!fCatalog)
     366        return B_NO_INIT;
     367    return fCatalog->ReadFromFile(path);
     368}
     369
     370
     371status_t
     372EditableCatalog::ReadFromAttribute(entry_ref *appOrAddOnRef)
     373{
     374    if (!fCatalog)
     375        return B_NO_INIT;
     376    return fCatalog->ReadFromAttribute(appOrAddOnRef);
     377}
     378
     379
     380status_t
     381EditableCatalog::ReadFromResource(entry_ref *appOrAddOnRef)
     382{
     383    if (!fCatalog)
     384        return B_NO_INIT;
     385    return fCatalog->ReadFromResource(appOrAddOnRef);
     386}
     387
     388
     389status_t
     390EditableCatalog::WriteToFile(const char *path)
     391{
     392    if (!fCatalog)
     393        return B_NO_INIT;
     394    return fCatalog->WriteToFile(path);
     395}
     396
     397
     398status_t
     399EditableCatalog::WriteToAttribute(entry_ref *appOrAddOnRef)
     400{
     401    if (!fCatalog)
     402        return B_NO_INIT;
     403    return fCatalog->WriteToAttribute(appOrAddOnRef);
     404}
     405
     406
     407status_t
     408EditableCatalog::WriteToResource(entry_ref *appOrAddOnRef)
     409{
     410    if (!fCatalog)
     411        return B_NO_INIT;
     412    return fCatalog->WriteToResource(appOrAddOnRef);
     413}
     414
     415
     416void EditableCatalog::MakeEmpty()
     417{
     418    if (fCatalog)
     419        fCatalog->MakeEmpty();
     420}
     421
     422
     423} // namespace BPrivate
  • src/kits/locale/FloatFormat.cpp

     
     1#include <FloatFormat.h>
     2#include <FloatFormatImpl.h>
     3
     4// copy constructor
     5BFloatFormat::BFloatFormat(const BFloatFormat &other)
     6    : BNumberFormat(other),
     7      BFloatFormatParameters(other)
     8{
     9}
     10
     11// destructor
     12BFloatFormat::~BFloatFormat()
     13{
     14}
     15
     16// Format
     17status_t
     18BFloatFormat::Format(double number, BString *buffer) const
     19{
     20    if (!fImpl)
     21        return B_NO_INIT;
     22    return FloatFormatImpl()->Format(this, number, buffer);
     23}
     24
     25// Format
     26status_t
     27BFloatFormat::Format(double number, BString *buffer,
     28                     format_field_position *positions, int32 positionCount,
     29                     int32 *fieldCount, bool allFieldPositions) const
     30{
     31    if (!fImpl)
     32        return B_NO_INIT;
     33    return FloatFormatImpl()->Format(this,number, buffer, positions,
     34        positionCount, fieldCount, allFieldPositions);
     35}
     36
     37// =
     38BFloatFormat &
     39BFloatFormat::operator=(const BFloatFormat &other)
     40{
     41    BNumberFormat::operator=(other);
     42    BFloatFormatParameters::operator=(other);
     43    return *this;
     44}
     45
     46// constructor
     47BFloatFormat::BFloatFormat(BFloatFormatImpl *impl)
     48    : BNumberFormat(impl),
     49      BFloatFormatParameters(impl ? impl->DefaultFloatFormatParameters()
     50                                    : NULL)
     51{
     52}
     53
     54// FloatFormatImpl
     55inline
     56BFloatFormatImpl *
     57BFloatFormat::FloatFormatImpl() const
     58{
     59    return static_cast<BFloatFormatImpl*>(fImpl);
     60}
     61
  • src/kits/locale/Collator.cpp

     
     1/*
     2** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
     3** Distributed under the terms of the OpenBeOS License.
     4*/
     5
     6
     7#include <Collator.h>
     8#include <UnicodeChar.h>
     9#include <String.h>
     10#include <Message.h>
     11
     12#include <typeinfo>
     13#include <ctype.h>
     14
     15
     16// conversion array for character ranges 192 - 223 & 224 - 255
     17static const uint8 kNoDiacrits[] = {
     18    'a','a','a','a','a','a','a',
     19    'c',
     20    'e','e','e','e',
     21    'i','i','i','i',
     22    240,    // eth
     23    'n',
     24    'o','o','o','o','o',
     25    247,    //
     26    'o',
     27    'u','u','u','u',
     28    'y',
     29    254,    // thorn
     30    'y'
     31};
     32
     33
     34static inline uint32
     35getPrimaryChar(uint32 c)
     36{
     37    if (c < 0x80)
     38        return tolower(c);
     39
     40    // this automatically returns lowercase letters
     41    if (c >= 192 && c < 223)
     42        return kNoDiacrits[c - 192];
     43    if (c == 223)   // ß
     44        return 's';
     45    if (c >= 224 && c < 256)
     46        return kNoDiacrits[c - 224];
     47
     48    return BUnicodeChar::ToLower(c);
     49}
     50
     51
     52BCollatorAddOn::input_context::input_context(bool ignorePunctuation)
     53    :
     54    ignore_punctuation(ignorePunctuation),
     55    next_char(0),
     56    reserved1(0),
     57    reserved2(0)
     58{
     59}
     60
     61
     62//  #pragma mark -
     63
     64
     65BCollator::BCollator()
     66    :
     67    fCollatorImage(B_ERROR),
     68    fStrength(B_COLLATE_PRIMARY),
     69    fIgnorePunctuation(true)
     70{
     71    // ToDo: the collator construction will have to change; the default
     72    //  collator should be constructed by the Locale/LocaleRoster, so we
     73    //  only need a constructor where you specify all details
     74
     75    fCollator = new BCollatorAddOn();
     76}
     77
     78
     79BCollator::BCollator(BCollatorAddOn *collator, int8 strength, bool ignorePunctuation)
     80    :
     81    fCollator(collator),
     82    fCollatorImage(B_ERROR),
     83    fStrength(strength),
     84    fIgnorePunctuation(ignorePunctuation)
     85{
     86    if (collator == NULL)
     87        fCollator = new BCollatorAddOn();
     88}
     89
     90
     91BCollator::BCollator(BMessage *archive)
     92    : BArchivable(archive),
     93    fCollator(NULL),
     94    fCollatorImage(B_ERROR)
     95{
     96    int32 data;
     97    if (archive->FindInt32("loc:strength", &data) == B_OK)
     98        fStrength = (uint8)data;
     99    else
     100        fStrength = B_COLLATE_PRIMARY;
     101
     102    if (archive->FindBool("loc:punctuation", &fIgnorePunctuation) != B_OK)
     103        fIgnorePunctuation = true;
     104
     105    BMessage collatorArchive;
     106    if (archive->FindMessage("loc:collator", &collatorArchive) == B_OK) {
     107        BArchivable *unarchived = instantiate_object(&collatorArchive, &fCollatorImage);
     108
     109        // do we really have a BCollatorAddOn here?
     110        fCollator = dynamic_cast<BCollatorAddOn *>(unarchived);
     111        if (fCollator == NULL)
     112            delete unarchived;
     113    }
     114
     115    if (fCollator == NULL) {
     116        fCollator = new BCollatorAddOn();
     117        fCollatorImage = B_ERROR;
     118    }
     119}
     120
     121
     122BCollator::~BCollator()
     123{
     124    delete fCollator;
     125
     126    if (fCollatorImage >= B_OK)
     127        unload_add_on(fCollatorImage);
     128}
     129
     130
     131void
     132BCollator::SetDefaultStrength(int8 strength)
     133{
     134    fStrength = strength;
     135}
     136
     137
     138int8
     139BCollator::DefaultStrength() const
     140{
     141    return fStrength;
     142}
     143
     144
     145void
     146BCollator::SetIgnorePunctuation(bool ignore)
     147{
     148    fIgnorePunctuation = ignore;
     149}
     150
     151
     152bool
     153BCollator::IgnorePunctuation() const
     154{
     155    return fIgnorePunctuation;
     156}
     157
     158
     159status_t
     160BCollator::GetSortKey(const char *string, BString *key, int8 strength)
     161{
     162    if (strength == B_COLLATE_DEFAULT)
     163        strength = fStrength;
     164
     165    return fCollator->GetSortKey(string, key, strength, fIgnorePunctuation);
     166}
     167
     168
     169int
     170BCollator::Compare(const char *a, const char *b, int32 length, int8 strength)
     171{
     172    if (length == -1)   // match the whole string
     173        length = 0x7fffffff;
     174
     175    return fCollator->Compare(a, b, length,
     176                strength == B_COLLATE_DEFAULT ? fStrength : strength, fIgnorePunctuation);
     177}
     178
     179
     180status_t
     181BCollator::Archive(BMessage *archive, bool deep) const
     182{
     183    status_t status = BArchivable::Archive(archive, deep);
     184    if (status < B_OK)
     185        return status;
     186
     187    if (status == B_OK)
     188        status = archive->AddInt32("loc:strength", fStrength);
     189    if (status == B_OK)
     190        status = archive->AddBool("loc:punctuation", fIgnorePunctuation);
     191
     192    BMessage collatorArchive;
     193    if (status == B_OK && deep
     194        && typeid(*fCollator) != typeid(BCollatorAddOn)
     195            // only archive subclasses from BCollatorAddOn
     196        && (status = fCollator->Archive(&collatorArchive, true)) == B_OK)
     197        status = archive->AddMessage("loc:collator", &collatorArchive);
     198
     199    return status;
     200}
     201
     202
     203BArchivable *
     204BCollator::Instantiate(BMessage *archive)
     205{
     206    if (validate_instantiation(archive, "BCollator"))
     207        return new BCollator(archive);
     208
     209    return NULL;
     210}
     211
     212
     213//  #pragma mark -
     214
     215
     216BCollatorAddOn::BCollatorAddOn()
     217{
     218}
     219
     220
     221BCollatorAddOn::BCollatorAddOn(BMessage *archive)
     222    : BArchivable(archive)
     223{
     224}
     225
     226
     227BCollatorAddOn::~BCollatorAddOn()
     228{
     229}
     230
     231
     232/** This returns the next Unicode character from the UTF-8 encoded
     233 *  input string, and bumps it to the next character.
     234 *  It will ignore punctuation if specified by the context, and
     235 *  might substitute characters if needed.
     236 */
     237
     238uint32
     239BCollatorAddOn::GetNextChar(const char **string, input_context &context)
     240{
     241    uint32 c = context.next_char;
     242    if (c != 0) {
     243        context.next_char = 0;
     244        return c;
     245    }
     246
     247    do {
     248        c = BUnicodeChar::FromUTF8(string);
     249    } while (context.ignore_punctuation
     250        && (BUnicodeChar::IsPunctuation(c) || BUnicodeChar::IsSpace(c)));
     251
     252    if (c == 223) {
     253        context.next_char = 's';
     254        return 's';
     255    }
     256
     257    return c;
     258}
     259
     260
     261/** Fills the specified buffer with the primary sort key. The buffer
     262 *  has to be long enough to hold the key.
     263 *  It returns the position in the buffer immediately after the key;
     264 *  it does not add a terminating null byte!
     265 */
     266
     267char *
     268BCollatorAddOn::PutPrimaryKey(const char *string, char *buffer, int32 length,
     269    bool ignorePunctuation)
     270{
     271    input_context context(ignorePunctuation);
     272
     273    uint32 c;
     274    for (int32 i = 0; (c = GetNextChar(&string, context)) != 0 && i < length; i++) {
     275        if (c < 0x80)
     276            *buffer++ = tolower(c);
     277        else
     278            BUnicodeChar::ToUTF8(getPrimaryChar(c), &buffer);
     279    }
     280
     281    return buffer;
     282}
     283
     284
     285size_t
     286BCollatorAddOn::PrimaryKeyLength(size_t length)
     287{
     288    return length * 2;
     289        // the primary key needs to make space for doubled characters (like 'ß')
     290}
     291
     292
     293status_t
     294BCollatorAddOn::GetSortKey(const char *string, BString *key, int8 strength,
     295    bool ignorePunctuation)
     296{
     297    if (strength >= B_COLLATE_QUATERNARY) {
     298        // the difference between tertiary and quaternary collation strength
     299        // are usually a different handling of punctuation characters
     300        ignorePunctuation = false;
     301    }
     302
     303    size_t length = strlen(string);
     304
     305    switch (strength) {
     306        case B_COLLATE_PRIMARY:
     307        {
     308            char *begin = key->LockBuffer(PrimaryKeyLength(length));
     309            if (begin == NULL)
     310                return B_NO_MEMORY;
     311
     312            char *end = PutPrimaryKey(string, begin, length, ignorePunctuation);
     313            *end = '\0';
     314
     315            key->UnlockBuffer(end - begin);
     316            break;
     317        }
     318
     319        case B_COLLATE_SECONDARY:
     320        {
     321            char *begin = key->LockBuffer(PrimaryKeyLength(length) + length + 1);
     322                // the primary key + the secondary key + separator char
     323            if (begin == NULL)
     324                return B_NO_MEMORY;
     325
     326            char *buffer = PutPrimaryKey(string, begin, length, ignorePunctuation);
     327            *buffer++ = '\01';
     328                // separator
     329
     330            input_context context(ignorePunctuation);
     331            uint32 c;
     332            for (uint32 i = 0; (c = GetNextChar(&string, context)) && i < length; i++) {
     333                if (c < 0x80)
     334                    *buffer++ = tolower(c);
     335                else
     336                    BUnicodeChar::ToUTF8(BUnicodeChar::ToLower(c), &buffer);
     337            }
     338            *buffer = '\0';
     339
     340            key->UnlockBuffer(buffer - begin);
     341            break;
     342        }
     343
     344        case B_COLLATE_TERTIARY:
     345        case B_COLLATE_QUATERNARY:
     346        {
     347            char *begin = key->LockBuffer(PrimaryKeyLength(length) + length + 1);
     348                // the primary key + the tertiary key + separator char
     349            if (begin == NULL)
     350                return B_NO_MEMORY;
     351
     352            char *buffer = PutPrimaryKey(string, begin, length, ignorePunctuation);
     353            *buffer++ = '\01';
     354                // separator
     355
     356            input_context context(ignorePunctuation);
     357            uint32 c;
     358            for (uint32 i = 0; (c = GetNextChar(&string, context)) && i < length; i++) {
     359                BUnicodeChar::ToUTF8(c, &buffer);
     360            }
     361            *buffer = '\0';
     362
     363            key->UnlockBuffer(buffer + length - begin);
     364            break;
     365        }
     366
     367        case B_COLLATE_IDENTICAL:
     368        default:
     369            key->SetTo(string, length);
     370                // is there any way to check if BString::SetTo() actually succeeded?
     371            break;
     372    }
     373    return B_OK;
     374}
     375
     376
     377int
     378BCollatorAddOn::Compare(const char *a, const char *b, int32 length, int8 strength,
     379    bool ignorePunctuation)
     380{
     381    if (strength >= B_COLLATE_QUATERNARY) {
     382        // the difference between tertiary and quaternary collation strength
     383        // are usually a different handling of punctuation characters
     384        ignorePunctuation = false;
     385    }
     386
     387    input_context contextA(ignorePunctuation);
     388    input_context contextB(ignorePunctuation);
     389
     390    switch (strength) {
     391        case B_COLLATE_PRIMARY:
     392        {
     393            for (int32 i = 0; i < length; i++) {
     394                uint32 charA = GetNextChar(&a, contextA);
     395                uint32 charB = GetNextChar(&b, contextB);
     396                if (charA == 0)
     397                    return charB == 0 ? 0 : -(int32)charB;
     398                else if (charB == 0)
     399                    return (int32)charA;
     400
     401                charA = getPrimaryChar(charA);
     402                charB = getPrimaryChar(charB);
     403
     404                if (charA != charB)
     405                    return (int32)charA - (int32)charB;
     406            }
     407            return 0;
     408        }
     409
     410        case B_COLLATE_SECONDARY:
     411        {
     412            // diacriticals can only change the order between equal strings
     413            int32 compare = Compare(a, b, length, B_COLLATE_PRIMARY, ignorePunctuation);
     414            if (compare != 0)
     415                return compare;
     416
     417            for (int32 i = 0; i < length; i++) {
     418                uint32 charA = BUnicodeChar::ToLower(GetNextChar(&a, contextA));
     419                uint32 charB = BUnicodeChar::ToLower(GetNextChar(&b, contextB));
     420
     421                // the two strings does have the same size when we get here
     422                if (charA == 0)
     423                    return 0;
     424
     425                if (charA != charB)
     426                    return (int32)charA - (int32)charB;
     427            }
     428            return 0;
     429        }
     430
     431        case B_COLLATE_TERTIARY:
     432        case B_COLLATE_QUATERNARY:
     433        {
     434            // diacriticals can only change the order between equal strings
     435            int32 compare = Compare(a, b, length, B_COLLATE_PRIMARY, ignorePunctuation);
     436            if (compare != 0)
     437                return compare;
     438
     439            for (int32 i = 0; i < length; i++) {
     440                uint32 charA = GetNextChar(&a, contextA);
     441                uint32 charB = GetNextChar(&b, contextB);
     442
     443                // the two strings does have the same size when we get here
     444                if (charA == 0)
     445                    return 0;
     446
     447                if (charA != charB)
     448                    return (int32)charA - (int32)charB;
     449            }
     450            return 0;
     451        }
     452
     453        case B_COLLATE_IDENTICAL:
     454        default:
     455            return strncmp(a, b, length);
     456    }
     457}
     458
     459
     460status_t
     461BCollatorAddOn::Archive(BMessage *archive, bool deep) const
     462{
     463    return BArchivable::Archive(archive, deep);
     464}
     465
     466
     467BArchivable *
     468BCollatorAddOn::Instantiate(BMessage *archive)
     469{
     470    if (validate_instantiation(archive, "BCollatorAddOn"))
     471        return new BCollatorAddOn(archive);
     472
     473    return NULL;
     474}
     475
  • src/kits/locale/OpenHashTable.h

     
     1/*
     2Open Tracker License
     3
     4Terms and Conditions
     5
     6Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
     7
     8Permission is hereby granted, free of charge, to any person obtaining a copy of
     9this software and associated documentation files (the "Software"), to deal in
     10the Software without restriction, including without limitation the rights to
     11use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
     12of the Software, and to permit persons to whom the Software is furnished to do
     13so, subject to the following conditions:
     14
     15The above copyright notice and this permission notice applies to all licensees
     16and shall be included in all copies or substantial portions of the Software.
     17
     18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
     20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     21BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
     23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     24
     25Except as contained in this notice, the name of Be Incorporated shall not be
     26used in advertising or otherwise to promote the sale, use or other dealings in
     27this Software without prior written authorization from Be Incorporated.
     28
     29Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
     30of Be Incorporated in the United States and other countries. Other brand product
     31names are registered trademarks or trademarks of their respective holders.
     32All rights reserved.
     33*/
     34
     35// Hash table with open addresssing
     36
     37#ifndef __OPEN_HASH_TABLE__
     38#define __OPEN_HASH_TABLE__
     39
     40#include <malloc.h>
     41#include <new.h>
     42
     43namespace BPrivate {
     44
     45template <class Element>
     46class ElementVector {
     47    // element vector for OpenHashTable needs to implement this
     48    // interface
     49    public:
     50        Element &At(int32 index);
     51        Element *Add();
     52        int32 IndexOf(const Element &) const;
     53        void Remove(int32 index);
     54};
     55
     56class OpenHashElement {
     57    public:
     58        uint32 Hash() const;
     59        bool operator==(const OpenHashElement &) const;
     60        void Adopt(OpenHashElement &);
     61            // low overhead copy, original element is in undefined state
     62            // after call (calls Adopt on BString members, etc.)
     63        int32 fNext;
     64};
     65
     66const uint32 kPrimes [] = {
     67    509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139,
     68    524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393, 67108859,
     69    134217689, 268435399, 536870909, 1073741789, 2147483647, 0
     70};
     71
     72template <class Element, class ElementVec = ElementVector<Element> >
     73class OpenHashTable {
     74    public:
     75        OpenHashTable(int32 minSize, ElementVec *elementVector = 0);
     76            // it is up to the subclass of OpenHashTable to supply
     77            // elementVector
     78        ~OpenHashTable();
     79
     80        void SetElementVector(ElementVec *elementVector);
     81
     82        Element *FindFirst(uint32 elementHash) const;
     83        Element &Add(uint32 elementHash);
     84
     85        void Remove(Element *);
     86
     87        // when calling Add, any outstanding element pointer may become
     88        // invalid; to deal with this, get the element index and restore
     89        // it after the add
     90        int32 ElementIndex(const Element *) const;
     91        Element *ElementAt(int32 index) const;
     92
     93        int32 VectorSize() const;
     94
     95    protected:
     96        static int32 OptimalSize(int32 minSize);
     97
     98        int32 fArraySize;
     99        int32 *fHashArray;
     100        ElementVec *fElementVector;
     101};
     102
     103
     104template <class Element>
     105class OpenHashElementArray : public ElementVector<Element> {
     106    // this is a straightforward implementation of an element vector
     107    // deleting is handled by linking deleted elements into a free list
     108    // the vector never shrinks
     109    public:
     110        OpenHashElementArray(int32 initialSize);
     111        ~OpenHashElementArray();
     112
     113        Element &At(int32 index);
     114        const Element &At(int32 index) const;
     115        int32 Add(const Element &);
     116        int32 Add();
     117        void Remove(int32 index);
     118        int32 IndexOf(const Element &) const;
     119        int32 Size() const;
     120
     121    private:
     122        Element *fData;
     123        int32 fSize;
     124        int32 fNextFree;
     125        int32 fNextDeleted;
     126};
     127
     128
     129//--- inline implementation --------------------------------
     130
     131
     132template<class Element, class ElementVec>
     133OpenHashTable<Element, ElementVec>::OpenHashTable(int32 minSize,ElementVec *elementVector)
     134    :
     135    fArraySize(OptimalSize(minSize)),
     136    fElementVector(elementVector)
     137{
     138    fHashArray = new int32[fArraySize];
     139    for (int32 index = 0; index < fArraySize; index++)
     140        fHashArray[index] = -1;
     141}
     142
     143
     144template<class Element, class ElementVec>
     145OpenHashTable<Element, ElementVec>::~OpenHashTable()
     146{
     147    delete fHashArray;
     148}
     149
     150
     151template<class Element, class ElementVec>
     152int32
     153OpenHashTable<Element, ElementVec>::OptimalSize(int32 minSize)
     154{
     155    for (int32 index = 0; ; index++)
     156        if (!kPrimes[index] || kPrimes[index] >= (uint32)minSize)
     157            return (int32)kPrimes[index];
     158
     159    return 0;
     160}
     161
     162
     163template<class Element, class ElementVec>
     164Element *
     165OpenHashTable<Element, ElementVec>::FindFirst(uint32 hash) const
     166{
     167    ASSERT(fElementVector);
     168    hash %= fArraySize;
     169    if (fHashArray[hash] < 0)
     170        return 0;
     171   
     172    return &fElementVector->At(fHashArray[hash]);
     173}
     174
     175
     176template<class Element, class ElementVec>
     177int32
     178OpenHashTable<Element, ElementVec>::ElementIndex(const Element *element) const
     179{
     180    return fElementVector->IndexOf(*element);
     181}
     182
     183
     184template<class Element, class ElementVec>
     185Element *
     186OpenHashTable<Element, ElementVec>::ElementAt(int32 index) const
     187{
     188    return &fElementVector->At(index);
     189}
     190
     191
     192template<class Element, class ElementVec>
     193int32
     194OpenHashTable<Element, ElementVec>::VectorSize() const
     195{
     196     return fElementVector->Size();
     197}
     198
     199
     200template<class Element, class ElementVec>
     201Element &
     202OpenHashTable<Element, ElementVec>::Add(uint32 hash)
     203{
     204    ASSERT(fElementVector);
     205    hash %= fArraySize;
     206    Element &result = *fElementVector->Add();
     207    result.fNext = fHashArray[hash];
     208    fHashArray[hash] = fElementVector->IndexOf(result);
     209    return result;
     210}
     211
     212
     213template<class Element, class ElementVec>
     214void
     215OpenHashTable<Element, ElementVec>::Remove(Element *element)
     216{
     217    uint32 hash = element->Hash() % fArraySize;
     218    int32 next = fHashArray[hash];
     219    ASSERT(next >= 0);
     220
     221    if (&fElementVector->At(next) == element) {
     222        fHashArray[hash] = element->fNext;
     223        fElementVector->Remove(next);
     224        return;
     225    }
     226
     227    for (int32 index = next; index >= 0; ) {
     228        // look for an existing match in table
     229        int32 next = fElementVector->At(index).fNext;
     230        if (next < 0) {
     231            TRESPASS();
     232            return;
     233        }
     234
     235        if (&fElementVector->At(next) == element) {
     236            fElementVector->At(index).fNext = element->fNext;
     237            fElementVector->Remove(next);
     238            return;
     239        }
     240        index = next;
     241    }
     242}
     243
     244
     245template<class Element, class ElementVec>
     246void
     247OpenHashTable<Element, ElementVec>::SetElementVector(ElementVec *elementVector)
     248{
     249    fElementVector = elementVector;
     250}
     251
     252
     253template<class Element>
     254OpenHashElementArray<Element>::OpenHashElementArray(int32 initialSize)
     255    :
     256    fSize(initialSize),
     257    fNextFree(0),
     258    fNextDeleted(-1)
     259{
     260    fData = (Element *)calloc((size_t)initialSize , sizeof(Element));
     261    if (!fData)
     262        throw bad_alloc();
     263}
     264
     265
     266template<class Element>
     267OpenHashElementArray<Element>::~OpenHashElementArray()
     268{
     269    free(fData);
     270}
     271
     272
     273template<class Element>
     274Element &
     275OpenHashElementArray<Element>::At(int32 index)
     276{
     277    ASSERT(index < fSize);
     278    return fData[index];
     279}
     280
     281
     282template<class Element>
     283const Element &
     284OpenHashElementArray<Element>::At(int32 index) const
     285{
     286    ASSERT(index < fSize);
     287    return fData[index];
     288}
     289
     290
     291template<class Element>
     292int32
     293OpenHashElementArray<Element>::IndexOf(const Element &element) const
     294{
     295    int32 result = &element - fData;
     296    if (result < 0 || result > fSize)
     297        return -1;
     298   
     299    return result;
     300}
     301
     302
     303template<class Element>
     304int32
     305OpenHashElementArray<Element>::Size() const
     306{
     307    return fSize;
     308}
     309
     310
     311template<class Element>
     312int32
     313OpenHashElementArray<Element>::Add(const Element &newElement)
     314{
     315    int32 index = Add();
     316    At(index).Adopt(newElement);
     317    return index;
     318}
     319
     320
     321#if DEBUG
     322const int32 kGrowChunk = 10;
     323#else
     324const int32 kGrowChunk = 1024;
     325#endif
     326
     327
     328template<class Element>
     329int32
     330OpenHashElementArray<Element>::Add()
     331{
     332    int32 index = fNextFree;
     333    if (fNextDeleted >= 0) {
     334        index = fNextDeleted;
     335        fNextDeleted = At(index).fNext;     
     336    } else if (fNextFree >= fSize - 1) {
     337        int32 newSize = fSize + kGrowChunk;
     338        Element *newData = (Element *)calloc((size_t)newSize , sizeof(Element));
     339        if (!fData)
     340            throw bad_alloc();
     341        memcpy(newData, fData, fSize * sizeof(Element));
     342        free(fData);
     343        fData = newData;
     344        fSize = newSize;
     345        index = fNextFree;
     346        fNextFree++;
     347    } else
     348        fNextFree++;
     349
     350    new (&At(index)) Element;
     351        // call placement new to initialize the element properly
     352    ASSERT(At(index).fNext == -1);
     353
     354    return index;       
     355}
     356
     357
     358template<class Element>
     359void
     360OpenHashElementArray<Element>::Remove(int32 index)
     361{
     362    // delete by chaining empty elements in a single linked
     363    // list, reusing the next field
     364    ASSERT(index < fSize);
     365    At(index).~Element();
     366        // call the destructor explicitly to destroy the element
     367        // properly
     368    At(index).fNext = fNextDeleted;
     369    fNextDeleted = index;
     370}
     371
     372} // namespace BPrivate
     373
     374using namespace BPrivate;
     375
     376#endif
  • src/kits/locale/NumberFormatImpl.cpp

     
     1#include <NumberFormatImpl.h>
     2#include <NumberFormatParameters.h>
     3
     4// constructor
     5BNumberFormatImpl::BNumberFormatImpl()
     6    : BFormatImpl()
     7{
     8}
     9
     10// destructor
     11BNumberFormatImpl::~BNumberFormatImpl()
     12{
     13}
     14
     15// DefaultFormatParameters
     16BFormatParameters *
     17BNumberFormatImpl::DefaultFormatParameters()
     18{
     19    return DefaultNumberFormatParameters();
     20}
     21
     22// DefaultFormatParameters
     23const BFormatParameters *
     24BNumberFormatImpl::DefaultFormatParameters() const
     25{
     26    return DefaultNumberFormatParameters();
     27}
     28
  • src/kits/locale/Language.cpp

     
     1/*
     2** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
     3** Distributed under the terms of the OpenBeOS License.
     4*/
     5
     6
     7#include <Language.h>
     8
     9#include <Path.h>
     10#include <FindDirectory.h>
     11
     12#include <stdlib.h>
     13#include <stdio.h>
     14#include <string.h>
     15#include <ctype.h>
     16
     17
     18static const char *gBuiltInStrings[] = {
     19    "Yesterday",
     20    "Today",
     21    "Tomorrow",
     22    "Future",
     23   
     24    "Sunday",
     25    "Monday",
     26    "Tuesday",
     27    "Wednesday",
     28    "Thursday",
     29    "Friday",
     30    "Saturday",
     31   
     32    "Sun",
     33    "Mon",
     34    "Tue",
     35    "Wed",
     36    "Thu",
     37    "Fri",
     38    "Sat",
     39   
     40    "January",
     41    "February",
     42    "March",
     43    "April",
     44    "May",
     45    "June",
     46    "July",
     47    "August",
     48    "September",
     49    "October",
     50    "November",
     51    "December",
     52   
     53    "Jan",
     54    "Feb",
     55    "Mar",
     56    "Apr",
     57    "May",
     58    "Jun",
     59    "Jul",
     60    "Aug",
     61    "Sep",
     62    "Oct",
     63    "Nov",
     64    "Dec",
     65   
     66    "^[yY]",
     67    "^[nN]",
     68    "yes",
     69    "no"
     70};
     71
     72
     73static char *
     74TrimCopy(char *string)
     75{
     76    while (isspace(*string))
     77        string++;
     78
     79    int32 length = strlen(string);
     80    while (length-- > 0 && isspace(string[length]))
     81        string[length] = '\0';
     82
     83    if (length < 0)
     84        return NULL;
     85
     86    return strdup(string);
     87}
     88
     89
     90//  #pragma mark -
     91
     92
     93BLanguage::BLanguage(const char *language)
     94    :
     95    fName(NULL),
     96    fCode(NULL),
     97    fFamily(NULL),
     98    fDirection(B_LEFT_TO_RIGHT)
     99{
     100    for (int32 i = B_NUM_LANGUAGE_STRINGS;i-- > 0;)
     101        fStrings[i] = NULL;
     102
     103    if (language == NULL) {
     104        Default();
     105        return;
     106    }
     107
     108    char name[B_FILE_NAME_LENGTH];
     109    sprintf(name, "locale/languages/%s.language", language);
     110
     111    BPath path;
     112    if (find_directory(B_BEOS_ETC_DIRECTORY, &path) < B_OK) {
     113        Default();
     114        return;
     115    }
     116
     117    path.Append(name);
     118
     119    FILE *file = fopen(path.Path(), "r");
     120    if (file == NULL) {
     121        Default();
     122        return;
     123    }
     124
     125    int32 count = -2;
     126    while (fgets(name, B_FILE_NAME_LENGTH, file) != NULL) {
     127        if (count == -2) {
     128            char *family = strchr(name, ',');
     129            if (family == NULL)
     130                break;
     131            *family++ = '\0';
     132
     133            // set the direction of writing         
     134            char *direction = strchr(family, ',');
     135            if (direction != NULL) {
     136                *direction++ = '\0';
     137                direction = TrimCopy(direction);
     138
     139                if (!strcasecmp(direction, "ltr"))
     140                    fDirection = B_LEFT_TO_RIGHT;
     141                else if (!strcasecmp(direction, "rtl"))
     142                    fDirection = B_RIGHT_TO_LEFT;
     143                else if (!strcasecmp(direction, "ttb"))
     144                    fDirection = B_TOP_TO_BOTTOM;
     145
     146                free(direction);
     147            }
     148
     149            fName = strdup(language);
     150            fCode = TrimCopy(name);
     151            fFamily = TrimCopy(family);
     152            count++;
     153        } else if (count == -1) {
     154            if (!strcmp(name,"--\n"))
     155                count++;
     156        } else if (count < B_NUM_LANGUAGE_STRINGS) {
     157            char *string = TrimCopy(name);
     158            if (string == NULL)
     159                continue;
     160
     161            fStrings[count++] = string;
     162        }
     163    }
     164
     165    if (count < 0)
     166        Default();
     167
     168    fclose(file);
     169}
     170
     171
     172BLanguage::~BLanguage()
     173{
     174    if (fName != NULL)
     175        free(fName);
     176    if (fCode != NULL)
     177        free(fCode);
     178    if (fFamily != NULL)
     179        free(fFamily);
     180
     181    for (int32 i = B_NUM_LANGUAGE_STRINGS;i-- > 0;)
     182        free(fStrings[i]);
     183}
     184
     185
     186void
     187BLanguage::Default()
     188{
     189    fName = strdup("english");
     190    fCode = strdup("en");
     191    fFamily = strdup("germanic");
     192    fDirection = B_LEFT_TO_RIGHT;
     193
     194    for (int32 i = B_NUM_LANGUAGE_STRINGS;i-- > 0;) {
     195        free(fStrings[i]);
     196        fStrings[i] = strdup(gBuiltInStrings[i]);
     197    }
     198}
     199
     200
     201uint8
     202BLanguage::Direction() const
     203{
     204    return fDirection;
     205}
     206
     207
     208const char *
     209BLanguage::GetString(uint32 id) const
     210{
     211    if (id < B_LANGUAGE_STRINGS_BASE || id > B_LANGUAGE_STRINGS_BASE + B_NUM_LANGUAGE_STRINGS)
     212        return NULL;
     213
     214    return fStrings[id - B_LANGUAGE_STRINGS_BASE];
     215}
     216
  • src/kits/locale/PropertyFile.cpp

     
     1/*
     2** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
     3** Distributed under the terms of the OpenBeOS License.
     4*/
     5
     6
     7#include "PropertyFile.h"
     8#include "UnicodeProperties.h"
     9
     10#include <Path.h>
     11#include <FindDirectory.h>
     12
     13#if B_BEOS_VERSION <= B_BEOS_VERSION_5 && !defined(__HAIKU__)
     14// B_BAD_DATA was introduced with DANO, so we define it for R5:
     15#   define B_BAD_DATA -2147483632L
     16#endif
     17
     18
     19status_t
     20PropertyFile::SetTo(const char *directory, const char *name)
     21{
     22    BPath path;
     23    status_t status = find_directory(B_BEOS_ETC_DIRECTORY, &path);
     24    if (status < B_OK)
     25        return status;
     26
     27    path.Append(directory);
     28    path.Append(name);
     29    status = BFile::SetTo(path.Path(), B_READ_ONLY);
     30    if (status < B_OK)
     31        return status;
     32
     33    UnicodePropertiesHeader header;
     34    ssize_t bytes = Read(&header, sizeof(header));
     35    if (bytes < (ssize_t)sizeof(header)
     36        || header.size != (uint8)sizeof(header)
     37        || header.isBigEndian != B_HOST_IS_BENDIAN
     38        || header.format != PROPERTIES_FORMAT)
     39        return B_BAD_DATA;
     40
     41    return B_OK;
     42}
     43
     44
     45off_t
     46PropertyFile::Size()
     47{
     48    off_t size;
     49    if (GetSize(&size) < B_OK)
     50        return 0;
     51
     52    return size - sizeof(UnicodePropertiesHeader);
     53}
     54
  • src/kits/locale/UnicodeChar.cpp

     
     1/*
     2** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
     3** Distributed under the terms of the OpenBeOS License.
     4*/
     5
     6/* Reads the information out of the data files created by (an edited version of)
     7 * IBM's ICU genprops utility. The BUnicodeChar class is mostly the counterpart
     8 * to ICU's uchar module, but is not as huge or broad as that one.
     9 *
     10 * Note, it probably won't be able to handle the output of the orginal genprops
     11 * tool and vice versa - only use the tool provided with this project to create
     12 * the Unicode property file.
     13 * However, the algorithmic idea behind the property file is still the same as
     14 * found in ICU - nothing important has been changed, so more recent versions
     15 * of genprops tool/data can probably be ported without too much effort.
     16 *
     17 * In case no property file can be found it will still provide basic services
     18 * for the Latin-1 part of the character tables.
     19 */
     20
     21
     22#include <OS.h>
     23
     24#include <UnicodeChar.h>
     25#include "UnicodeProperties.h"
     26#include "PropertyFile.h"
     27
     28#include <stdlib.h>
     29#include <stdio.h>
     30#include <string.h>
     31
     32
     33#if B_BEOS_VERSION <= B_BEOS_VERSION_5 && !defined(__HAIKU__)
     34// B_BAD_DATA was introduced with DANO, so we define it for R5:
     35#define B_BAD_DATA -2147483632L
     36#endif
     37
     38static const uint16 *sPropsTable = NULL;
     39#define sProps32Table ((uint32 *)sPropsTable)
     40static uint16 *sIndices;
     41static vint32 sHavePropsData = 0;
     42
     43#define FLAG(n) ((uint32)1 << (n))
     44enum {
     45    UF_UPPERCASE        = FLAG(B_UNICODE_UPPERCASE_LETTER),
     46    UF_LOWERCASE        = FLAG(B_UNICODE_LOWERCASE_LETTER),
     47    UF_TITLECASE        = FLAG(B_UNICODE_TITLECASE_LETTER),
     48    UF_MODIFIER_LETTER  = FLAG(B_UNICODE_MODIFIER_LETTER),
     49    UF_OTHER_LETTER     = FLAG(B_UNICODE_OTHER_LETTER),
     50    UF_DECIMAL_NUMBER   = FLAG(B_UNICODE_DECIMAL_DIGIT_NUMBER),
     51    UF_OTHER_NUMBER     = FLAG(B_UNICODE_OTHER_NUMBER),
     52    UF_LETTER_NUMBER    = FLAG(B_UNICODE_LETTER_NUMBER)
     53};
     54
     55
     56static uint32 gStaticProps32Table[] = {
     57    /* 0x00 */  0x48f,      0x48f,      0x48f,      0x48f,
     58    /* 0x04 */  0x48f,      0x48f,      0x48f,      0x48f,
     59    /* 0x08 */  0x48f,      0x20c,      0x1ce,      0x20c,
     60    /* 0x0c */  0x24d,      0x1ce,      0x48f,      0x48f,
     61    /* 0x10 */  0x48f,      0x48f,      0x48f,      0x48f,
     62    /* 0x14 */  0x48f,      0x48f,      0x48f,      0x48f,
     63    /* 0x18 */  0x48f,      0x48f,      0x48f,      0x48f,
     64    /* 0x1c */  0x1ce,      0x1ce,      0x1ce,      0x20c,
     65    /* 0x20 */  0x24c,      0x297,      0x297,      0x117,
     66    /* 0x24 */  0x119,      0x117,      0x297,      0x297,
     67    /* 0x28 */  0x100a94,   0xfff00a95, 0x297,      0x118,
     68    /* 0x2c */  0x197,      0x113,      0x197,      0xd7,
     69    /* 0x30 */  0x89,       0x100089,   0x200089,   0x300089,
     70    /* 0x34 */  0x400089,   0x500089,   0x600089,   0x700089,
     71    /* 0x38 */  0x800089,   0x900089,   0x197,      0x297,
     72    /* 0x3c */  0x200a98,   0x298,      0xffe00a98, 0x297,
     73    /* 0x40 */  0x297,      0x2000001,  0x2000001,  0x2000001,
     74    /* 0x44 */  0x2000001,  0x2000001,  0x2000001,  0x2000001,
     75    /* 0x48 */  0x2000001,  0x2000001,  0x2000001,  0x2000001,
     76    /* 0x4c */  0x2000001,  0x2000001,  0x2000001,  0x2000001,
     77    /* 0x50 */  0x2000001,  0x2000001,  0x2000001,  0x2000001,
     78    /* 0x54 */  0x2000001,  0x2000001,  0x2000001,  0x2000001,
     79    /* 0x58 */  0x2000001,  0x2000001,  0x2000001,  0x200a94,
     80    /* 0x5c */  0x297,      0xffe00a95, 0x29a,      0x296,
     81    /* 0x60 */  0x29a,      0x2000002,  0x2000002,  0x2000002,
     82    /* 0x64 */  0x2000002,  0x2000002,  0x2000002,  0x2000002,
     83    /* 0x68 */  0x2000002,  0x2000002,  0x2000002,  0x2000002,
     84    /* 0x6c */  0x2000002,  0x2000002,  0x2000002,  0x2000002,
     85    /* 0x70 */  0x2000002,  0x2000002,  0x2000002,  0x2000002,
     86    /* 0x74 */  0x2000002,  0x2000002,  0x2000002,  0x2000002,
     87    /* 0x78 */  0x2000002,  0x2000002,  0x2000002,  0x200a94,
     88    /* 0x7c */  0x298,      0xffe00a95, 0x298,      0x48f,
     89    /* 0x80 */  0x48f,      0x48f,      0x48f,      0x48f,
     90    /* 0x84 */  0x48f,      0x1ce,      0x48f,      0x48f,
     91    /* 0x88 */  0x48f,      0x48f,      0x48f,      0x48f,
     92    /* 0x8c */  0x48f,      0x48f,      0x48f,      0x48f,
     93    /* 0x90 */  0x48f,      0x48f,      0x48f,      0x48f,
     94    /* 0x94 */  0x48f,      0x48f,      0x48f,      0x48f,
     95    /* 0x98 */  0x48f,      0x48f,      0x48f,      0x48f,
     96    /* 0x9c */  0x48f,      0x48f,      0x48f,      0x48f
     97};
     98
     99enum {
     100    INDEX_STAGE_2_BITS,
     101    INDEX_STAGE_3_BITS,
     102    INDEX_EXCEPTIONS,
     103    INDEX_STAGE_3_INDEX,
     104    INDEX_PROPS,
     105    INDEX_UCHARS
     106};
     107
     108/* constants and macros for access to the data */
     109enum {
     110    EXC_UPPERCASE,
     111    EXC_LOWERCASE,
     112    EXC_TITLECASE,
     113    EXC_DIGIT_VALUE,
     114    EXC_NUMERIC_VALUE,
     115    EXC_DENOMINATOR_VALUE,
     116    EXC_MIRROR_MAPPING,
     117    EXC_SPECIAL_CASING,
     118    EXC_CASE_FOLDING
     119};
     120
     121enum {
     122    EXCEPTION_SHIFT = 5,
     123    BIDI_SHIFT,
     124    MIRROR_SHIFT    = BIDI_SHIFT + 5,
     125    VALUE_SHIFT     = 20,
     126
     127    VALUE_BITS      = 32 - VALUE_SHIFT
     128};
     129
     130/* number of bits in an 8-bit integer value */
     131#define EXC_GROUP 8
     132static uint8 gFlagsOffset[256] = {
     133    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
     134    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
     135    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
     136    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
     137    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
     138    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
     139    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
     140    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
     141    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
     142    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
     143    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
     144    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
     145    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
     146    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
     147    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
     148    4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
     149};
     150
     151#ifdef UCHAR_VARIABLE_TRIE_BITS
     152    // access values calculated from indices
     153    static uint16_t stage23Bits, stage2Mask, stage3Mask;
     154#   define sStage3Bits   indexes[INDEX_STAGE_3_BITS]
     155#else
     156    // Use hardcoded bit distribution for the trie table access
     157#   define sStage23Bits  10
     158#   define sStage2Mask   0x3f
     159#   define sStage3Mask   0xf
     160#   define sStage3Bits   4
     161#endif
     162
     163
     164/** We need to change the char category for ISO 8 controls, since the
     165 *  genprops utility we got from IBM's ICU apparently changes it for
     166 *  some characters.
     167 */
     168
     169static inline bool
     170isISO8Control(uint32 c)
     171{
     172    return ((uint32)c < 0x20 || (uint32)(c - 0x7f) <= 0x20);
     173}
     174
     175
     176static inline uint32
     177getProperties(uint32 c)
     178{
     179    if (c > 0x10ffff)
     180        return 0;
     181
     182    if (sHavePropsData > 0)
     183        return sProps32Table[sPropsTable[
     184                    sPropsTable[sPropsTable[8 + (c >> sStage23Bits)]
     185                        + ((c >> sStage3Bits) & sStage2Mask)]
     186                    + (c & sStage3Mask)]];
     187
     188    return c > 0x9f ? 0 : gStaticProps32Table[c];
     189}
     190
     191
     192static inline uint8
     193getCategory(uint32 properties)
     194{
     195    return properties & 0x1f;
     196}
     197
     198
     199static inline bool
     200propertyIsException(uint32 properties)
     201{
     202    return properties & (1UL << EXCEPTION_SHIFT);
     203}
     204
     205
     206static inline uint32
     207getUnsignedValue(uint32 properties)
     208{
     209    return properties >> VALUE_SHIFT;
     210}
     211
     212
     213static inline uint32
     214getSignedValue(uint32 properties)
     215{
     216    return (int32)properties >> VALUE_SHIFT;
     217}
     218
     219
     220static inline uint32 *
     221getExceptions(uint32 properties)
     222{
     223    return sProps32Table + sIndices[INDEX_EXCEPTIONS] + getUnsignedValue(properties);
     224}
     225
     226
     227static inline bool
     228haveExceptionValue(uint32 flags,int16 index)
     229{
     230    return flags & (1UL << index);
     231}
     232
     233
     234static inline void
     235addExceptionOffset(uint32 &flags, int16 &index, uint32 **offset)
     236{
     237    if (index >= EXC_GROUP) {
     238        *offset += gFlagsOffset[flags & ((1 << EXC_GROUP) - 1)];
     239        flags >>= EXC_GROUP;
     240        index -= EXC_GROUP;
     241    }
     242    *offset += gFlagsOffset[flags & ((1 << index) - 1)];
     243}
     244
     245
     246static status_t
     247loadPropsData()
     248{
     249    PropertyFile file;
     250    status_t status = file.SetTo(PROPERTIES_DIRECTORY, PROPERTIES_FILE_NAME);
     251    if (status < B_OK) {
     252        fprintf(stderr, "could not open unicode.properties file: %s\n", strerror(status));
     253        return status;
     254    }
     255
     256    off_t size = file.Size();
     257    uint16 *table = (uint16 *)malloc(size);
     258    if (table == NULL)
     259        return B_NO_MEMORY;
     260
     261    if (file.Read(table, size) < size) {
     262        free(table);
     263        return B_IO_ERROR;
     264    }
     265
     266    // check if the property file matches our needs
     267    if (table[INDEX_STAGE_2_BITS] != 6 || table[INDEX_STAGE_3_BITS] != 4) {
     268        free(table);
     269        return B_BAD_DATA;
     270    }
     271
     272    sIndices = table;
     273#ifdef UCHAR_VARIABLE_TRIE_BITS
     274    sStage23Bits = uint16(sIndices[INDEX_STAGE_2_BITS] + sIndices[INDEX_STAGE_3_BITS]);
     275    sStage2Mask = uint16((1 << sIndices[INDEX_STAGE_2_BITS]) - 1);
     276    sStage3Mask = uint16((1 << sIndices[INDEX_STAGE_3_BITS]) - 1);
     277#endif
     278
     279    sPropsTable = table;
     280    sHavePropsData = 1;
     281
     282    return B_OK;
     283}
     284
     285
     286//  #pragma mark -
     287
     288
     289/** If the constructor is used for the first time, the property
     290 *  file gets loaded from disk.
     291 *  It makes sure that this will only happen once throughout the
     292 *  application's lifetime.
     293 */
     294
     295BUnicodeChar::BUnicodeChar()
     296{
     297    static int32 lock = 0;
     298
     299    if (atomic_add(&lock, 1) > 0) {
     300        while (sHavePropsData == 0)
     301            snooze(10000);
     302
     303        return;
     304    }
     305    if (loadPropsData() < B_OK)
     306        sHavePropsData = -1;
     307}
     308
     309
     310bool
     311BUnicodeChar::IsAlpha(uint32 c)
     312{
     313    BUnicodeChar();
     314    return (FLAG(getCategory(getProperties(c)))
     315            & (UF_UPPERCASE | UF_LOWERCASE | UF_TITLECASE | UF_MODIFIER_LETTER | UF_OTHER_LETTER)
     316           ) != 0;
     317}
     318
     319
     320/** Returns the type code of the specified unicode character */
     321
     322int8
     323BUnicodeChar::Type(uint32 c)
     324{
     325    BUnicodeChar();
     326    return (int8)getCategory(getProperties(c));
     327}
     328
     329
     330bool
     331BUnicodeChar::IsLower(uint32 c)
     332{
     333    BUnicodeChar();
     334    return getCategory(getProperties(c)) == B_UNICODE_LOWERCASE_LETTER;
     335}
     336
     337
     338bool
     339BUnicodeChar::IsUpper(uint32 c)
     340{
     341    BUnicodeChar();
     342    return getCategory(getProperties(c)) == B_UNICODE_UPPERCASE_LETTER;
     343}
     344
     345
     346bool
     347BUnicodeChar::IsTitle(uint32 c)
     348{
     349    BUnicodeChar();
     350    return getCategory(getProperties(c)) == B_UNICODE_TITLECASE_LETTER;
     351}
     352
     353
     354bool
     355BUnicodeChar::IsDigit(uint32 c)
     356{
     357    BUnicodeChar();
     358    return (FLAG(getCategory(getProperties(c)))
     359            & (UF_DECIMAL_NUMBER | UF_OTHER_NUMBER | UF_LETTER_NUMBER)
     360           ) != 0;
     361}
     362
     363
     364bool
     365BUnicodeChar::IsAlNum(uint32 c)
     366{
     367    BUnicodeChar();
     368    return (FLAG(getCategory(getProperties(c)))
     369            & (UF_DECIMAL_NUMBER | UF_OTHER_NUMBER | UF_LETTER_NUMBER | UF_UPPERCASE
     370               | UF_LOWERCASE | UF_TITLECASE | UF_MODIFIER_LETTER | UF_OTHER_LETTER)
     371           ) != 0;
     372}
     373
     374
     375bool
     376BUnicodeChar::IsDefined(uint32 c)
     377{
     378    BUnicodeChar();
     379    return getProperties(c) != 0;
     380}
     381
     382
     383/** Returns true if the specified unicode character is a base
     384 *  form character that can be used with a diacritic.
     385 *  This doesn't mean that the character has to be distinct,
     386 *  though.
     387 */
     388
     389bool
     390BUnicodeChar::IsBase(uint32 c)
     391{
     392    BUnicodeChar();
     393    return (FLAG(getCategory(getProperties(c)))
     394            & (UF_DECIMAL_NUMBER | UF_OTHER_NUMBER | UF_LETTER_NUMBER
     395               | UF_UPPERCASE | UF_LOWERCASE | UF_TITLECASE
     396               | UF_MODIFIER_LETTER | UF_OTHER_LETTER | FLAG(B_UNICODE_NON_SPACING_MARK)
     397               | FLAG(B_UNICODE_ENCLOSING_MARK) | FLAG(B_UNICODE_COMBINING_SPACING_MARK))
     398           ) != 0;
     399}
     400
     401
     402/** Returns true if the specified unicode character is a
     403 *  control character.
     404 */
     405
     406bool
     407BUnicodeChar::IsControl(uint32 c)
     408{
     409    BUnicodeChar();
     410    return isISO8Control(c)
     411            || (FLAG(getCategory(getProperties(c)))
     412                & (FLAG(B_UNICODE_CONTROL_CHAR) | FLAG(B_UNICODE_FORMAT_CHAR)
     413                    | FLAG(B_UNICODE_LINE_SEPARATOR) | FLAG(B_UNICODE_PARAGRAPH_SEPARATOR))
     414               ) != 0;
     415}
     416
     417
     418/** Returns true if the specified unicode character is a
     419 *  punctuation character.
     420 */
     421
     422bool
     423BUnicodeChar::IsPunctuation(uint32 c)
     424{
     425    BUnicodeChar();
     426    return (FLAG(getCategory(getProperties(c)))
     427            & (FLAG(B_UNICODE_DASH_PUNCTUATION)
     428                | FLAG(B_UNICODE_START_PUNCTUATION)
     429                | FLAG(B_UNICODE_END_PUNCTUATION)
     430                | FLAG(B_UNICODE_CONNECTOR_PUNCTUATION)
     431                | FLAG(B_UNICODE_OTHER_PUNCTUATION))
     432            ) != 0;
     433}
     434
     435
     436/** Returns true if the specified unicode character is some
     437 *  kind of a space character.
     438 */
     439
     440bool
     441BUnicodeChar::IsSpace(uint32 c)
     442{
     443    BUnicodeChar();
     444    return (FLAG(getCategory(getProperties(c)))
     445            & (FLAG(B_UNICODE_SPACE_SEPARATOR)
     446                | FLAG(B_UNICODE_LINE_SEPARATOR)
     447                | FLAG(B_UNICODE_PARAGRAPH_SEPARATOR))
     448           ) != 0;
     449}
     450
     451
     452/** Returns true if the specified unicode character is a white
     453 *  space character.
     454 *  This is essentially the same as IsSpace(), but excludes all
     455 *  non-breakable spaces.
     456 */
     457
     458bool
     459BUnicodeChar::IsWhitespace(uint32 c)
     460{
     461    BUnicodeChar();
     462    return (FLAG(getCategory(getProperties(c)))
     463            & (FLAG(B_UNICODE_SPACE_SEPARATOR)
     464                | FLAG(B_UNICODE_LINE_SEPARATOR)
     465                | FLAG(B_UNICODE_PARAGRAPH_SEPARATOR))
     466           ) != 0 && c != 0xa0 && c != 0x202f && c != 0xfeff; // exclude non-breakable spaces
     467}
     468
     469
     470/** Returns true if the specified unicode character is printable.
     471 */
     472
     473bool
     474BUnicodeChar::IsPrintable(uint32 c)
     475{
     476    BUnicodeChar();
     477    return !isISO8Control(c)
     478            && (FLAG(getCategory(getProperties(c)))
     479                & ~(FLAG(B_UNICODE_UNASSIGNED) | FLAG(B_UNICODE_CONTROL_CHAR)
     480                    | FLAG(B_UNICODE_FORMAT_CHAR) | FLAG(B_UNICODE_PRIVATE_USE_CHAR)
     481                    | FLAG(B_UNICODE_SURROGATE) | FLAG(B_UNICODE_GENERAL_OTHER_TYPES)
     482                    | FLAG(31))
     483                   ) != 0;
     484}
     485
     486
     487//  #pragma mark -
     488
     489
     490/** Transforms the specified unicode character to lowercase.
     491 */
     492
     493uint32
     494BUnicodeChar::ToLower(uint32 c)
     495{
     496    BUnicodeChar();
     497
     498    uint32 props = getProperties(c);
     499
     500    if (!propertyIsException(props)) {
     501        if (FLAG(getCategory(props)) & (UF_UPPERCASE | UF_TITLECASE))
     502            return c + getSignedValue(props);
     503    } else {
     504        uint32 *exceptions = getExceptions(props);
     505        uint32 firstExceptionValue = *exceptions;
     506
     507        if (haveExceptionValue(firstExceptionValue, EXC_LOWERCASE)) {
     508            int16 index = EXC_LOWERCASE;
     509            addExceptionOffset(firstExceptionValue, index, &++exceptions);
     510            return *exceptions;
     511        }
     512    }
     513    // no mapping found, just return the character unchanged
     514    return c;
     515}
     516
     517
     518/** Transforms the specified unicode character to uppercase.
     519 */
     520
     521uint32
     522BUnicodeChar::ToUpper(uint32 c)
     523{
     524    BUnicodeChar();
     525
     526    uint32 props = getProperties(c);
     527
     528    if (!propertyIsException(props)) {
     529        if (getCategory(props) == B_UNICODE_LOWERCASE_LETTER)
     530            return c - getSignedValue(props);
     531    } else {
     532        uint32 *exceptions = getExceptions(props);
     533        uint32 firstExceptionValue = *exceptions;
     534
     535        if (haveExceptionValue(firstExceptionValue, EXC_UPPERCASE)) {
     536            int16 index = EXC_UPPERCASE;
     537            ++exceptions;
     538            addExceptionOffset(firstExceptionValue, index, &exceptions);
     539            return *exceptions;
     540        }
     541    }
     542    // no mapping found, just return the character unchanged
     543    return c;
     544}
     545
     546
     547/** Transforms the specified unicode character to title case.
     548 */
     549
     550uint32
     551BUnicodeChar::ToTitle(uint32 c)
     552{
     553    BUnicodeChar();
     554
     555    uint32 props = getProperties(c);
     556
     557    if (!propertyIsException(props)) {
     558        if (getCategory(props) == B_UNICODE_LOWERCASE_LETTER) {
     559            // here, titlecase is the same as uppercase
     560            return c - getSignedValue(props);
     561        }
     562    } else {
     563        uint32 *exceptions = getExceptions(props);
     564        uint32 firstExceptionValue = *exceptions;
     565
     566        if (haveExceptionValue(firstExceptionValue, EXC_TITLECASE)) {
     567            int16 index = EXC_TITLECASE;
     568            addExceptionOffset(firstExceptionValue, index, &++exceptions);
     569            return (uint32)*exceptions;
     570        } else if (haveExceptionValue(firstExceptionValue, EXC_UPPERCASE)) {
     571            // here, titlecase is the same as uppercase
     572            int16 index = EXC_UPPERCASE;
     573            addExceptionOffset(firstExceptionValue, index, &++exceptions);
     574            return *exceptions;
     575        }
     576    }
     577    // no mapping found, just return the character unchanged
     578    return c;
     579}
     580
     581
     582int32
     583BUnicodeChar::DigitValue(uint32 c)
     584{
     585    BUnicodeChar();
     586
     587    uint32 props = getProperties(c);
     588
     589    if (!propertyIsException(props)) {
     590        if (getCategory(props) == B_UNICODE_DECIMAL_DIGIT_NUMBER)
     591            return getSignedValue(props);
     592    } else {
     593        uint32 *exceptions = getExceptions(props);
     594        uint32 firstExceptionValue = *exceptions;
     595
     596        if (haveExceptionValue(firstExceptionValue, EXC_DIGIT_VALUE)) {
     597            int16 index = EXC_DIGIT_VALUE;
     598            addExceptionOffset(firstExceptionValue, index, &++exceptions);
     599
     600            int32 value = (int32)(int16)*exceptions;
     601                 // the digit value is in the lower 16 bits
     602            if (value != -1)
     603                return value;
     604        }
     605    }
     606
     607    // If there is no value in the properties table,
     608    // then check for some special characters
     609    switch (c) {
     610        case 0x3007:    return 0;
     611        case 0x4e00:    return 1;
     612        case 0x4e8c:    return 2;
     613        case 0x4e09:    return 3;
     614        case 0x56d8:    return 4;
     615        case 0x4e94:    return 5;
     616        case 0x516d:    return 6;
     617        case 0x4e03:    return 7;
     618        case 0x516b:    return 8;
     619        case 0x4e5d:    return 9;
     620        default:        return -1;
     621    }
     622}
     623
     624
     625void
     626BUnicodeChar::ToUTF8(uint32 c, char **out)
     627{
     628    char *s = *out;
     629
     630    if (c < 0x80)
     631        *(s++) = c;
     632    else if (c < 0x800) {
     633        *(s++) = 0xc0 | (c >> 6);
     634        *(s++) = 0x80 | (c & 0x3f);
     635    } else if (c < 0x10000) {
     636        *(s++) = 0xe0 | (c >> 12);
     637        *(s++) = 0x80 | ((c >> 6) & 0x3f);
     638        *(s++) = 0x80 | (c & 0x3f);
     639    } else if (c <= 0x10ffff) {
     640        *(s++) = 0xf0 | (c >> 18);
     641        *(s++) = 0x80 | ((c >> 12) & 0x3f);
     642        *(s++) = 0x80 | ((c >> 6) & 0x3f);
     643        *(s++) = 0x80 | (c & 0x3f);
     644    }
     645    *out = s;
     646}
     647
     648
     649uint32
     650BUnicodeChar::FromUTF8(const char **in)
     651{
     652    uint8 *bytes = (uint8 *)*in;
     653    if (bytes == NULL)
     654        return 0;
     655
     656    int32 length;
     657    uint8 mask = 0x1f;
     658
     659    switch (bytes[0] & 0xf0) {
     660        case 0xc0:
     661        case 0xd0:  length = 2; break;
     662        case 0xe0:  length = 3; break;
     663        case 0xf0:
     664            mask = 0x0f;
     665            length = 4;
     666            break;
     667        default:
     668            // valid 1-byte character
     669            // and invalid characters
     670            (*in)++;
     671            return bytes[0];
     672    }
     673    uint32 c = bytes[0] & mask;
     674    int32 i = 1;
     675    for (;i < length && (bytes[i] & 0x80) > 0;i++)
     676        c = (c << 6) | (bytes[i] & 0x3f);
     677
     678    if (i < length) {
     679        // invalid character
     680        (*in)++;
     681        return (uint32)bytes[0];
     682    }
     683    *in += length;
     684    return c;
     685}
     686
     687size_t
     688BUnicodeChar::UTF8StringLength(const char *str)
     689{
     690    size_t len = 0;
     691    while (*str) {
     692        FromUTF8(&str);
     693        len++;
     694    }
     695    return len;
     696}
     697
     698size_t
     699BUnicodeChar::UTF8StringLength(const char *str, size_t maxLength)
     700{
     701    size_t len = 0;
     702    while (len < maxLength && *str) {
     703        FromUTF8(&str);
     704        len++;
     705    }
     706    return len;
     707}
     708
  • src/kits/locale/NumberFormatParameters.cpp

     
     1#include <NumberFormatParameters.h>
     2
     3// defaults
     4static const bool kDefaultUseGrouping = false;
     5static const number_format_sign_policy kDefaultSignPolicy
     6    = B_USE_NEGATIVE_SIGN_ONLY;
     7static const number_format_base kDefaultBase = B_DEFAULT_BASE;
     8static const bool kDefaultUseBasePrefix = false;
     9static const size_t kDefaultMinimalIntegerDigits = 1;
     10static const bool kDefaultUseZeroPadding = false;
     11
     12// flags
     13enum {
     14    USE_GROUPING_SET            = 0x01,
     15    SIGN_POLICY_SET             = 0x02,
     16    BASE_SET                    = 0x04,
     17    USE_BASE_PREFIX_SET         = 0x08,
     18    MINIMAL_INTEGER_DIGITS_SET  = 0x10,
     19    USE_ZERO_PADDING_SET        = 0x20,
     20};
     21
     22// constructor
     23BNumberFormatParameters::BNumberFormatParameters(
     24    const BNumberFormatParameters *parent)
     25    : BFormatParameters(parent),
     26      fParent(parent),
     27      fFlags(0)
     28{
     29}
     30
     31// copy constructor
     32BNumberFormatParameters::BNumberFormatParameters(
     33    const BNumberFormatParameters &other)
     34    : BFormatParameters(other),
     35      fParent(other.fParent),
     36      fUseGrouping(other.fUseGrouping),
     37      fSignPolicy(other.fSignPolicy),
     38      fBase(other.fBase),
     39      fUseBasePrefix(other.fUseBasePrefix),
     40      fMinimalIntegerDigits(other.fMinimalIntegerDigits),
     41      fFlags(other.fFlags)
     42{
     43}
     44
     45// destructor
     46BNumberFormatParameters::~BNumberFormatParameters()
     47{
     48}
     49
     50// SetUseGrouping
     51void
     52BNumberFormatParameters::SetUseGrouping(bool useGrouping)
     53{
     54    fUseGrouping = useGrouping;
     55    fFlags |= USE_GROUPING_SET;
     56}
     57
     58// UseGrouping
     59bool
     60BNumberFormatParameters::UseGrouping() const
     61{
     62    if (fFlags & USE_GROUPING_SET)
     63        return fUseGrouping;
     64    if (fParent)
     65        return fParent->UseGrouping();
     66    return kDefaultUseGrouping;
     67}
     68
     69// SetSignPolicy
     70void
     71BNumberFormatParameters::SetSignPolicy(number_format_sign_policy policy)
     72{
     73    fSignPolicy = policy;
     74    fFlags |= SIGN_POLICY_SET;
     75}
     76
     77// SignPolicy
     78number_format_sign_policy
     79BNumberFormatParameters::SignPolicy() const
     80{
     81    if (fFlags & SIGN_POLICY_SET)
     82        return fSignPolicy;
     83    if (fParent)
     84        return fParent->SignPolicy();
     85    return kDefaultSignPolicy;
     86}
     87
     88// SetBase
     89void
     90BNumberFormatParameters::SetBase(number_format_base base)
     91{
     92    fBase = base;
     93    fFlags |= BASE_SET;
     94}
     95
     96// Base
     97number_format_base
     98BNumberFormatParameters::Base() const
     99{
     100    if (fFlags & BASE_SET)
     101        return fBase;
     102    if (fParent)
     103        return fParent->Base();
     104    return kDefaultBase;
     105}
     106
     107// SetUseBasePrefix
     108void
     109BNumberFormatParameters::SetUseBasePrefix(bool useBasePrefix)
     110{
     111    fUseBasePrefix = useBasePrefix;
     112    fFlags |= USE_BASE_PREFIX_SET;
     113}
     114
     115// UseBasePrefix
     116bool
     117BNumberFormatParameters::UseBasePrefix() const
     118{
     119    if (fFlags & USE_BASE_PREFIX_SET)
     120        return fUseBasePrefix;
     121    if (fParent)
     122        return fParent->UseBasePrefix();
     123    return kDefaultUseBasePrefix;
     124}
     125
     126// SetMinimalIntegerDigits
     127void
     128BNumberFormatParameters::SetMinimalIntegerDigits(size_t minIntegerDigits)
     129{
     130    fMinimalIntegerDigits = minIntegerDigits;
     131    fFlags |= MINIMAL_INTEGER_DIGITS_SET;
     132}
     133
     134// MinimalIntegerDigits
     135size_t
     136BNumberFormatParameters::MinimalIntegerDigits() const
     137{
     138    if (fFlags & MINIMAL_INTEGER_DIGITS_SET)
     139        return fMinimalIntegerDigits;
     140    if (fParent)
     141        return fParent->MinimalIntegerDigits();
     142    return kDefaultMinimalIntegerDigits;
     143}
     144
     145// SetUseZeroPadding
     146void
     147BNumberFormatParameters::SetUseZeroPadding(bool useZeroPadding)
     148{
     149    fUseZeroPadding = useZeroPadding;
     150    fFlags |= USE_ZERO_PADDING_SET;
     151}
     152
     153// UseZeroPadding
     154bool
     155BNumberFormatParameters::UseZeroPadding() const
     156{
     157    if (fFlags & USE_ZERO_PADDING_SET)
     158        return fUseZeroPadding;
     159    if (fParent)
     160        return fParent->UseZeroPadding();
     161    return kDefaultUseZeroPadding;
     162}
     163
     164// SetParentNumberParameters
     165void
     166BNumberFormatParameters::SetParentNumberParameters(
     167    const BNumberFormatParameters *parent)
     168{
     169    fParent = parent;
     170    SetParentParameters(parent);
     171}
     172
     173// ParentNumberParameters
     174const BNumberFormatParameters *
     175BNumberFormatParameters::ParentNumberParameters() const
     176{
     177    return fParent;
     178}
     179
     180// =
     181BNumberFormatParameters &
     182BNumberFormatParameters::operator=(const BNumberFormatParameters &other)
     183{
     184    BFormatParameters::operator=(other);
     185    fParent = other.fParent;
     186    fUseGrouping = other.fUseGrouping;
     187    fSignPolicy = other.fSignPolicy;
     188    fBase = other.fBase;
     189    fUseBasePrefix = other.fUseBasePrefix;
     190    fMinimalIntegerDigits = other.fMinimalIntegerDigits;
     191    fFlags = other.fFlags;
     192    return *this;
     193}
     194
  • src/kits/locale/Jamfile

     
     1SubDir HAIKU_TOP src kits locale ;
     2
     3DEFINES += _BUILDING_locale=1 ;
     4
     5UsePublicHeaders [ FDirName $(HAIKU_TOP) headers os storage ] ;
     6
     7UseHeaders [ FDirName $(HAIKU_TOP) headers os locale ] : true ;
     8UseHeaders [ FDirName $(HAIKU_TOP) headers os locale posix ] : true ;
     9
     10SharedLibrary liblocale.so
     11    : adler32.c
     12      cat.cpp
     13      Catalog.cpp
     14      Collator.cpp
     15      Country.cpp
     16      Currency.cpp
     17      DefaultCatalog.cpp
     18      FloatFormat.cpp
     19      FloatFormatImpl.cpp
     20      FloatFormatParameters.cpp
     21      Format.cpp
     22      FormatImpl.cpp
     23      FormatParameters.cpp
     24      GenericNumberFormat.cpp
     25      IntegerFormat.cpp
     26      IntegerFormatImpl.cpp
     27      IntegerFormatParameters.cpp
     28      langinfo.cpp
     29      Language.cpp
     30      LibraryInit.cpp
     31      Locale.cpp
     32      LocaleRoster.cpp
     33      NumberFormat.cpp
     34      NumberFormatImpl.cpp
     35      NumberFormatParameters.cpp
     36      PropertyFile.cpp
     37      strfmon.cpp
     38      UnicodeChar.cpp
     39    : be
     40;
     41
  • src/kits/locale/strfmon.cpp

     
     1/*
     2** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
     3** Distributed under the terms of the OpenBeOS License.
     4*/
     5
     6
     7#include <SupportDefs.h>
     8
     9#include <errno.h>
     10
     11#include <monetary.h>
     12#include <locale.h>
     13#include <ctype.h>
     14#include <stdio.h>
     15#include <stdarg.h>
     16
     17
     18// ToDo: implementation is not yet working!
     19
     20
     21enum strfmon_flags {
     22    USE_GROUPING        = 1,
     23    USE_SIGN            = 2,
     24    USE_LOCALE_POSNEG   = 4,
     25    NEG_IN_PARENTHESES  = 8,
     26    NO_CURRENCY         = 16,
     27    LEFT_JUSTIFIED      = 32,
     28    USE_INT_CURRENCY    = 64
     29};
     30
     31
     32static int32
     33parseNumber(const char **_format)
     34{
     35    const char *format = *_format;
     36    int32 number = 0;
     37    while (isdigit(*format))
     38        number = number * 10 + *format++ - '0';
     39
     40    *_format = format;
     41    return number;
     42}
     43
     44
     45ssize_t
     46vstrfmon(char *string, size_t maxSize, const char *format, va_list args)
     47{
     48    if (format == NULL || string == NULL)
     49        return B_BAD_VALUE;
     50
     51    struct lconv *lconv = localeconv();
     52    int32 length = 0;
     53
     54    while (*format) {
     55        if (format[0] != '%' || *++format == '%') {
     56            if (++length >= (int32)maxSize)
     57                return E2BIG;
     58
     59            *string++ = *format++;
     60            continue;
     61        }
     62        if (format[0] == '\0')
     63            return B_BAD_VALUE;
     64
     65        char flags = USE_GROUPING | USE_LOCALE_POSNEG;
     66        char fill = ' ';
     67        int32 width = 0, leftPrecision = 0, rightPrecision = -1;
     68        bool isNegative = false;
     69
     70        // flags
     71        int32 mode = 0;
     72        while (*format && mode == 0) {
     73            switch (*format++) {
     74                case '=':
     75                    fill = *format++;
     76                    if (fill == '\0')
     77                        return B_BAD_VALUE;
     78                    break;
     79                case '+':
     80                    if (flags & USE_SIGN)
     81                        return B_BAD_VALUE;
     82                    flags |= USE_SIGN;
     83                    break;
     84                case '(':
     85                    if (flags & USE_SIGN)
     86                        return B_BAD_VALUE;
     87                    flags |= USE_SIGN | NEG_IN_PARENTHESES;
     88                    break;
     89                case '^':
     90                    flags &= ~USE_GROUPING;
     91                    break;
     92                case '!':
     93                    flags |= NO_CURRENCY;
     94                    break;
     95                case '-':
     96                    flags |= LEFT_JUSTIFIED;
     97                    break;
     98                default:
     99                    mode = 1;
     100            }
     101        }
     102
     103        // width
     104        if (isdigit(*format))
     105            width = parseNumber(&format);
     106
     107        // left precision
     108        if (*format == '#') {
     109            format++;
     110            if (!isdigit(*format))
     111                return B_BAD_VALUE;
     112
     113            leftPrecision = parseNumber(&format);
     114        }
     115
     116        // right precision
     117        if (*format == '.') {
     118            format++;
     119            if (!isdigit(*format))
     120                return B_BAD_VALUE;
     121
     122            rightPrecision = parseNumber(&format);
     123        }
     124
     125        // which currency symbol to use?
     126        switch (*format++) {
     127            case 'n':
     128                // national currency symbol is the default
     129                break;
     130            case 'i':
     131                flags |= USE_INT_CURRENCY;
     132                break;
     133            default:
     134                return B_BAD_VALUE;
     135        }
     136
     137        // adjust the default right precision value according the currency symbol
     138        if (rightPrecision == -1) {
     139            rightPrecision = flags & USE_INT_CURRENCY ? lconv->int_frac_digits : lconv->frac_digits;
     140            if (rightPrecision == CHAR_MAX)
     141                rightPrecision = 2;
     142        }
     143
     144        double value = va_arg(args,double);
     145        if (value < 0) {
     146            isNegative = true;
     147            value = -value;
     148        }
     149
     150        if (leftPrecision + rightPrecision > 255)
     151            return B_BAD_VALUE;
     152
     153        char number[256];
     154        sprintf(number, "%*.*f", (int)leftPrecision, (int)rightPrecision,
     155                value);
     156
     157        if (leftPrecision >= 0) {
     158           
     159        }
     160    }
     161    return B_OK;
     162}
     163
     164
     165ssize_t
     166strfmon(char *string, size_t maxSize, const char *format, ...)
     167{
     168    va_list args;
     169    va_start(args, format);
     170   
     171    ssize_t status = vstrfmon(string, maxSize, format, args);
     172   
     173    va_end(args);
     174
     175    if (status < B_OK) {
     176        errno = status;
     177        return -1;
     178    }
     179    return status;
     180}
     181
  • src/kits/locale/Currency.cpp

     
     1#include <Currency.h>
     2
     3// message archive field names
     4static const char *kArchivedCurrencyCodeName    = "be:currency code";
     5static const char *kArchivedDefaultSymbol       = "be:default symbol";
     6static const char *kArchivedDefaultFractionDigits
     7    = "be:default fraction digits";
     8
     9// constructor
     10BCurrency::BCurrency(const BCurrency &other)
     11    : fCurrencyCode(),
     12      fDefaultSymbol(),
     13      fDefaultFractionDigits(B_NO_INIT)
     14{
     15    *this = other;
     16}
     17
     18// constructor
     19BCurrency::BCurrency(BMessage *archive)
     20    : fCurrencyCode(),
     21      fDefaultSymbol(),
     22      fDefaultFractionDigits(B_NO_INIT)
     23{
     24    if (archive->FindString(kArchivedCurrencyCodeName, &fCurrencyCode)
     25            == B_OK
     26        && archive->FindString(kArchivedDefaultSymbol, &fDefaultSymbol)
     27            == B_OK
     28        && archive->FindInt32(kArchivedDefaultFractionDigits,
     29                              &fDefaultFractionDigits) == B_OK
     30        && _CheckData()) {
     31        // everything went fine
     32    } else
     33        _Unset(B_NO_INIT);
     34}
     35
     36// constructor
     37BCurrency::BCurrency(const char *currencyCode)
     38{
     39    // TODO: load currency from disk
     40}
     41
     42// destructor
     43BCurrency::~BCurrency()
     44{
     45}
     46
     47// InitCheck
     48status_t
     49BCurrency::InitCheck() const
     50{
     51    return (fDefaultFractionDigits < 0 ? fDefaultFractionDigits : B_OK);
     52}
     53
     54// Archive
     55status_t
     56BCurrency::Archive(BMessage *archive, bool deep) const
     57{
     58    status_t error = BArchivable::Archive(archive, deep);
     59    if (error == B_OK) {
     60        if (archive->AddString(kArchivedCurrencyCodeName, fCurrencyCode)
     61                == B_OK
     62            && archive->AddString(kArchivedDefaultSymbol, fDefaultSymbol)
     63                == B_OK
     64            && archive->AddInt32(kArchivedDefaultFractionDigits,
     65                                 fDefaultFractionDigits) == B_OK) {
     66            // everything went fine
     67        } else
     68            error = B_ERROR;
     69    }
     70    return error;
     71}
     72
     73// Instantiate
     74_EXPORT
     75BArchivable *
     76BCurrency::Instantiate(BMessage *archive)
     77{
     78    if (!validate_instantiation(archive, "BCurrency"))
     79        return NULL;
     80    return new BCurrency(archive);
     81}
     82
     83// CurrencyCode
     84const char *
     85BCurrency::CurrencyCode() const
     86{
     87    return (InitCheck() == B_OK ? fCurrencyCode.String() : NULL);
     88}
     89
     90// DefaultSymbol
     91const char *
     92BCurrency::DefaultSymbol() const
     93{
     94    return (InitCheck() == B_OK ? fDefaultSymbol.String() : NULL);
     95}
     96
     97// DefaultFractionDigits
     98int32
     99BCurrency::DefaultFractionDigits() const
     100{
     101    return (InitCheck() == B_OK ? fDefaultFractionDigits : 0);
     102}
     103
     104// GetSymbol
     105status_t
     106BCurrency::GetSymbol(char *symbol, size_t maxSize, BLocale *locale)
     107{
     108    // check initialization and parameters
     109    if (InitCheck() != B_OK)
     110        return B_NO_INIT;
     111    if (symbol == NULL)
     112        return B_BAD_VALUE;
     113    // TODO: get symbol from locale
     114    // fall back to the default symbol
     115    if ((int32)maxSize <= fDefaultSymbol.Length())
     116        return EOVERFLOW;   // OpenBeOS: B_BUFFER_OVERFLOW
     117    strcpy(symbol, fDefaultSymbol.String());
     118    return B_OK;
     119}
     120
     121// GetSymbol
     122status_t
     123BCurrency::GetSymbol(BString *symbol, BLocale *locale)
     124{
     125    // check initialization and parameters
     126    if (InitCheck() != B_OK)
     127        return B_NO_INIT;
     128    if (symbol == NULL)
     129        return B_BAD_VALUE;
     130    // TODO: get symbol from locale
     131    // fall back to the default symbol