diff options
author | no-author <no-author@gcc.gnu.org> | 2004-03-18 22:52:39 +0000 |
---|---|---|
committer | no-author <no-author@gcc.gnu.org> | 2004-03-18 22:52:39 +0000 |
commit | 37938edeb9a221d2beed23bf9772e5cfbd853e59 (patch) | |
tree | 145433cdee4057620af1877754e58c0e635fe398 | |
parent | 2cbd6c30fa9c080759fb52447ed5b315c80ebc58 (diff) |
This commit was manufactured by cvs2svn to create branch
'tree-ssa-20020619-branch'.
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/tree-ssa-20020619-branch@79648 138bc75d-0d04-0410-961f-82ee72b054a4
117 files changed, 13055 insertions, 0 deletions
diff --git a/gcc/ada/5qsystem.ads b/gcc/ada/5qsystem.ads new file mode 100644 index 00000000000..4d17cdacde5 --- /dev/null +++ b/gcc/ada/5qsystem.ads @@ -0,0 +1,236 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT RUN-TIME COMPONENTS -- +-- -- +-- S Y S T E M -- +-- -- +-- S p e c -- +-- (OpenVMS 64bit GCC_ZCX DEC Threads Version) -- +-- -- +-- Copyright (C) 2004 Free Software Foundation, Inc. -- +-- -- +-- This specification is derived from the Ada Reference Manual for use with -- +-- GNAT. The copyright notice above, and the license provisions that follow -- +-- apply solely to the contents of the part following the private keyword. -- +-- -- +-- GNAT is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 2, or (at your option) any later ver- -- +-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- +-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- +-- for more details. You should have received a copy of the GNU General -- +-- Public License distributed with GNAT; see file COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- As a special exception, if other files instantiate generics from this -- +-- unit, or you link this unit with other files to produce an executable, -- +-- this unit does not by itself cause the resulting executable to be -- +-- covered by the GNU General Public License. This exception does not -- +-- however invalidate any other reasons why the executable file might be -- +-- covered by the GNU Public License. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- Extensive contributions were provided by Ada Core Technologies Inc. -- +-- -- +------------------------------------------------------------------------------ + +package System is +pragma Pure (System); +-- Note that we take advantage of the implementation permission to +-- make this unit Pure instead of Preelaborable, see RM 13.7(36) + + type Name is (SYSTEM_NAME_GNAT); + System_Name : constant Name := SYSTEM_NAME_GNAT; + + -- System-Dependent Named Numbers + + Min_Int : constant := Long_Long_Integer'First; + Max_Int : constant := Long_Long_Integer'Last; + + Max_Binary_Modulus : constant := 2 ** Long_Long_Integer'Size; + Max_Nonbinary_Modulus : constant := Integer'Last; + + Max_Base_Digits : constant := Long_Long_Float'Digits; + Max_Digits : constant := Long_Long_Float'Digits; + + Max_Mantissa : constant := 63; + Fine_Delta : constant := 2.0 ** (-Max_Mantissa); + + Tick : constant := 0.01; + + -- Storage-related Declarations + + type Address is private; + Null_Address : constant Address; + + Storage_Unit : constant := 8; + Word_Size : constant := 64; + Memory_Size : constant := 2 ** 64; + + -- Address comparison + + function "<" (Left, Right : Address) return Boolean; + function "<=" (Left, Right : Address) return Boolean; + function ">" (Left, Right : Address) return Boolean; + function ">=" (Left, Right : Address) return Boolean; + function "=" (Left, Right : Address) return Boolean; + + pragma Import (Intrinsic, "<"); + pragma Import (Intrinsic, "<="); + pragma Import (Intrinsic, ">"); + pragma Import (Intrinsic, ">="); + pragma Import (Intrinsic, "="); + + -- Other System-Dependent Declarations + + type Bit_Order is (High_Order_First, Low_Order_First); + Default_Bit_Order : constant Bit_Order := Low_Order_First; + + -- Priority-related Declarations (RM D.1) + + Max_Priority : constant Positive := 30; + Max_Interrupt_Priority : constant Positive := 31; + + subtype Any_Priority is Integer range 0 .. 31; + subtype Priority is Any_Priority range 0 .. 30; + subtype Interrupt_Priority is Any_Priority range 31 .. 31; + + Default_Priority : constant Priority := 15; + +private + + type Address is mod Memory_Size; + Null_Address : constant Address := 0; + + -------------------------------------- + -- System Implementation Parameters -- + -------------------------------------- + + -- These parameters provide information about the target that is used + -- by the compiler. They are in the private part of System, where they + -- can be accessed using the special circuitry in the Targparm unit + -- whose source should be consulted for more detailed descriptions + -- of the individual switch values. + + AAMP : constant Boolean := False; + Backend_Divide_Checks : constant Boolean := False; + Backend_Overflow_Checks : constant Boolean := False; + Command_Line_Args : constant Boolean := True; + Configurable_Run_Time : constant Boolean := False; + Denorm : constant Boolean := False; + Duration_32_Bits : constant Boolean := False; + Exit_Status_Supported : constant Boolean := True; + Fractional_Fixed_Ops : constant Boolean := False; + Frontend_Layout : constant Boolean := False; + Functions_Return_By_DSP : constant Boolean := False; + Machine_Overflows : constant Boolean := False; + Machine_Rounds : constant Boolean := True; + OpenVMS : constant Boolean := True; + Signed_Zeros : constant Boolean := True; + Stack_Check_Default : constant Boolean := True; + Stack_Check_Probes : constant Boolean := True; + Support_64_Bit_Divides : constant Boolean := True; + Support_Aggregates : constant Boolean := True; + Support_Composite_Assign : constant Boolean := True; + Support_Composite_Compare : constant Boolean := True; + Support_Long_Shifts : constant Boolean := True; + Suppress_Standard_Library : constant Boolean := False; + Use_Ada_Main_Program_Name : constant Boolean := False; + ZCX_By_Default : constant Boolean := True; + GCC_ZCX_Support : constant Boolean := True; + Front_End_ZCX_Support : constant Boolean := False; + + -- Obsolete entries, to be removed eventually (bootstrap issues!) + + High_Integrity_Mode : constant Boolean := False; + Long_Shifts_Inlined : constant Boolean := False; + + -------------------------- + -- Underlying Priorities -- + --------------------------- + + -- Important note: this section of the file must come AFTER the + -- definition of the system implementation parameters to ensure + -- that the value of these parameters is available for analysis + -- of the declarations here (using Rtsfind at compile time). + + -- The underlying priorities table provides a generalized mechanism + -- for mapping from Ada priorities to system priorities. In some + -- cases a 1-1 mapping is not the convenient or optimal choice. + + -- For DEC Threads OpenVMS, we use the full range of 31 priorities + -- in the Ada model, but map them by compression onto the more limited + -- range of priorities available in OpenVMS. + + -- To replace the default values of the Underlying_Priorities mapping, + -- copy this source file into your build directory, edit the file to + -- reflect your desired behavior, and recompile with the command: + + -- $ gcc -c -O3 -gnatpgn system.ads + + -- then recompile the run-time parts that depend on this package: + + -- $ gnatmake -a -gnatn -O3 <your application> + + -- then force rebuilding your application if you need different options: + + -- $ gnatmake -f <your options> <your application> + + type Priorities_Mapping is array (Any_Priority) of Integer; + pragma Suppress_Initialization (Priorities_Mapping); + -- Suppress initialization in case gnat.adc specifies Normalize_Scalars + + Underlying_Priorities : constant Priorities_Mapping := + + (Priority'First => 16, + + 1 => 17, + 2 => 18, + 3 => 18, + 4 => 18, + 5 => 18, + 6 => 19, + 7 => 19, + 8 => 19, + 9 => 20, + 10 => 20, + 11 => 21, + 12 => 21, + 13 => 22, + 14 => 23, + + Default_Priority => 24, + + 16 => 25, + 17 => 25, + 18 => 25, + 19 => 26, + 20 => 26, + 21 => 26, + 22 => 27, + 23 => 27, + 24 => 27, + 25 => 28, + 26 => 28, + 27 => 29, + 28 => 29, + 29 => 30, + + Priority'Last => 30, + + Interrupt_Priority => 31); + + ---------------------------- + -- Special VMS Interfaces -- + ---------------------------- + + procedure Lib_Stop (I : in Integer); + pragma Interface (C, Lib_Stop); + pragma Import_Procedure (Lib_Stop, "LIB$STOP", Mechanism => (Value)); + -- Interface to VMS condition handling. Used by RTSfind and pragma + -- {Import,Export}_Exception. Put here because this is the only + -- VMS specific package that doesn't drag in tasking. + +end System; diff --git a/gcc/ada/5xcrtl.ads b/gcc/ada/5xcrtl.ads new file mode 100644 index 00000000000..dd3292e384a --- /dev/null +++ b/gcc/ada/5xcrtl.ads @@ -0,0 +1,159 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT RUN-TIME COMPONENTS -- +-- -- +-- S Y S T E M . C R T L -- +-- -- +-- S p e c -- +-- -- +-- Copyright (C) 2004 Free Software Foundation, Inc. -- +-- -- +-- GNAT is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 2, or (at your option) any later ver- -- +-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- +-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- +-- for more details. You should have received a copy of the GNU General -- +-- Public License distributed with GNAT; see file COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- As a special exception, if other files instantiate generics from this -- +-- unit, or you link this unit with other files to produce an executable, -- +-- this unit does not by itself cause the resulting executable to be -- +-- covered by the GNU General Public License. This exception does not -- +-- however invalidate any other reasons why the executable file might be -- +-- covered by the GNU Public License. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- Extensive contributions were provided by Ada Core Technologies Inc. -- +-- -- +------------------------------------------------------------------------------ + +-- This package provides the low level interface to the C Run Time Library +-- on 64 bit VMS + +with System.Parameters; +package System.CRTL is +pragma Preelaborate (CRTL); + + subtype chars is System.Address; + -- Pointer to null-terminated array of characters + + subtype FILEs is System.Address; + -- Corresponds to the C type FILE* + + subtype int is Integer; + + type long is range -(2 ** (System.Parameters.long_bits - 1)) + .. +(2 ** (System.Parameters.long_bits - 1)) - 1; + + subtype off_t is Integer; + + type size_t is mod 2 ** Standard'Address_Size; + + function atoi (A : System.Address) return Integer; + pragma Import (C, atoi, "decc$atoi"); + + procedure clearerr (stream : FILEs); + pragma Import (C, clearerr, "decc$clearerr"); + + function fclose (stream : FILEs) return int; + pragma Import (C, fclose, "decc$fclose"); + + function fdopen (handle : int; mode : chars) return FILEs; + pragma Import (C, fdopen, "decc$fdopen"); + + function fflush (stream : FILEs) return int; + pragma Import (C, fflush, "decc$fflush"); + + function fgetc (stream : FILEs) return int; + pragma Import (C, fgetc, "decc$fgetc"); + + function fgets (strng : chars; n : int; stream : FILEs) return chars; + pragma Import (C, fgets, "decc$fgets"); + + function fopen (filename : chars; Mode : chars) return FILEs; + pragma Import (C, fopen, "decc$fopen"); + + function fputc (C : int; stream : FILEs) return int; + pragma Import (C, fputc, "decc$fputc"); + + function fputs (Strng : chars; Stream : FILEs) return int; + pragma Import (C, fputs, "decc$fputs"); + + procedure free (Ptr : System.Address); + pragma Import (C, free, "decc$free"); + + function freopen + (filename : chars; + mode : chars; + stream : FILEs) + return FILEs; + pragma Import (C, freopen, "decc$freopen"); + + function fseek + (stream : FILEs; + offset : long; + origin : int) + return int; + pragma Import (C, fseek, "decc$fseek"); + + function ftell (stream : FILEs) return long; + pragma Import (C, ftell, "decc$ftell"); + + function getenv (S : String) return System.Address; + pragma Import (C, getenv, "decc$getenv"); + + function isatty (handle : int) return int; + pragma Import (C, isatty, "decc$isatty"); + + function lseek (fd : int; offset : off_t; direction : int) return off_t; + pragma Import (C, lseek, "decc$lseek"); + + function malloc (Size : size_t) return System.Address; + pragma Import (C, malloc, "decc$_malloc64"); + + procedure memcpy (S1 : System.Address; S2 : System.Address; N : size_t); + pragma Import (C, memcpy, "decc$_memcpy64"); + + procedure memmove (S1 : System.Address; S2 : System.Address; N : size_t); + pragma Import (C, memmove, "decc$_memmove64"); + + procedure mktemp (template : chars); + pragma Import (C, mktemp, "decc$_mktemp64"); + + function read (fd : int; buffer : chars; nbytes : int) return int; + pragma Import (C, read, "decc$read"); + + function realloc + (Ptr : System.Address; Size : size_t) return System.Address; + pragma Import (C, realloc, "decc$_realloc64"); + + procedure rewind (stream : FILEs); + pragma Import (C, rewind, "decc$rewind"); + + function setvbuf + (stream : FILEs; + buffer : chars; + mode : int; + size : size_t) + return int; + pragma Import (C, setvbuf, "decc$setvbuf"); + + procedure tmpnam (string : chars); + pragma Import (C, tmpnam, "decc$_tmpnam64"); + + function tmpfile return FILEs; + pragma Import (C, tmpfile, "decc$tmpfile"); + + function ungetc (c : int; stream : FILEs) return int; + pragma Import (C, ungetc, "decc$ungetc"); + + function unlink (filename : chars) return int; + pragma Import (C, unlink, "decc$unlink"); + + function write (fd : int; buffer : chars; nbytes : int) return int; + pragma Import (C, write, "decc$write"); +end System.CRTL; diff --git a/gcc/ada/5zstchop.adb b/gcc/ada/5zstchop.adb new file mode 100644 index 00000000000..b19bb56f274 --- /dev/null +++ b/gcc/ada/5zstchop.adb @@ -0,0 +1,255 @@ +------------------------------------------------------------------------------ +-- -- +-- GNU ADA RUN-TIME LIBRARY (GNARL) COMPONENTS -- +-- -- +-- S Y S T E M . S T A C K _ C H E C K I N G . O P E R A T I O N S -- +-- -- +-- B o d y -- +-- -- +-- Copyright (C) 1999-2004 Free Software Foundation, Inc. -- +-- -- +-- GNARL is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 2, or (at your option) any later ver- -- +-- sion. GNARL is distributed in the hope that it will be useful, but WITH- -- +-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- +-- for more details. You should have received a copy of the GNU General -- +-- Public License distributed with GNARL; see file COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- As a special exception, if other files instantiate generics from this -- +-- unit, or you link this unit with other files to produce an executable, -- +-- this unit does not by itself cause the resulting executable to be -- +-- covered by the GNU General Public License. This exception does not -- +-- however invalidate any other reasons why the executable file might be -- +-- covered by the GNU Public License. -- +-- -- +-- GNARL was developed by the GNARL team at Florida State University. -- +-- Extensive contributions were provided by Ada Core Technologies, Inc. -- +-- -- +------------------------------------------------------------------------------ + +-- This is the VxWorks version of this package. +-- This file should be kept synchronized with the general implementation +-- provided by s-stchop.adb. + +pragma Restrictions (No_Elaboration_Code); +-- We want to guarantee the absence of elaboration code because the +-- binder does not handle references to this package. + +with Ada.Exceptions; + +with System.Storage_Elements; use System.Storage_Elements; +with System.Parameters; use System.Parameters; +with System.Soft_Links; +with Interfaces.C; +with System.OS_Interface; + +package body System.Stack_Checking.Operations is + + -- In order to have stack checking working appropriately on + -- VxWorks we need to extract the stack size information from the + -- VxWorks kernel itself. It means that the library for showing + -- task-related information needs to be linked into the VxWorks + -- system, when using stack checking. The TaskShow library can be + -- linked into the VxWorks system by either: + -- * defining INCLUDE_SHOW_ROUTINES in config.h when using + -- configuration header files, or + -- * selecting INCLUDE_TASK_SHOW when using the Tornado project + -- facility. + + function Set_Stack_Info (Stack : access Stack_Access) return Stack_Access; + + -- The function Set_Stack_Info is the actual function that updates + -- the cache containing a pointer to the Stack_Info. It may also + -- be used for detecting asynchronous abort in combination with + -- Invalidate_Self_Cache. + + -- Set_Stack_Info should do the following things in order: + -- 1) Get the Stack_Access value for the current task + -- 2) Set Stack.all to the value obtained in 1) + -- 3) Optionally Poll to check for asynchronous abort + + -- This order is important because if at any time a write to + -- the stack cache is pending, that write should be followed + -- by a Poll to prevent loosing signals. + + -- Note: This function must be compiled with Polling turned off + + -- Note: on systems like VxWorks and OS/2 with real thread-local storage, + -- Set_Stack_Info should return an access value for such local + -- storage. In those cases the cache will always be up-to-date. + + -- The following constants should be imported from some system-specific + -- constants package. The constants must be static for performance reasons. + + ---------------------------- + -- Invalidate_Stack_Cache -- + ---------------------------- + + procedure Invalidate_Stack_Cache (Any_Stack : Stack_Access) is + pragma Warnings (Off, Any_Stack); + begin + Cache := Null_Stack; + end Invalidate_Stack_Cache; + + -------------------- + -- Set_Stack_Info -- + -------------------- + + function Set_Stack_Info + (Stack : access Stack_Access) return Stack_Access + is + + -- Task descriptor that is handled internally by the VxWorks kernel + type Task_Descriptor is record + T_Id : Interfaces.C.int; -- task identifier + Td_Name : System.Address; -- task name + Td_Priority : Interfaces.C.int; -- task priority + Td_Status : Interfaces.C.int; -- task status + Td_Options : Interfaces.C.int; -- task option bits (see below) + Td_Entry : System.Address; -- original entry point of task + Td_Sp : System.Address; -- saved stack pointer + Td_PStackBase : System.Address; -- the bottom of the stack + Td_PStackLimit : System.Address; -- the effective end of the stack + Td_PStackEnd : System.Address; -- the actual end of the stack + Td_StackSize : Interfaces.C.int; -- size of stack in bytes + Td_StackCurrent : Interfaces.C.int; -- current stack usage in bytes + Td_StackHigh : Interfaces.C.int; -- maximum stack usage in bytes + Td_StackMargin : Interfaces.C.int; -- current stack margin in bytes + Td_ErrorStatus : Interfaces.C.int; -- most recent task error status + Td_Delay : Interfaces.C.int; -- delay/timeout ticks + end record; + + -- This VxWorks procedure fills in a specified task descriptor + -- for a specified task. + procedure TaskInfoGet (T_Id : System.OS_Interface.t_id; + Task_Desc : access Task_Descriptor); + pragma Import (C, TaskInfoGet, "taskInfoGet"); + + My_Stack : Stack_Access; + Task_Desc : aliased Task_Descriptor; + + begin + -- The order of steps 1 .. 3 is important, see specification. + + -- 1) Get the Stack_Access value for the current task + + My_Stack := Soft_Links.Get_Stack_Info.all; + + if My_Stack.Base = Null_Address then + + -- First invocation. Ask the VxWorks kernel about stack + -- values. + TaskInfoGet (System.OS_Interface.taskIdSelf, Task_Desc'Access); + + My_Stack.Size := System.Storage_Elements.Storage_Offset + (Task_Desc.Td_StackSize); + My_Stack.Base := Task_Desc.Td_PStackBase; + My_Stack.Limit := Task_Desc.Td_PStackLimit; + + end if; + + -- 2) Set Stack.all to the value obtained in 1) + + Stack.all := My_Stack; + + -- 3) Optionally Poll to check for asynchronous abort + + if Soft_Links.Check_Abort_Status.all /= 0 then + raise Standard'Abort_Signal; + end if; + + return My_Stack; -- Never trust the cached value, but return local copy! + end Set_Stack_Info; + + -------------------- + -- Set_Stack_Size -- + -------------------- + + -- Specify the stack size for the current frame. + + procedure Set_Stack_Size + (Stack_Size : System.Storage_Elements.Storage_Offset) + is + My_Stack : Stack_Access; + Frame_Address : constant System.Address := My_Stack'Address; + + begin + My_Stack := Stack_Check (Frame_Address); + + if Stack_Grows_Down then + My_Stack.Limit := My_Stack.Base - Stack_Size; + else + My_Stack.Limit := My_Stack.Base + Stack_Size; + end if; + end Set_Stack_Size; + + ----------------- + -- Stack_Check -- + ----------------- + + function Stack_Check + (Stack_Address : System.Address) return Stack_Access + is + type Frame_Marker is null record; + Marker : Frame_Marker; + Cached_Stack : constant Stack_Access := Cache; + Frame_Address : constant System.Address := Marker'Address; + + begin + -- This function first does a "cheap" check which is correct + -- if it succeeds. In case of failure, the full check is done. + -- Ideally the cheap check should be done in an optimized manner, + -- or be inlined. + + if (Stack_Grows_Down and then + (Frame_Address <= Cached_Stack.Base + and + Stack_Address > Cached_Stack.Limit)) + or else + (not Stack_Grows_Down and then + (Frame_Address >= Cached_Stack.Base + and + Stack_Address < Cached_Stack.Limit)) + then + -- Cached_Stack is valid as it passed the stack check + return Cached_Stack; + end if; + + Full_Check : + declare + My_Stack : constant Stack_Access := Set_Stack_Info (Cache'Access); + -- At this point Stack.all might already be invalid, so + -- it is essential to use our local copy of Stack! + + begin + if (Stack_Grows_Down and then + Stack_Address < My_Stack.Limit) + or else + (not Stack_Grows_Down and then + Stack_Address > My_Stack.Limit) + then + Ada.Exceptions.Raise_Exception + (E => Storage_Error'Identity, + Message => "stack overflow detected"); + end if; + + return My_Stack; + end Full_Check; + end Stack_Check; + + ------------------------ + -- Update_Stack_Cache -- + ------------------------ + + procedure Update_Stack_Cache (Stack : Stack_Access) is + begin + if not Multi_Processor then + Cache := Stack; + end if; + end Update_Stack_Cache; + +end System.Stack_Checking.Operations; diff --git a/gcc/ada/s-stchop.adb b/gcc/ada/s-stchop.adb new file mode 100644 index 00000000000..3a1b1e91a07 --- /dev/null +++ b/gcc/ada/s-stchop.adb @@ -0,0 +1,273 @@ +------------------------------------------------------------------------------ +-- -- +-- GNU ADA RUN-TIME LIBRARY (GNARL) COMPONENTS -- +-- -- +-- S Y S T E M . S T A C K _ C H E C K I N G . O P E R A T I O N S -- +-- -- +-- B o d y -- +-- -- +-- Copyright (C) 1999-2004 Free Software Foundation, Inc. -- +-- -- +-- GNARL is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 2, or (at your option) any later ver- -- +-- sion. GNARL is distributed in the hope that it will be useful, but WITH- -- +-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- +-- for more details. You should have received a copy of the GNU General -- +-- Public License distributed with GNARL; see file COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- As a special exception, if other files instantiate generics from this -- +-- unit, or you link this unit with other files to produce an executable, -- +-- this unit does not by itself cause the resulting executable to be -- +-- covered by the GNU General Public License. This exception does not -- +-- however invalidate any other reasons why the executable file might be -- +-- covered by the GNU Public License. -- +-- -- +-- GNARL was developed by the GNARL team at Florida State University. -- +-- Extensive contributions were provided by Ada Core Technologies, Inc. -- +-- -- +------------------------------------------------------------------------------ + +-- This is the general implementation of this package. There is a VxWorks +-- specific version of this package (5zstchop.adb). This file should +-- be kept synchronized with it. + +pragma Restrictions (No_Elaboration_Code); +-- We want to guarantee the absence of elaboration code because the +-- binder does not handle references to this package. + +with Ada.Exceptions; + +with System.Storage_Elements; use System.Storage_Elements; +with System.Parameters; use System.Parameters; +with System.Soft_Links; +with System.CRTL; + +package body System.Stack_Checking.Operations is + + Kilobyte : constant := 1024; + + function Set_Stack_Info (Stack : access Stack_Access) return Stack_Access; + + -- The function Set_Stack_Info is the actual function that updates + -- the cache containing a pointer to the Stack_Info. It may also + -- be used for detecting asynchronous abort in combination with + -- Invalidate_Self_Cache. + + -- Set_Stack_Info should do the following things in order: + -- 1) Get the Stack_Access value for the current task + -- 2) Set Stack.all to the value obtained in 1) + -- 3) Optionally Poll to check for asynchronous abort + + -- This order is important because if at any time a write to + -- the stack cache is pending, that write should be followed + -- by a Poll to prevent loosing signals. + + -- Note: This function must be compiled with Polling turned off + + -- Note: on systems like VxWorks and OS/2 with real thread-local storage, + -- Set_Stack_Info should return an access value for such local + -- storage. In those cases the cache will always be up-to-date. + + -- The following constants should be imported from some system-specific + -- constants package. The constants must be static for performance reasons. + + ---------------------------- + -- Invalidate_Stack_Cache -- + ---------------------------- + + procedure Invalidate_Stack_Cache (Any_Stack : Stack_Access) is + pragma Warnings (Off, Any_Stack); + begin + Cache := Null_Stack; + end Invalidate_Stack_Cache; + + -------------------- + -- Set_Stack_Info -- + -------------------- + + function Set_Stack_Info + (Stack : access Stack_Access) return Stack_Access + is + type Frame_Mark is null record; + Frame_Location : Frame_Mark; + Frame_Address : constant Address := Frame_Location'Address; + + My_Stack : Stack_Access; + Limit_Chars : System.Address; + Limit : Integer; + + begin + -- The order of steps 1 .. 3 is important, see specification. + + -- 1) Get the Stack_Access value for the current task + + My_Stack := Soft_Links.Get_Stack_Info.all; + + if My_Stack.Base = Null_Address then + + -- First invocation, initialize based on the assumption that + -- there are Environment_Stack_Size bytes available beyond + -- the current frame address. + + if My_Stack.Size = 0 then + My_Stack.Size := Storage_Offset (Default_Env_Stack_Size); + + -- When the environment variable GNAT_STACK_LIMIT is set, + -- set Environment_Stack_Size to that number of kB. + + Limit_Chars := System.CRTL.getenv ("GNAT_STACK_LIMIT" & ASCII.NUL); + + if Limit_Chars /= Null_Address then + Limit := System.CRTL.atoi (Limit_Chars); + + if Limit >= 0 then + My_Stack.Size := Storage_Offset (Limit) * Kilobyte; + end if; + end if; + end if; + + My_Stack.Base := Frame_Address; + + if Stack_Grows_Down then + + -- Prevent wrap-around on too big stack sizes + + My_Stack.Limit := My_Stack.Base - My_Stack.Size; + + if My_Stack.Limit > My_Stack.Base then + My_Stack.Limit := Address'First; + end if; + + else + My_Stack.Limit := My_Stack.Base + My_Stack.Size; + + -- Prevent wrap-around on too big stack sizes + + if My_Stack.Limit < My_Stack.Base then + My_Stack.Limit := Address'Last; + end if; + end if; + end if; + + -- 2) Set Stack.all to the value obtained in 1) + + Stack.all := My_Stack; + + -- 3) Optionally Poll to check for asynchronous abort + + if Soft_Links.Check_Abort_Status.all /= 0 then + raise Standard'Abort_Signal; + end if; + + return My_Stack; -- Never trust the cached value, but return local copy! + end Set_Stack_Info; + + -------------------- + -- Set_Stack_Size -- + -------------------- + + -- Specify the stack size for the current frame. + + procedure Set_Stack_Size + (Stack_Size : System.Storage_Elements.Storage_Offset) + is + My_Stack : Stack_Access; + Frame_Address : constant System.Address := My_Stack'Address; + + begin + My_Stack := Stack_Check (Frame_Address); + + if Stack_Grows_Down then + My_Stack.Limit := My_Stack.Base - Stack_Size; + else + My_Stack.Limit := My_Stack.Base + Stack_Size; + end if; + end Set_Stack_Size; + + ----------------- + -- Stack_Check -- + ----------------- + + function Stack_Check + (Stack_Address : System.Address) return Stack_Access + is + type Frame_Marker is null record; + Marker : Frame_Marker; + Cached_Stack : constant Stack_Access := Cache; + Frame_Address : constant System.Address := Marker'Address; + + begin + -- This function first does a "cheap" check which is correct + -- if it succeeds. In case of failure, the full check is done. + -- Ideally the cheap check should be done in an optimized manner, + -- or be inlined. + + if (Stack_Grows_Down and then + (Frame_Address <= Cached_Stack.Base + and + Stack_Address > Cached_Stack.Limit)) + or else + (not Stack_Grows_Down and then + (Frame_Address >= Cached_Stack.Base + and + Stack_Address < Cached_Stack.Limit)) + then + -- Cached_Stack is valid as it passed the stack check + return Cached_Stack; + end if; + + Full_Check : + declare + My_Stack : constant Stack_Access := Set_Stack_Info (Cache'Access); + -- At this point Stack.all might already be invalid, so + -- it is essential to use our local copy of Stack! + + begin + if (Stack_Grows_Down and then + (not (Frame_Address <= My_Stack.Base))) + or else + (not Stack_Grows_Down and then + (not (Frame_Address >= My_Stack.Base))) + then + -- The returned Base is lower than the stored one, + -- so assume that the original one wasn't right and use the + -- current Frame_Address as new one. This allows initializing + -- Base with the Frame_Address as approximation. + -- During initialization the Frame_Address will be close to + -- the stack base anyway: the difference should be compensated + -- for in the stack reserve. + + My_Stack.Base := Frame_Address; + end if; + + if (Stack_Grows_Down and then + Stack_Address < My_Stack.Limit) + or else + (not Stack_Grows_Down and then + Stack_Address > My_Stack.Limit) + then + Ada.Exceptions.Raise_Exception + (E => Storage_Error'Identity, + Message => "stack overflow detected"); + end if; + + return My_Stack; + end Full_Check; + end Stack_Check; + + ------------------------ + -- Update_Stack_Cache -- + ------------------------ + + procedure Update_Stack_Cache (Stack : Stack_Access) is + begin + if not Multi_Processor then + Cache := Stack; + end if; + end Update_Stack_Cache; + +end System.Stack_Checking.Operations; diff --git a/gcc/ada/s-stchop.ads b/gcc/ada/s-stchop.ads new file mode 100644 index 00000000000..10217204d6f --- /dev/null +++ b/gcc/ada/s-stchop.ads @@ -0,0 +1,74 @@ +------------------------------------------------------------------------------ +-- -- +-- GNU ADA RUN-TIME LIBRARY (GNARL) COMPONENTS -- +-- -- +-- S Y S T E M . S T A C K _ C H E C K I N G . O P E R A T I O N S -- +-- -- +-- S p e c -- +-- -- +-- Copyright (C) 1999-2004 Free Software Foundation, Inc. -- +-- -- +-- GNARL is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 2, or (at your option) any later ver- -- +-- sion. GNARL is distributed in the hope that it will be useful, but WITH- -- +-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- +-- for more details. You should have received a copy of the GNU General -- +-- Public License distributed with GNARL; see file COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- As a special exception, if other files instantiate generics from this -- +-- unit, or you link this unit with other files to produce an executable, -- +-- this unit does not by itself cause the resulting executable to be -- +-- covered by the GNU General Public License. This exception does not -- +-- however invalidate any other reasons why the executable file might be -- +-- covered by the GNU Public License. -- +-- -- +-- GNARL was developed by the GNARL team at Florida State University. -- +-- Extensive contributions were provided by Ada Core Technologies, Inc. -- +-- -- +------------------------------------------------------------------------------ + +-- This package provides a implementation of stack checking operations +-- using comparison with stack base and limit. + +pragma Restrictions (No_Elaboration_Code); +-- We want to guarantee the absence of elaboration code because the +-- binder does not handle references to this package. + +with System.Storage_Elements; + +pragma Polling (Off); +-- Turn off polling, we do not want polling to take place during stack +-- checking operations. It causes infinite loops and other problems. + +package System.Stack_Checking.Operations is + procedure Set_Stack_Size + (Stack_Size : System.Storage_Elements.Storage_Offset); + -- Specify the stack size for the current task. + + procedure Update_Stack_Cache (Stack : Stack_Access); + -- Set the stack cache for the current task. Note that this is only + -- for optimization purposes, nothing can be assumed about the + -- contents of the cache at any time, see Set_Stack_Info. + + procedure Invalidate_Stack_Cache (Any_Stack : Stack_Access); + -- Invalidate cache entries for the task T that owns Any_Stack. + -- This causes the Set_Stack_Info function to be called during + -- the next stack check done by T. This can be used to interrupt + -- task T asynchronously. + -- Stack_Check should be called in loops for this to work reliably. + + function Stack_Check (Stack_Address : System.Address) return Stack_Access; + -- This version of Stack_Check should not be inlined. + +private + + Cache : aliased Stack_Access := Null_Stack; + + pragma Export (C, Cache, "_gnat_stack_cache"); + pragma Export (C, Stack_Check, "_gnat_stack_check"); + +end System.Stack_Checking.Operations; diff --git a/gcc/config/h8300/t-rtems b/gcc/config/h8300/t-rtems new file mode 100644 index 00000000000..104ee2366f1 --- /dev/null +++ b/gcc/config/h8300/t-rtems @@ -0,0 +1,7 @@ +# Custom multilibs for RTEMS + +# -mn is not applicable to RTEMS (-mn implies 16bit void*) + +MULTILIB_OPTIONS = mh/ms mint32 +MULTILIB_DIRNAMES = h8300h h8300s int32 +MULTILIB_EXCEPTIONS = mint32 diff --git a/gcc/config/host-linux.c b/gcc/config/host-linux.c new file mode 100644 index 00000000000..7302d381dbe --- /dev/null +++ b/gcc/config/host-linux.c @@ -0,0 +1,137 @@ +/* Linux host-specific hook definitions. + Copyright (C) 2004 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include <sys/mman.h> +#include "hosthooks.h" +#include "hosthooks-def.h" + + +/* Linux has a feature called exec-shield-randomize that perturbs the + address of non-fixed mapped segments by a (relatively) small amount. + The feature is intended to make it harder to attack the system with + buffer overflow attacks, since every invocation of a program will + have its libraries and data segments at slightly different addresses. + + This feature causes us problems with PCH because it makes it that + much harder to acquire a stable location at which to map our PCH + data file. + + [ The feature causes other points of non-determinism within the + compiler as well, so we'd *really* like to be able to have the + driver disable exec-shield-randomize for the process group, but + that isn't possible at present. ] + + We're going to try several things: + + * Select an architecture specific address as "likely" and see + if that's free. For our 64-bit hosts, we can easily choose + an address in Never Never Land. + + * If exec-shield-randomize is disabled, then just use the + address chosen by mmap in step one. + + * If exec-shield-randomize is enabled, then temporarily allocate + 32M of memory as a buffer, then allocate PCH memory, then + free the buffer. The theory here is that the perturbation is + no more than 16M, and so by allocating our buffer larger than + that we make it considerably more likely that the address will + be free when we want to load the data back. +*/ + +#undef HOST_HOOKS_GT_PCH_GET_ADDRESS +#define HOST_HOOKS_GT_PCH_GET_ADDRESS linux_gt_pch_get_address + +/* For various ports, try to guess a fixed spot in the vm space + that's probably free. */ +#if defined(__alpha) +# define TRY_EMPTY_VM_SPACE 0x10000000000 +#elif defined(__ia64) +# define TRY_EMPTY_VM_SPACE 0x2000000100000000 +#elif defined(__x86_64) +# define TRY_EMPTY_VM_SPACE 0x1000000000 +#elif defined(__i386) +# define TRY_EMPTY_VM_SPACE 0x60000000 +#else +# define TRY_EMPTY_VM_SPACE 0 +#endif + +/* Determine a location where we might be able to reliably allocate SIZE + bytes. FD is the PCH file, though we should return with the file + unmapped. */ + +static void * +linux_gt_pch_get_address (size_t size, int fd) +{ + size_t buffer_size = 32 * 1024 * 1024; + void *addr, *buffer; + FILE *f; + bool randomize_on; + + addr = mmap ((void *)TRY_EMPTY_VM_SPACE, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE, fd, 0); + + /* If we failed the map, that means there's *no* free space. */ + if (addr == (void *) MAP_FAILED) + return NULL; + /* Unmap the area before returning. */ + munmap (addr, size); + + /* If we got the exact area we requested, then that's great. */ + if (TRY_EMPTY_VM_SPACE && addr == (void *) TRY_EMPTY_VM_SPACE) + return addr; + + /* If we didn't, then we need to look to see if randomization is on. */ + f = fopen ("/proc/sys/kernel/exec-shield-randomize", "r"); + randomize_on = false; + if (f != NULL) + { + char buf[100]; + size_t c; + + c = fread (buf, 1, sizeof buf - 1, f); + if (c > 0) + { + buf[c] = '\0'; + randomize_on = (atoi (buf) > 0); + } + fclose (f); + } + + /* If it isn't, then accept the address that mmap selected as fine. */ + if (!randomize_on) + return addr; + + /* Otherwise, we need to try again with buffer space. */ + buffer = mmap (0, buffer_size, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0); + addr = mmap (0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + if (buffer != (void *) MAP_FAILED) + munmap (buffer, buffer_size); + if (addr == (void *) MAP_FAILED) + return NULL; + munmap (addr, size); + + return addr; +} + + +const struct host_hooks host_hooks = HOST_HOOKS_INITIALIZER; diff --git a/gcc/config/host-solaris.c b/gcc/config/host-solaris.c new file mode 100644 index 00000000000..4fa7a5b1ad0 --- /dev/null +++ b/gcc/config/host-solaris.c @@ -0,0 +1,79 @@ +/* Solaris host-specific hook definitions. + Copyright (C) 2004 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include <sys/mman.h> +#include "hosthooks.h" +#include "hosthooks-def.h" + + +#undef HOST_HOOKS_GT_PCH_USE_ADDRESS +#define HOST_HOOKS_GT_PCH_USE_ADDRESS sol_gt_pch_use_address + +/* Map SIZE bytes of FD+OFFSET at BASE. Return 1 if we succeeded at + mapping the data at BASE, -1 if we couldn't. */ + +static int +sol_gt_pch_use_address (void *base, size_t size, int fd, size_t offset) +{ + void *addr; + + /* We're called with size == 0 if we're not planning to load a PCH + file at all. This allows the hook to free any static space that + we might have allocated at link time. */ + if (size == 0) + return -1; + + addr = mmap (base, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, + fd, offset); + + /* Solaris isn't good about honoring the mmap START parameter + without MAP_FIXED set. Before we give up, search the desired + address space with mincore to see if the space is really free. */ + if (addr != base) + { + size_t page_size = getpagesize(); + char one_byte; + size_t i; + + if (addr != (void *) MAP_FAILED) + munmap (addr, size); + + errno = 0; + for (i = 0; i < size; i += page_size) + if (mincore ((char *)base + i, page_size, (void *)&one_byte) == -1 + && errno == ENOMEM) + continue; /* The page is not mapped. */ + else + break; + + if (i >= size) + addr = mmap (base, size, + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, + fd, offset); + } + + return addr == base ? 1 : -1; +} + + +const struct host_hooks host_hooks = HOST_HOOKS_INITIALIZER; diff --git a/gcc/config/rs6000/t-rtems b/gcc/config/rs6000/t-rtems new file mode 100644 index 00000000000..364a22d2278 --- /dev/null +++ b/gcc/config/rs6000/t-rtems @@ -0,0 +1,86 @@ +# Multilibs for powerpc RTEMS targets. + +MULTILIB_OPTIONS = \ +mcpu=403/mcpu=505/mcpu=601/mcpu=602/mcpu=603/mcpu=603e/mcpu=604/mcpu=750/mcpu=821/mcpu=860 \ +Dmpc509/Dmpc8260 \ +D_OLD_EXCEPTIONS \ +msoft-float + +MULTILIB_DIRNAMES = \ +m403 m505 m601 m602 m603 m603e m604 m750 m821 m860 \ +mpc509 \ +mpc8260 \ +roe \ +nof + +MULTILIB_EXTRA_OPTS = mrelocatable-lib mno-eabi mstrict-align + +# MULTILIB_MATCHES = ${MULTILIB_MATCHES_FLOAT} +MULTILIB_MATCHES = ${MULTILIB_MATCHES_ENDIAN} \ + ${MULTILIB_MATCHES_SYSV} \ + mcpu?505/Dmpc505=mcpu?505/Dmpc509 + +# +# RTEMS old/new-exceptions handling +# +# old-exception processing is depredicated, therefore +# +# * Cpu-variants supporting new exception processing are build +# with new exception processing only +# * Cpu-variants not having been ported to new exception processing are +# build with old and new exception processing +# + +# Cpu-variants supporting new exception processing only +MULTILIB_NEW_EXCEPTIONS_ONLY = \ +*mcpu=604*/*D_OLD_EXCEPTIONS* \ +*mcpu=750*/*D_OLD_EXCEPTIONS* \ +*mcpu=821*/*D_OLD_EXCEPTIONS* \ +*Dmpc8260*/*D_OLD_EXCEPTIONS* \ +*mcpu=860*/*D_OLD_EXCEPTIONS* + +# Soft-float only, default implies msoft-float +# NOTE: Must match with MULTILIB_MATCHES_FLOAT and MULTILIB_MATCHES +MULTILIB_SOFTFLOAT_ONLY = \ +mcpu=403/*msoft-float* \ +mcpu=821/*msoft-float* \ +mcpu=860/*msoft-float* + +# Hard-float only, take out msoft-float +MULTILIB_HARDFLOAT_ONLY = \ +mcpu=505/*msoft-float* + +MULTILIB_EXCEPTIONS = + +# Disallow -D_OLD_EXCEPTIONS without other options +MULTILIB_EXCEPTIONS += D_OLD_EXCEPTIONS* + +# Disallow -Dppc and -Dmpc without other options +MULTILIB_EXCEPTIONS += Dppc* Dmpc* + +MULTILIB_EXCEPTIONS += \ +${MULTILIB_NEW_EXCEPTIONS_ONLY} \ +${MULTILIB_SOFTFLOAT_ONLY} \ +${MULTILIB_HARDFLOAT_ONLY} + +# Special rules +# Take out all variants we don't want +MULTILIB_EXCEPTIONS += mcpu=403/Dmpc509* +MULTILIB_EXCEPTIONS += mcpu=403/Dmpc8260* +MULTILIB_EXCEPTIONS += mcpu=505/Dmpc509* +MULTILIB_EXCEPTIONS += mcpu=505/Dmpc8260* +MULTILIB_EXCEPTIONS += mcpu=601/Dmpc509* +MULTILIB_EXCEPTIONS += mcpu=601/Dmpc8260* +MULTILIB_EXCEPTIONS += mcpu=602/Dmpc509* +MULTILIB_EXCEPTIONS += mcpu=602/Dmpc8260* +MULTILIB_EXCEPTIONS += mcpu=603/Dmpc509* +MULTILIB_EXCEPTIONS += mcpu=603/Dmpc8260* +MULTILIB_EXCEPTIONS += mcpu=603e/Dmpc509* +MULTILIB_EXCEPTIONS += mcpu=604/Dmpc509* +MULTILIB_EXCEPTIONS += mcpu=604/Dmpc8260* +MULTILIB_EXCEPTIONS += mcpu=750/Dmpc509* +MULTILIB_EXCEPTIONS += mcpu=750/Dmpc8260* +MULTILIB_EXCEPTIONS += mcpu=821/Dmpc509* +MULTILIB_EXCEPTIONS += mcpu=821/Dmpc8260* +MULTILIB_EXCEPTIONS += mcpu=860/Dmpc509* +MULTILIB_EXCEPTIONS += mcpu=860/Dmpc8260* diff --git a/gcc/config/x-linux b/gcc/config/x-linux new file mode 100644 index 00000000000..d14586b0b36 --- /dev/null +++ b/gcc/config/x-linux @@ -0,0 +1,4 @@ +host-linux.o : $(srcdir)/config/host-linux.c $(CONFIG_H) $(SYSTEM_H) \ + coretypes.h hosthooks.h hosthooks-def.h + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/host-linux.c diff --git a/gcc/config/x-solaris b/gcc/config/x-solaris new file mode 100644 index 00000000000..782f4a36802 --- /dev/null +++ b/gcc/config/x-solaris @@ -0,0 +1,4 @@ +host-solaris.o : $(srcdir)/config/host-solaris.c $(CONFIG_H) $(SYSTEM_H) \ + coretypes.h hosthooks.h hosthooks-def.h + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/host-solaris.c diff --git a/gcc/testsuite/g++.dg/eh/spec7.C b/gcc/testsuite/g++.dg/eh/spec7.C new file mode 100644 index 00000000000..08586a2af75 --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/spec7.C @@ -0,0 +1,35 @@ +// PR 14535 +// { dg-do run } +// { dg-options "-O -finline" } +// +// Original test case failure required that Raiser constructor be inlined. + +extern "C" void abort(); +bool destructor_called = false; + +struct B { + virtual void Run(){}; +}; + +struct D : public B { + virtual void Run() + { + struct O { + ~O() { destructor_called = true; }; + } o; + + struct Raiser { + Raiser() throw( int ) {throw 1;}; + } raiser; + }; +}; + +int main() { + try { + D d; + static_cast<B&>(d).Run(); + } catch (...) {} + + if (!destructor_called) + abort (); +} diff --git a/gcc/testsuite/g++.dg/ext/anon-struct4.C b/gcc/testsuite/g++.dg/ext/anon-struct4.C new file mode 100644 index 00000000000..f0b3b57f70d --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/anon-struct4.C @@ -0,0 +1,3 @@ +// PR c++/14401 + +struct { struct { int& i ; } bar ; } foo ; // { dg-error "" } diff --git a/gcc/testsuite/g++.dg/ext/attrib14.C b/gcc/testsuite/g++.dg/ext/attrib14.C new file mode 100644 index 00000000000..3a819e01d82 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attrib14.C @@ -0,0 +1,13 @@ +// PR c++/13170 +// The bogus attribute is ignored, but was in TYPE_ATTRIBUTES during +// parsing of the class, causing some variants to have it and some not. + +struct __attribute__((bogus)) A +{ + virtual ~A(); + void foo(const A&); + void bar(const A&); +}; // { dg-warning "ignored" "" } + +void A::foo(const A&) {} +void A::bar(const A& a) { foo(a); } diff --git a/gcc/testsuite/g++.dg/init/ctor3.C b/gcc/testsuite/g++.dg/init/ctor3.C new file mode 100644 index 00000000000..1678aaf2c4d --- /dev/null +++ b/gcc/testsuite/g++.dg/init/ctor3.C @@ -0,0 +1,6 @@ +// PR c++/14401 + +struct S { + S() {} // { dg-error "" } + const int i; +}; diff --git a/gcc/testsuite/g++.dg/init/ref11.C b/gcc/testsuite/g++.dg/init/ref11.C new file mode 100644 index 00000000000..b283e3a69be --- /dev/null +++ b/gcc/testsuite/g++.dg/init/ref11.C @@ -0,0 +1,13 @@ +// PR c++/14230 + +struct A { + A (); + A (const A&); + A& operator= (const A&); +}; + +struct D { + A a; +}; + +const A& z = D().a; diff --git a/gcc/testsuite/g++.dg/init/union1.C b/gcc/testsuite/g++.dg/init/union1.C new file mode 100644 index 00000000000..0049f442916 --- /dev/null +++ b/gcc/testsuite/g++.dg/init/union1.C @@ -0,0 +1,5 @@ +// PR c++/14401 + +union U { + int& i; // { dg-error "" } +}; diff --git a/gcc/testsuite/g++.dg/lookup/enum1.C b/gcc/testsuite/g++.dg/lookup/enum1.C new file mode 100644 index 00000000000..9422814e271 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/enum1.C @@ -0,0 +1,5 @@ +// PR c++/14476 + +struct tree_common { + enum tree_code code : 8; // { dg-error "" } +}; diff --git a/gcc/testsuite/g++.dg/lookup/struct2.C b/gcc/testsuite/g++.dg/lookup/struct2.C new file mode 100644 index 00000000000..a66f403c291 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/struct2.C @@ -0,0 +1,7 @@ +// PR c++/14510 + +struct c {}; +namespace A { + int c(struct c*req); +} +int A::c(struct c*req) {} diff --git a/gcc/testsuite/g++.dg/opt/eh1.C b/gcc/testsuite/g++.dg/opt/eh1.C new file mode 100644 index 00000000000..63a4d2ef35f --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/eh1.C @@ -0,0 +1,21 @@ +// PR middle-end/14477 +// { dg-do compile } +// { dg-options "-O2 -fno-default-inline" } + +struct A +{ + A(); +}; + +struct B +{ + B(const A*); +}; + +struct C +{ + B b; + C(int) : b(new A) {} +}; + +C c(0); diff --git a/gcc/testsuite/g++.dg/overload/ref1.C b/gcc/testsuite/g++.dg/overload/ref1.C new file mode 100644 index 00000000000..e239d88a438 --- /dev/null +++ b/gcc/testsuite/g++.dg/overload/ref1.C @@ -0,0 +1,21 @@ +// Copyright (C) 2004 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 5 Mar 2004 <nathan@codesourcery.com> + +// Origin: schmid@snake.iap.physik.tu-darmstadt.de +// Bug 14397: Bogus access error. + +struct S { + S (int); + S(S const&); + private: + S(S&); +}; + +S foo() +{ + int result = 0; + + S s ((0,S (result))); + + return S (result); +} diff --git a/gcc/testsuite/g++.dg/parse/builtin2.C b/gcc/testsuite/g++.dg/parse/builtin2.C new file mode 100644 index 00000000000..c524ea68416 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/builtin2.C @@ -0,0 +1,5 @@ +// PR c++/14432 +// { dg-options "" } + +struct Y {}; +Y y1; diff --git a/gcc/testsuite/g++.dg/parse/crash14.C b/gcc/testsuite/g++.dg/parse/crash14.C new file mode 100644 index 00000000000..b4cf49a9921 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/crash14.C @@ -0,0 +1,20 @@ +// { dg-do compile } +// Contributed by: Giovanni Bajo <giovannibajo at libero dot it> +// PR c++/14448: Fold constant initializers in templates + +template <int> struct A +{ + A(); +}; + + +template<typename T> void foo(T) +{ + static const int n=1+1; + A<n+1> a; +} + +void bar() +{ + foo(0); +} diff --git a/gcc/testsuite/g++.dg/parse/non-dependent3.C b/gcc/testsuite/g++.dg/parse/non-dependent3.C new file mode 100644 index 00000000000..9dfb99636a8 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/non-dependent3.C @@ -0,0 +1,17 @@ +// PR c++/14586 + +enum E { e }; + +E & operator |= (E &f1, const E &f2); + +E operator | (const E &f1, const E &f2) { + E result = f1; + result |= f2; + return result; +} + +template <typename> void foo () { + const E flags = e | e; +} + +template void foo<double> (); diff --git a/gcc/testsuite/g++.dg/parse/template14.C b/gcc/testsuite/g++.dg/parse/template14.C new file mode 100644 index 00000000000..ada87524352 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/template14.C @@ -0,0 +1,17 @@ +// PR c++/14550 + +struct A { + A(); +}; + +template <int> void foo() +{ + A *p = new A; +} + +void bar() +{ + foo<0>(); +} + + diff --git a/gcc/testsuite/g++.dg/template/spec12.C b/gcc/testsuite/g++.dg/template/spec12.C new file mode 100644 index 00000000000..7cf2e2f0aa2 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/spec12.C @@ -0,0 +1,18 @@ +// { dg-do compile } +// Contributed by: Wolfgang Bangerth <bangerth at dealii dot org> +// PR c++/14409: Accepts invalid function signature for explicit instantiation + +struct X +{ + template <typename U> + void foo (U) {} + + template <typename U> + void foo_const (U) const {} +}; + +template void X::foo (int); +template void X::foo_const (int) const; + +template void X::foo (int) const; // { dg-error "" } +template void X::foo_const (int); // { dg-error "" } diff --git a/gcc/testsuite/g++.dg/warn/Wunused-7.C b/gcc/testsuite/g++.dg/warn/Wunused-7.C new file mode 100644 index 00000000000..4281bc81569 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wunused-7.C @@ -0,0 +1,12 @@ +// PR c++/14481 +// { dg-options "-Wunused" } + +void func() +{ + struct mybitfields { + unsigned int s_field:8; + }; + struct mybitfields s; + s.s_field = 255; +}; + diff --git a/gcc/testsuite/gcc.c-torture/execute/20040309-1.c b/gcc/testsuite/gcc.c-torture/execute/20040309-1.c new file mode 100644 index 00000000000..49fa79560c6 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20040309-1.c @@ -0,0 +1,24 @@ +extern void abort (); + +int foo(unsigned short x) +{ + unsigned short y; + y = x > 32767 ? x - 32768 : 0; + return y; +} + +int main() +{ + if (foo (0) != 0) + abort (); + if (foo (32767) != 0) + abort (); + if (foo (32768) != 0) + abort (); + if (foo (32769) != 1) + abort (); + if (foo (65535) != 32767) + abort (); + return 0; +} + diff --git a/gcc/testsuite/gcc.c-torture/execute/20040311-1.c b/gcc/testsuite/gcc.c-torture/execute/20040311-1.c new file mode 100644 index 00000000000..013d869abf4 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20040311-1.c @@ -0,0 +1,68 @@ +/* Copyright (C) 2004 Free Software Foundation. + + Check that constant folding and RTL simplification of -(x >> y) doesn't + break anything and produces the expected results. + + Written by Roger Sayle, 11th March 2004. */ + +extern void abort (void); + +#define INT_BITS (sizeof(int)*8) + +int test1(int x) +{ + return -(x >> (INT_BITS-1)); +} + +int test2(unsigned int x) +{ + return -((int)(x >> (INT_BITS-1))); +} + +int test3(int x) +{ + int y; + y = INT_BITS-1; + return -(x >> y); +} + +int test4(unsigned int x) +{ + int y; + y = INT_BITS-1; + return -((int)(x >> y)); +} + +int main() +{ + if (test1(0) != 0) + abort (); + if (test1(1) != 0) + abort (); + if (test1(-1) != 1) + abort (); + + if (test2(0) != 0) + abort (); + if (test2(1) != 0) + abort (); + if (test2((unsigned int)-1) != -1) + abort (); + + if (test3(0) != 0) + abort (); + if (test3(1) != 0) + abort (); + if (test3(-1) != 1) + abort (); + + if (test4(0) != 0) + abort (); + if (test4(1) != 0) + abort (); + if (test4((unsigned int)-1) != -1) + abort (); + + return 0; +} + diff --git a/gcc/testsuite/gcc.c-torture/execute/20040313-1.c b/gcc/testsuite/gcc.c-torture/execute/20040313-1.c new file mode 100644 index 00000000000..c05fe730f0c --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20040313-1.c @@ -0,0 +1,17 @@ +/* PR middle-end/14470 */ +/* Origin: Lodewijk Voge <lvoge@cs.vu.nl> */ + +extern void abort(void); + +int main() +{ + int t[1025] = { 1024 }, d; + + d = 0; + d = t[d]++; + if (t[0] != 1025) + abort(); + if (d != 1024) + abort(); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/20040305-2.c b/gcc/testsuite/gcc.dg/20040305-2.c new file mode 100644 index 00000000000..b0423a25495 --- /dev/null +++ b/gcc/testsuite/gcc.dg/20040305-2.c @@ -0,0 +1,47 @@ +/* PR target/14262 */ +/* { dg-do run } */ + +typedef char ACS; +typedef char LSM; +typedef char PANEL; +typedef char DRIVE; +typedef struct { + ACS acs; + LSM lsm; +} LSMID; +typedef struct { + LSMID lsm_id; + PANEL panel; +} PANELID; +typedef struct { + PANELID panel_id; + DRIVE drive; +} DRIVEID; + +void sub (DRIVEID driveid) +{ + if (driveid.drive != 1) + abort (); + if (driveid.panel_id.panel != 2) + abort (); + if (driveid.panel_id.lsm_id.lsm != 3) + abort (); + if (driveid.panel_id.lsm_id.acs != 4) + abort (); +} + +int main(void) +{ + DRIVEID driveid; + + driveid.drive = 1; + driveid.panel_id.panel = 2; + driveid.panel_id.lsm_id.lsm = 3; + driveid.panel_id.lsm_id.acs = 4; + + sub(driveid); + + return 0; +} + + diff --git a/gcc/testsuite/gcc.dg/20040309-1.c b/gcc/testsuite/gcc.dg/20040309-1.c new file mode 100644 index 00000000000..736150731c7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/20040309-1.c @@ -0,0 +1,17 @@ +/* Test integer mod on ia64. There was a bug in the inline integer + division code. */ + +/* { dg-do run } */ +/* { dg-options "-minline-int-divide-max-throughput" { target ia64-*-* } } */ + +extern void abort (void); + +volatile int i = 10; +volatile int j = 10; + +int main() +{ + int k = i % j; + if (k != 0) abort(); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/20040310-1.c b/gcc/testsuite/gcc.dg/20040310-1.c new file mode 100644 index 00000000000..104e98d0889 --- /dev/null +++ b/gcc/testsuite/gcc.dg/20040310-1.c @@ -0,0 +1,34 @@ +/* This caused cc1 to segfault on s390x-ibm-linux + due to a bug in if_then_else_cond (combine.c). */ + +/* { dg-do compile } */ +/* { dg-options "-O1" } */ + +extern void use (unsigned int x); + +int main (void) +{ + union + { + unsigned int x; + unsigned long pad; + } A; + + struct + { + unsigned int x : 1; + } B; + + A.x = 1; + B.x = 1; + A.x /= B.x; + use (A.x); + + A.x = 1; + B.x = 1; + B.x /= A.x; + use (B.x); + + return 0; +} + diff --git a/gcc/testsuite/gcc.dg/20040311-2.c b/gcc/testsuite/gcc.dg/20040311-2.c new file mode 100644 index 00000000000..0d0d5da3259 --- /dev/null +++ b/gcc/testsuite/gcc.dg/20040311-2.c @@ -0,0 +1,36 @@ +/* PR target/14533 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fpic" } */ + +void bar (char *, int); + +extern char b[]; +extern int d, e; +struct S +{ + struct S *m; + int n; +} **g; + +void +foo (int x, char *y) +{ + struct S *h; + int k = 1, l; + +again: + for (h = *g; h != (struct S *) g; h = h->m) + { + if (k == 0 && h->n & 0x100000); + l = y - b; + if (e) + bar (b, l); + if (d) + bar (b, l); + } + if (k) + { + k = 0; + goto again; + } +} diff --git a/gcc/testsuite/gcc.dg/alias-2.c b/gcc/testsuite/gcc.dg/alias-2.c new file mode 100644 index 00000000000..d507416b0ff --- /dev/null +++ b/gcc/testsuite/gcc.dg/alias-2.c @@ -0,0 +1,16 @@ +// { dg-do compile } +// { dg-options "-Wstrict-aliasing=2 -fstrict-aliasing" } + +struct foo { + char c; + char d; + short s; + int i; +} bar; + +int +sub1 (long long int foobar) +{ + struct foo *tmp = (struct foo *) &foobar; // { dg-warning "type-punned pointer might" "" } + return tmp->i; +} diff --git a/gcc/testsuite/gcc.dg/builtins-34.c b/gcc/testsuite/gcc.dg/builtins-34.c new file mode 100644 index 00000000000..d2bf4d41219 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtins-34.c @@ -0,0 +1,66 @@ +/* Copyright (C) 2004 Free Software Foundation. + + Check that exp10, exp10f, exp10l, exp2, exp2f, exp2l, pow10, pow10f + and pow10l built-in functions compile. + + Written by Uros Bizjak, 13th February 2004. */ + +/* { dg-do compile } */ +/* { dg-options "-O2 -ffast-math" } */ + +extern double exp10(double); +extern double exp2(double); +extern double pow10(double); +extern float exp10f(float); +extern float exp2f(float); +extern float pow10f(float); +extern long double exp10l(long double); +extern long double exp2l(long double); +extern long double pow10l(long double); + + +double test1(double x) +{ + return exp10(x); +} + +double test2(double x) +{ + return exp2(x); +} + +double test3(double x) +{ + return pow10(x); +} + +float test1f(float x) +{ + return exp10f(x); +} + +float test2f(float x) +{ + return exp2f(x); +} + +float test3f(float x) +{ + return pow10f(x); +} + +long double test1l(long double x) +{ + return exp10l(x); +} + +long double test2l(long double x) +{ + return exp2l(x); +} + +long double test3l(long double x) +{ + return pow10l(x); +} + diff --git a/gcc/testsuite/gcc.dg/c90-dupqual-1.c b/gcc/testsuite/gcc.dg/c90-dupqual-1.c new file mode 100644 index 00000000000..14838c7367f --- /dev/null +++ b/gcc/testsuite/gcc.dg/c90-dupqual-1.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */ + +typedef const int CI; +const const int c1; /* { dg-error "duplicate" } */ +const CI c2; /* { dg-error "duplicate" } */ +const CI *c3; /* { dg-error "duplicate" } */ + +typedef volatile int VI; +volatile volatile int v1; /* { dg-error "duplicate" } */ +volatile VI v2; /* { dg-error "duplicate" } */ +volatile VI *v3; /* { dg-error "duplicate" } */ diff --git a/gcc/testsuite/gcc.dg/c99-dupqual-1.c b/gcc/testsuite/gcc.dg/c99-dupqual-1.c new file mode 100644 index 00000000000..2e6d7e1bc5a --- /dev/null +++ b/gcc/testsuite/gcc.dg/c99-dupqual-1.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */ + +typedef const int CI; +const const int c1; /* { dg-bogus "duplicate" } */ +const CI c2; /* { dg-bogus "duplicate" } */ +const CI *c3; /* { dg-bogus "duplicate" } */ + +typedef volatile int VI; +volatile volatile int v1; /* { dg-bogus "duplicate" } */ +volatile VI v2; /* { dg-bogus "duplicate" } */ +volatile VI *v3; /* { dg-bogus "duplicate" } */ diff --git a/gcc/testsuite/gcc.dg/compat/struct-by-value-21_main.c b/gcc/testsuite/gcc.dg/compat/struct-by-value-21_main.c new file mode 100644 index 00000000000..b722bccd2ca --- /dev/null +++ b/gcc/testsuite/gcc.dg/compat/struct-by-value-21_main.c @@ -0,0 +1,13 @@ +/* Test function argument passing. This was written when correcting + a deviation from the ABI on SPARC64 between 3.3 and 3.4. */ + +extern void struct_by_value_21_x (void); +extern void exit (int); +int fails; + +int +main () +{ + struct_by_value_21_x (); + exit (0); +} diff --git a/gcc/testsuite/gcc.dg/compat/struct-by-value-21_x.c b/gcc/testsuite/gcc.dg/compat/struct-by-value-21_x.c new file mode 100644 index 00000000000..3b01ba86eb1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/compat/struct-by-value-21_x.c @@ -0,0 +1,168 @@ +#include "compat-common.h" + +#define T(TYPE) \ +TYPE g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE; \ +TYPE g5s##TYPE, g6s##TYPE, g7s##TYPE, g8s##TYPE; \ +TYPE g9s##TYPE, g10s##TYPE, g11s##TYPE, g12s##TYPE; \ +TYPE g13s##TYPE, g14s##TYPE, g15s##TYPE, g16s##TYPE; \ + \ +extern void init##TYPE (TYPE *p, int i); \ +extern void checkg##TYPE (void); \ +extern void \ +test##TYPE (TYPE s1, TYPE s2, TYPE s3, TYPE s4, \ + TYPE s5, TYPE s6, TYPE s7, TYPE s8, \ + TYPE s9, TYPE s10, TYPE s11, TYPE s12, \ + TYPE s13, TYPE s14, TYPE s15, TYPE s16); \ +extern void testva##TYPE (int n, ...); \ + \ +void \ +test2_##TYPE (TYPE s1, TYPE s2, TYPE s3, TYPE s4, \ + TYPE s5, TYPE s6, TYPE s7, TYPE s8) \ +{ \ + test##TYPE (s1, g2s##TYPE, s2, g4s##TYPE, \ + s3, g6s##TYPE, s4, g8s##TYPE, \ + s5, g10s##TYPE, s6, g12s##TYPE, \ + s7, g14s##TYPE, s8, g16s##TYPE); \ +} \ + \ +void \ +testit##TYPE (void) \ +{ \ + DEBUG_FPUTS (#TYPE); \ + DEBUG_FPUTS (" init: "); \ + init##TYPE ( &g1s##TYPE, 1); \ + init##TYPE ( &g2s##TYPE, 2); \ + init##TYPE ( &g3s##TYPE, 3); \ + init##TYPE ( &g4s##TYPE, 4); \ + init##TYPE ( &g5s##TYPE, 5); \ + init##TYPE ( &g6s##TYPE, 6); \ + init##TYPE ( &g7s##TYPE, 7); \ + init##TYPE ( &g8s##TYPE, 8); \ + init##TYPE ( &g9s##TYPE, 9); \ + init##TYPE (&g10s##TYPE, 10); \ + init##TYPE (&g11s##TYPE, 11); \ + init##TYPE (&g12s##TYPE, 12); \ + init##TYPE (&g13s##TYPE, 13); \ + init##TYPE (&g14s##TYPE, 14); \ + init##TYPE (&g15s##TYPE, 15); \ + init##TYPE (&g16s##TYPE, 16); \ + checkg##TYPE (); \ + DEBUG_NL; \ + DEBUG_FPUTS (#TYPE); \ + DEBUG_FPUTS (" test: "); \ + test##TYPE (g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE, g6s##TYPE, g7s##TYPE, g8s##TYPE, \ + g9s##TYPE, g10s##TYPE, g11s##TYPE, g12s##TYPE, \ + g13s##TYPE, g14s##TYPE, g15s##TYPE, g16s##TYPE); \ + DEBUG_NL; \ + DEBUG_FPUTS (#TYPE); \ + DEBUG_FPUTS (" testva:"); \ + DEBUG_NL; \ + testva##TYPE (1, \ + g1s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (2, \ + g1s##TYPE, g2s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (3, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (4, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (5, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (6, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE, g6s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (7, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE, g6s##TYPE, g7s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (8, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE, g6s##TYPE, g7s##TYPE, g8s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (9, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE, g6s##TYPE, g7s##TYPE, g8s##TYPE, \ + g9s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (10, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE, g6s##TYPE, g7s##TYPE, g8s##TYPE, \ + g9s##TYPE, g10s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (11, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE, g6s##TYPE, g7s##TYPE, g8s##TYPE, \ + g9s##TYPE, g10s##TYPE, g11s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (12, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE, g6s##TYPE, g7s##TYPE, g8s##TYPE, \ + g9s##TYPE, g10s##TYPE, g11s##TYPE, g12s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (13, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE, g6s##TYPE, g7s##TYPE, g8s##TYPE, \ + g9s##TYPE, g10s##TYPE, g11s##TYPE, g12s##TYPE, \ + g13s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (14, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE, g6s##TYPE, g7s##TYPE, g8s##TYPE, \ + g9s##TYPE, g10s##TYPE, g11s##TYPE, g12s##TYPE, \ + g13s##TYPE, g14s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (15, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE, g6s##TYPE, g7s##TYPE, g8s##TYPE, \ + g9s##TYPE, g10s##TYPE, g11s##TYPE, g12s##TYPE, \ + g13s##TYPE, g14s##TYPE, g15s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (16, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE, g6s##TYPE, g7s##TYPE, g8s##TYPE, \ + g9s##TYPE, g10s##TYPE, g11s##TYPE, g12s##TYPE, \ + g13s##TYPE, g14s##TYPE, g15s##TYPE, g16s##TYPE); \ + DEBUG_NL; \ + DEBUG_FPUTS (#TYPE); \ + DEBUG_FPUTS (" test2:"); \ + test2_##TYPE (g1s##TYPE, g3s##TYPE, g5s##TYPE, g7s##TYPE, \ + g9s##TYPE, g11s##TYPE, g13s##TYPE, g15s##TYPE); \ + DEBUG_NL; \ +} + +#include "mixed-struct-defs.h" +#include "mixed-struct-check.h" + +T(Sfi) +T(Sfii) +T(Sfifi) +T(Sfiifii) + +#undef T + +void +struct_by_value_21_x () +{ +DEBUG_INIT + +#define T(TYPE) testit##TYPE (); + +T(Sfi) +T(Sfii) +T(Sfifi) +T(Sfiifii) + +DEBUG_FINI + +if (fails != 0) + abort (); + +#undef T +} diff --git a/gcc/testsuite/gcc.dg/compat/struct-by-value-21_y.c b/gcc/testsuite/gcc.dg/compat/struct-by-value-21_y.c new file mode 100644 index 00000000000..fc06d9d4fce --- /dev/null +++ b/gcc/testsuite/gcc.dg/compat/struct-by-value-21_y.c @@ -0,0 +1,86 @@ +#include <stdarg.h> + +#include "compat-common.h" + +#ifdef SKIP_VA +const int test_va = 0; +#else +const int test_va = 1; +#endif + +#include "mixed-struct-defs.h" +#include "mixed-struct-init.h" + +#define T(TYPE) \ +extern void check##TYPE (TYPE x, int i); \ +extern TYPE g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE; \ +extern TYPE g5s##TYPE, g6s##TYPE, g7s##TYPE, g8s##TYPE; \ +extern TYPE g9s##TYPE, g10s##TYPE, g11s##TYPE, g12s##TYPE; \ +extern TYPE g13s##TYPE, g14s##TYPE, g15s##TYPE, g16s##TYPE; \ + \ +void \ +checkg##TYPE (void) \ +{ \ + check##TYPE ( g1s##TYPE, 1); \ + check##TYPE ( g2s##TYPE, 2); \ + check##TYPE ( g3s##TYPE, 3); \ + check##TYPE ( g4s##TYPE, 4); \ + check##TYPE ( g5s##TYPE, 5); \ + check##TYPE ( g6s##TYPE, 6); \ + check##TYPE ( g7s##TYPE, 7); \ + check##TYPE ( g8s##TYPE, 8); \ + check##TYPE ( g9s##TYPE, 9); \ + check##TYPE ( g10s##TYPE, 10); \ + check##TYPE ( g11s##TYPE, 11); \ + check##TYPE ( g12s##TYPE, 12); \ + check##TYPE ( g13s##TYPE, 13); \ + check##TYPE ( g14s##TYPE, 14); \ + check##TYPE ( g15s##TYPE, 15); \ + check##TYPE ( g16s##TYPE, 16); \ +} \ + \ +void \ +test##TYPE (TYPE s1, TYPE s2, TYPE s3, TYPE s4, \ + TYPE s5, TYPE s6, TYPE s7, TYPE s8, \ + TYPE s9, TYPE s10, TYPE s11, TYPE s12, \ + TYPE s13, TYPE s14, TYPE s15, TYPE s16) \ +{ \ + check##TYPE (s1, 1); \ + check##TYPE (s2, 2); \ + check##TYPE (s3, 3); \ + check##TYPE (s4, 4); \ + check##TYPE (s5, 5); \ + check##TYPE (s6, 6); \ + check##TYPE (s7, 7); \ + check##TYPE (s8, 8); \ + check##TYPE (s9, 9); \ + check##TYPE (s10, 10); \ + check##TYPE (s11, 11); \ + check##TYPE (s12, 12); \ + check##TYPE (s13, 13); \ + check##TYPE (s14, 14); \ + check##TYPE (s15, 15); \ + check##TYPE (s16, 16); \ +} \ + \ +void \ +testva##TYPE (int n, ...) \ +{ \ + int i; \ + va_list ap; \ + if (test_va) \ + { \ + va_start (ap, n); \ + for (i = 0; i < n; i++) \ + { \ + TYPE t = va_arg (ap, TYPE); \ + check##TYPE (t, i+1); \ + } \ + va_end (ap); \ + } \ +} + +T(Sfi) +T(Sfii) +T(Sfifi) +T(Sfiifii) diff --git a/gcc/testsuite/gcc.dg/compat/struct-return-21_main.c b/gcc/testsuite/gcc.dg/compat/struct-return-21_main.c new file mode 100644 index 00000000000..34e0ab42996 --- /dev/null +++ b/gcc/testsuite/gcc.dg/compat/struct-return-21_main.c @@ -0,0 +1,13 @@ +/* Test function return values. This was written when correcting + a deviation from the ABI on SPARC64 between 3.3 and 3.4. */ + +extern void struct_return_21_x (void); +extern void exit (int); +int fails; + +int +main () +{ + struct_return_21_x (); + exit (0); +} diff --git a/gcc/testsuite/gcc.dg/compat/struct-return-21_x.c b/gcc/testsuite/gcc.dg/compat/struct-return-21_x.c new file mode 100644 index 00000000000..721deff036e --- /dev/null +++ b/gcc/testsuite/gcc.dg/compat/struct-return-21_x.c @@ -0,0 +1,112 @@ +#include "compat-common.h" + +#ifdef SKIP_VA +const int test_va = 0; +#else +const int test_va = 1; +#endif + +#define T(TYPE) \ +TYPE g01##TYPE, g02##TYPE, g03##TYPE, g04##TYPE; \ +TYPE g05##TYPE, g06##TYPE, g07##TYPE, g08##TYPE; \ +TYPE g09##TYPE, g10##TYPE, g11##TYPE, g12##TYPE; \ +TYPE g13##TYPE, g14##TYPE, g15##TYPE, g16##TYPE; \ + \ +extern void init##TYPE (TYPE *p, int i); \ +extern void checkg##TYPE (void); \ +extern TYPE test0##TYPE (void); \ +extern TYPE test1##TYPE (TYPE); \ +extern TYPE testva##TYPE (int n, ...); \ + \ +void \ +testit##TYPE (void) \ +{ \ + TYPE rslt; \ + DEBUG_FPUTS (#TYPE); \ + DEBUG_FPUTS (" init: "); \ + init##TYPE (&g01##TYPE, 1); \ + init##TYPE (&g02##TYPE, 2); \ + init##TYPE (&g03##TYPE, 3); \ + init##TYPE (&g04##TYPE, 4); \ + init##TYPE (&g05##TYPE, 5); \ + init##TYPE (&g06##TYPE, 6); \ + init##TYPE (&g07##TYPE, 7); \ + init##TYPE (&g08##TYPE, 8); \ + init##TYPE (&g09##TYPE, 9); \ + init##TYPE (&g10##TYPE, 10); \ + init##TYPE (&g11##TYPE, 11); \ + init##TYPE (&g12##TYPE, 12); \ + init##TYPE (&g13##TYPE, 13); \ + init##TYPE (&g14##TYPE, 14); \ + init##TYPE (&g15##TYPE, 15); \ + init##TYPE (&g16##TYPE, 16); \ + checkg##TYPE (); \ + DEBUG_NL; \ + DEBUG_FPUTS (#TYPE); \ + DEBUG_FPUTS (" test0: "); \ + rslt = test0##TYPE (); \ + check##TYPE (rslt, 1); \ + DEBUG_NL; \ + DEBUG_FPUTS (#TYPE); \ + DEBUG_FPUTS (" test1: "); \ + rslt = test1##TYPE (g01##TYPE); \ + check##TYPE (rslt, 1); \ + if (test_va) \ + { \ + DEBUG_NL; \ + DEBUG_FPUTS (#TYPE); \ + DEBUG_FPUTS (" testva: "); \ + rslt = testva##TYPE (1, g01##TYPE); \ + check##TYPE (rslt, 1); \ + rslt = testva##TYPE (5, g01##TYPE, g02##TYPE, \ + g03##TYPE, g04##TYPE, \ + g05##TYPE); \ + check##TYPE (rslt, 5); \ + rslt = testva##TYPE (9, g01##TYPE, g02##TYPE, \ + g03##TYPE, g04##TYPE, \ + g05##TYPE, g06##TYPE, \ + g07##TYPE, g08##TYPE, \ + g09##TYPE); \ + check##TYPE (rslt, 9); \ + rslt = testva##TYPE (16, g01##TYPE, g02##TYPE, \ + g03##TYPE, g04##TYPE, \ + g05##TYPE, g06##TYPE, \ + g07##TYPE, g08##TYPE, \ + g09##TYPE, g10##TYPE, \ + g11##TYPE, g12##TYPE, \ + g13##TYPE, g14##TYPE, \ + g15##TYPE, g16##TYPE); \ + check##TYPE (rslt, 16); \ + } \ + DEBUG_NL; \ +} + +#include "mixed-struct-defs.h" +#include "mixed-struct-check.h" + +T(Sfi) +T(Sfii) +T(Sfifi) +T(Sfiifii) + +#undef T + +void +struct_return_21_x () +{ +DEBUG_INIT + +#define T(TYPE) testit##TYPE (); + +T(Sfi) +T(Sfii) +T(Sfifi) +T(Sfiifii) + +DEBUG_FINI + +if (fails != 0) + abort (); + +#undef T +} diff --git a/gcc/testsuite/gcc.dg/compat/struct-return-21_y.c b/gcc/testsuite/gcc.dg/compat/struct-return-21_y.c new file mode 100644 index 00000000000..b44d7f58e69 --- /dev/null +++ b/gcc/testsuite/gcc.dg/compat/struct-return-21_y.c @@ -0,0 +1,65 @@ +#include <stdarg.h> + +#include "compat-common.h" + +#include "mixed-struct-defs.h" +#include "mixed-struct-init.h" + +#define T(TYPE) \ +extern TYPE g01##TYPE, g02##TYPE, g03##TYPE, g04##TYPE; \ +extern TYPE g05##TYPE, g06##TYPE, g07##TYPE, g08##TYPE; \ +extern TYPE g09##TYPE, g10##TYPE, g11##TYPE, g12##TYPE; \ +extern TYPE g13##TYPE, g14##TYPE, g15##TYPE, g16##TYPE; \ + \ +extern void check##TYPE (TYPE x, int i); \ + \ +void \ +checkg##TYPE (void) \ +{ \ + check##TYPE (g01##TYPE, 1); \ + check##TYPE (g02##TYPE, 2); \ + check##TYPE (g03##TYPE, 3); \ + check##TYPE (g04##TYPE, 4); \ + check##TYPE (g05##TYPE, 5); \ + check##TYPE (g06##TYPE, 6); \ + check##TYPE (g07##TYPE, 7); \ + check##TYPE (g08##TYPE, 8); \ + check##TYPE (g09##TYPE, 9); \ + check##TYPE (g10##TYPE, 10); \ + check##TYPE (g11##TYPE, 11); \ + check##TYPE (g12##TYPE, 12); \ + check##TYPE (g13##TYPE, 13); \ + check##TYPE (g14##TYPE, 14); \ + check##TYPE (g15##TYPE, 15); \ + check##TYPE (g16##TYPE, 16); \ +} \ + \ +TYPE \ +test0##TYPE (void) \ +{ \ + return g01##TYPE; \ +} \ + \ +TYPE \ +test1##TYPE (TYPE x01) \ +{ \ + return x01; \ +} \ + \ +TYPE \ +testva##TYPE (int n, ...) \ +{ \ + int i; \ + TYPE rslt; \ + va_list ap; \ + va_start (ap, n); \ + for (i = 0; i < n; i++) \ + rslt = va_arg (ap, TYPE); \ + va_end (ap); \ + return rslt; \ +} + +T(Sfi) +T(Sfii) +T(Sfifi) +T(Sfiifii) diff --git a/gcc/testsuite/gcc.dg/compat/union-by-value-1_main.c b/gcc/testsuite/gcc.dg/compat/union-by-value-1_main.c new file mode 100644 index 00000000000..cd9065920f6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/compat/union-by-value-1_main.c @@ -0,0 +1,13 @@ +/* Test function argument passing. This was written when correcting + a deviation from the ABI on SPARC64 between 3.3 and 3.4. */ + +extern void union_by_value_1_x (void); +extern void exit (int); +int fails; + +int +main () +{ + union_by_value_1_x (); + exit (0); +} diff --git a/gcc/testsuite/gcc.dg/compat/union-by-value-1_x.c b/gcc/testsuite/gcc.dg/compat/union-by-value-1_x.c new file mode 100644 index 00000000000..a3efd4ed7d8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/compat/union-by-value-1_x.c @@ -0,0 +1,180 @@ +#include "compat-common.h" + +#define T(TYPE) \ +TYPE g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE; \ +TYPE g5s##TYPE, g6s##TYPE, g7s##TYPE, g8s##TYPE; \ +TYPE g9s##TYPE, g10s##TYPE, g11s##TYPE, g12s##TYPE; \ +TYPE g13s##TYPE, g14s##TYPE, g15s##TYPE, g16s##TYPE; \ + \ +extern void init##TYPE (TYPE *p, int i); \ +extern void checkg##TYPE (void); \ +extern void \ +test##TYPE (TYPE s1, TYPE s2, TYPE s3, TYPE s4, \ + TYPE s5, TYPE s6, TYPE s7, TYPE s8, \ + TYPE s9, TYPE s10, TYPE s11, TYPE s12, \ + TYPE s13, TYPE s14, TYPE s15, TYPE s16); \ +extern void testva##TYPE (int n, ...); \ + \ +void \ +test2_##TYPE (TYPE s1, TYPE s2, TYPE s3, TYPE s4, \ + TYPE s5, TYPE s6, TYPE s7, TYPE s8) \ +{ \ + test##TYPE (s1, g2s##TYPE, s2, g4s##TYPE, \ + s3, g6s##TYPE, s4, g8s##TYPE, \ + s5, g10s##TYPE, s6, g12s##TYPE, \ + s7, g14s##TYPE, s8, g16s##TYPE); \ +} \ + \ +void \ +testit##TYPE (void) \ +{ \ + DEBUG_FPUTS (#TYPE); \ + DEBUG_FPUTS (" init: "); \ + init##TYPE ( &g1s##TYPE, 1); \ + init##TYPE ( &g2s##TYPE, 2); \ + init##TYPE ( &g3s##TYPE, 3); \ + init##TYPE ( &g4s##TYPE, 4); \ + init##TYPE ( &g5s##TYPE, 5); \ + init##TYPE ( &g6s##TYPE, 6); \ + init##TYPE ( &g7s##TYPE, 7); \ + init##TYPE ( &g8s##TYPE, 8); \ + init##TYPE ( &g9s##TYPE, 9); \ + init##TYPE (&g10s##TYPE, 10); \ + init##TYPE (&g11s##TYPE, 11); \ + init##TYPE (&g12s##TYPE, 12); \ + init##TYPE (&g13s##TYPE, 13); \ + init##TYPE (&g14s##TYPE, 14); \ + init##TYPE (&g15s##TYPE, 15); \ + init##TYPE (&g16s##TYPE, 16); \ + checkg##TYPE (); \ + DEBUG_NL; \ + DEBUG_FPUTS (#TYPE); \ + DEBUG_FPUTS (" test: "); \ + test##TYPE (g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE, g6s##TYPE, g7s##TYPE, g8s##TYPE, \ + g9s##TYPE, g10s##TYPE, g11s##TYPE, g12s##TYPE, \ + g13s##TYPE, g14s##TYPE, g15s##TYPE, g16s##TYPE); \ + DEBUG_NL; \ + DEBUG_FPUTS (#TYPE); \ + DEBUG_FPUTS (" testva:"); \ + DEBUG_NL; \ + testva##TYPE (1, \ + g1s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (2, \ + g1s##TYPE, g2s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (3, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (4, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (5, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (6, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE, g6s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (7, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE, g6s##TYPE, g7s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (8, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE, g6s##TYPE, g7s##TYPE, g8s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (9, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE, g6s##TYPE, g7s##TYPE, g8s##TYPE, \ + g9s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (10, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE, g6s##TYPE, g7s##TYPE, g8s##TYPE, \ + g9s##TYPE, g10s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (11, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE, g6s##TYPE, g7s##TYPE, g8s##TYPE, \ + g9s##TYPE, g10s##TYPE, g11s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (12, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE, g6s##TYPE, g7s##TYPE, g8s##TYPE, \ + g9s##TYPE, g10s##TYPE, g11s##TYPE, g12s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (13, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE, g6s##TYPE, g7s##TYPE, g8s##TYPE, \ + g9s##TYPE, g10s##TYPE, g11s##TYPE, g12s##TYPE, \ + g13s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (14, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE, g6s##TYPE, g7s##TYPE, g8s##TYPE, \ + g9s##TYPE, g10s##TYPE, g11s##TYPE, g12s##TYPE, \ + g13s##TYPE, g14s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (15, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE, g6s##TYPE, g7s##TYPE, g8s##TYPE, \ + g9s##TYPE, g10s##TYPE, g11s##TYPE, g12s##TYPE, \ + g13s##TYPE, g14s##TYPE, g15s##TYPE); \ + DEBUG_NL; \ + testva##TYPE (16, \ + g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE, \ + g5s##TYPE, g6s##TYPE, g7s##TYPE, g8s##TYPE, \ + g9s##TYPE, g10s##TYPE, g11s##TYPE, g12s##TYPE, \ + g13s##TYPE, g14s##TYPE, g15s##TYPE, g16s##TYPE); \ + DEBUG_NL; \ + DEBUG_FPUTS (#TYPE); \ + DEBUG_FPUTS (" test2:"); \ + test2_##TYPE (g1s##TYPE, g3s##TYPE, g5s##TYPE, g7s##TYPE, \ + g9s##TYPE, g11s##TYPE, g13s##TYPE, g15s##TYPE); \ + DEBUG_NL; \ +} + +#include "union-defs.h" +#include "union-check.h" + +T(Ucs) +T(Uci) +T(Ucl) +T(Ucll) +T(Usi) +T(Usl) +T(Usll) +T(Uil) +T(Uill) +T(Ulll) + +#undef T + +void +union_by_value_1_x () +{ +DEBUG_INIT + +#define T(TYPE) testit##TYPE (); + +T(Ucs) +T(Uci) +T(Ucl) +T(Ucll) +T(Usi) +T(Usl) +T(Usll) +T(Uil) +T(Uill) +T(Ulll) + +DEBUG_FINI + +if (fails != 0) + abort (); + +#undef T +} diff --git a/gcc/testsuite/gcc.dg/compat/union-by-value-1_y.c b/gcc/testsuite/gcc.dg/compat/union-by-value-1_y.c new file mode 100644 index 00000000000..b17613e9952 --- /dev/null +++ b/gcc/testsuite/gcc.dg/compat/union-by-value-1_y.c @@ -0,0 +1,92 @@ +#include <stdarg.h> + +#include "compat-common.h" + +#ifdef SKIP_VA +const int test_va = 0; +#else +const int test_va = 1; +#endif + +#include "union-defs.h" +#include "union-init.h" + +#define T(TYPE) \ +extern void check##TYPE (TYPE x, int i); \ +extern TYPE g1s##TYPE, g2s##TYPE, g3s##TYPE, g4s##TYPE; \ +extern TYPE g5s##TYPE, g6s##TYPE, g7s##TYPE, g8s##TYPE; \ +extern TYPE g9s##TYPE, g10s##TYPE, g11s##TYPE, g12s##TYPE; \ +extern TYPE g13s##TYPE, g14s##TYPE, g15s##TYPE, g16s##TYPE; \ + \ +void \ +checkg##TYPE (void) \ +{ \ + check##TYPE ( g1s##TYPE, 1); \ + check##TYPE ( g2s##TYPE, 2); \ + check##TYPE ( g3s##TYPE, 3); \ + check##TYPE ( g4s##TYPE, 4); \ + check##TYPE ( g5s##TYPE, 5); \ + check##TYPE ( g6s##TYPE, 6); \ + check##TYPE ( g7s##TYPE, 7); \ + check##TYPE ( g8s##TYPE, 8); \ + check##TYPE ( g9s##TYPE, 9); \ + check##TYPE ( g10s##TYPE, 10); \ + check##TYPE ( g11s##TYPE, 11); \ + check##TYPE ( g12s##TYPE, 12); \ + check##TYPE ( g13s##TYPE, 13); \ + check##TYPE ( g14s##TYPE, 14); \ + check##TYPE ( g15s##TYPE, 15); \ + check##TYPE ( g16s##TYPE, 16); \ +} \ + \ +void \ +test##TYPE (TYPE s1, TYPE s2, TYPE s3, TYPE s4, \ + TYPE s5, TYPE s6, TYPE s7, TYPE s8, \ + TYPE s9, TYPE s10, TYPE s11, TYPE s12, \ + TYPE s13, TYPE s14, TYPE s15, TYPE s16) \ +{ \ + check##TYPE (s1, 1); \ + check##TYPE (s2, 2); \ + check##TYPE (s3, 3); \ + check##TYPE (s4, 4); \ + check##TYPE (s5, 5); \ + check##TYPE (s6, 6); \ + check##TYPE (s7, 7); \ + check##TYPE (s8, 8); \ + check##TYPE (s9, 9); \ + check##TYPE (s10, 10); \ + check##TYPE (s11, 11); \ + check##TYPE (s12, 12); \ + check##TYPE (s13, 13); \ + check##TYPE (s14, 14); \ + check##TYPE (s15, 15); \ + check##TYPE (s16, 16); \ +} \ + \ +void \ +testva##TYPE (int n, ...) \ +{ \ + int i; \ + va_list ap; \ + if (test_va) \ + { \ + va_start (ap, n); \ + for (i = 0; i < n; i++) \ + { \ + TYPE t = va_arg (ap, TYPE); \ + check##TYPE (t, i+1); \ + } \ + va_end (ap); \ + } \ +} + +T(Ucs) +T(Uci) +T(Ucl) +T(Ucll) +T(Usi) +T(Usl) +T(Usll) +T(Uil) +T(Uill) +T(Ulll) diff --git a/gcc/testsuite/gcc.dg/compat/union-check.h b/gcc/testsuite/gcc.dg/compat/union-check.h new file mode 100644 index 00000000000..b5157814d58 --- /dev/null +++ b/gcc/testsuite/gcc.dg/compat/union-check.h @@ -0,0 +1,34 @@ +/* Function definitions that are used by multiple tests. */ + +#define CHECK_CHAR(TYPE) \ + void check##TYPE (TYPE p, int i) \ + { if (p.c != (char)i) DEBUG_CHECK } + +CHECK_CHAR(Ucs) +CHECK_CHAR(Uci) +CHECK_CHAR(Ucl) +CHECK_CHAR(Ucll) + + +#define CHECK_SHORT(TYPE) \ + void check##TYPE (TYPE p, int i) \ + { if (p.s != (short)i) DEBUG_CHECK } + +CHECK_SHORT(Usi) +CHECK_SHORT(Usl) +CHECK_SHORT(Usll) + + +#define CHECK_INT(TYPE) \ + void check##TYPE (TYPE p, int i) \ + { if (p.i != i) DEBUG_CHECK } + +CHECK_INT(Uil) +CHECK_INT(Uill) + + +#define CHECK_LONG(TYPE) \ + void check##TYPE (TYPE p, int i) \ + { if (p.l != (long)i) DEBUG_CHECK } + +CHECK_LONG(Ulll) diff --git a/gcc/testsuite/gcc.dg/compat/union-defs.h b/gcc/testsuite/gcc.dg/compat/union-defs.h new file mode 100644 index 00000000000..887cd6da8e8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/compat/union-defs.h @@ -0,0 +1,15 @@ +/* Type definitions that are used by multiple tests. */ + +typedef union { char c; short s; } Ucs; +typedef union { char c; int i; } Uci; +typedef union { char c; long l; } Ucl; +typedef union { char c; long long ll; } Ucll; + +typedef union { short s; int i; } Usi; +typedef union { short s; long l; } Usl; +typedef union { short s; long long ll; } Usll; + +typedef union { int i; long l; } Uil; +typedef union { int i; long long ll; } Uill; + +typedef union { long l; long long ll; } Ulll; diff --git a/gcc/testsuite/gcc.dg/compat/union-init.h b/gcc/testsuite/gcc.dg/compat/union-init.h new file mode 100644 index 00000000000..5add7b4a800 --- /dev/null +++ b/gcc/testsuite/gcc.dg/compat/union-init.h @@ -0,0 +1,34 @@ +/* Function definitions that are used by multiple tests. */ + +#define INIT_CHAR(TYPE) \ + void init##TYPE (TYPE *p, int i) \ + { p->c = (char)i; } + +INIT_CHAR(Ucs) +INIT_CHAR(Uci) +INIT_CHAR(Ucl) +INIT_CHAR(Ucll) + + +#define INIT_SHORT(TYPE) \ + void init##TYPE (TYPE *p, int i) \ + { p->s = (short)i; } + +INIT_SHORT(Usi) +INIT_SHORT(Usl) +INIT_SHORT(Usll) + + +#define INIT_INT(TYPE) \ + void init##TYPE (TYPE *p, int i) \ + { p->i = i; } + +INIT_INT(Uil) +INIT_INT(Uill) + + +#define INIT_LONG(TYPE) \ + void init##TYPE (TYPE *p, int i) \ + { p->l = (long)i; } + +INIT_LONG(Ulll) diff --git a/gcc/testsuite/gcc.dg/compat/union-return-1_main.c b/gcc/testsuite/gcc.dg/compat/union-return-1_main.c new file mode 100644 index 00000000000..edf15166b95 --- /dev/null +++ b/gcc/testsuite/gcc.dg/compat/union-return-1_main.c @@ -0,0 +1,13 @@ +/* Test function return values. This was written when correcting + a deviation from the ABI on SPARC64 between 3.3 and 3.4. */ + +extern void union_return_1_x (void); +extern void exit (int); +int fails; + +int +main () +{ + union_return_1_x (); + exit (0); +} diff --git a/gcc/testsuite/gcc.dg/compat/union-return-1_x.c b/gcc/testsuite/gcc.dg/compat/union-return-1_x.c new file mode 100644 index 00000000000..761f000aa11 --- /dev/null +++ b/gcc/testsuite/gcc.dg/compat/union-return-1_x.c @@ -0,0 +1,124 @@ +#include "compat-common.h" + +#ifdef SKIP_VA +const int test_va = 0; +#else +const int test_va = 1; +#endif + +#define T(TYPE) \ +TYPE g01##TYPE, g02##TYPE, g03##TYPE, g04##TYPE; \ +TYPE g05##TYPE, g06##TYPE, g07##TYPE, g08##TYPE; \ +TYPE g09##TYPE, g10##TYPE, g11##TYPE, g12##TYPE; \ +TYPE g13##TYPE, g14##TYPE, g15##TYPE, g16##TYPE; \ + \ +extern void init##TYPE (TYPE *p, int i); \ +extern void checkg##TYPE (void); \ +extern TYPE test0##TYPE (void); \ +extern TYPE test1##TYPE (TYPE); \ +extern TYPE testva##TYPE (int n, ...); \ + \ +void \ +testit##TYPE (void) \ +{ \ + TYPE rslt; \ + DEBUG_FPUTS (#TYPE); \ + DEBUG_FPUTS (" init: "); \ + init##TYPE (&g01##TYPE, 1); \ + init##TYPE (&g02##TYPE, 2); \ + init##TYPE (&g03##TYPE, 3); \ + init##TYPE (&g04##TYPE, 4); \ + init##TYPE (&g05##TYPE, 5); \ + init##TYPE (&g06##TYPE, 6); \ + init##TYPE (&g07##TYPE, 7); \ + init##TYPE (&g08##TYPE, 8); \ + init##TYPE (&g09##TYPE, 9); \ + init##TYPE (&g10##TYPE, 10); \ + init##TYPE (&g11##TYPE, 11); \ + init##TYPE (&g12##TYPE, 12); \ + init##TYPE (&g13##TYPE, 13); \ + init##TYPE (&g14##TYPE, 14); \ + init##TYPE (&g15##TYPE, 15); \ + init##TYPE (&g16##TYPE, 16); \ + checkg##TYPE (); \ + DEBUG_NL; \ + DEBUG_FPUTS (#TYPE); \ + DEBUG_FPUTS (" test0: "); \ + rslt = test0##TYPE (); \ + check##TYPE (rslt, 1); \ + DEBUG_NL; \ + DEBUG_FPUTS (#TYPE); \ + DEBUG_FPUTS (" test1: "); \ + rslt = test1##TYPE (g01##TYPE); \ + check##TYPE (rslt, 1); \ + if (test_va) \ + { \ + DEBUG_NL; \ + DEBUG_FPUTS (#TYPE); \ + DEBUG_FPUTS (" testva: "); \ + rslt = testva##TYPE (1, g01##TYPE); \ + check##TYPE (rslt, 1); \ + rslt = testva##TYPE (5, g01##TYPE, g02##TYPE, \ + g03##TYPE, g04##TYPE, \ + g05##TYPE); \ + check##TYPE (rslt, 5); \ + rslt = testva##TYPE (9, g01##TYPE, g02##TYPE, \ + g03##TYPE, g04##TYPE, \ + g05##TYPE, g06##TYPE, \ + g07##TYPE, g08##TYPE, \ + g09##TYPE); \ + check##TYPE (rslt, 9); \ + rslt = testva##TYPE (16, g01##TYPE, g02##TYPE, \ + g03##TYPE, g04##TYPE, \ + g05##TYPE, g06##TYPE, \ + g07##TYPE, g08##TYPE, \ + g09##TYPE, g10##TYPE, \ + g11##TYPE, g12##TYPE, \ + g13##TYPE, g14##TYPE, \ + g15##TYPE, g16##TYPE); \ + check##TYPE (rslt, 16); \ + } \ + DEBUG_NL; \ +} + +#include "union-defs.h" +#include "union-check.h" + +T(Ucs) +T(Uci) +T(Ucl) +T(Ucll) +T(Usi) +T(Usl) +T(Usll) +T(Uil) +T(Uill) +T(Ulll) + +#undef T + +void +union_return_1_x () +{ +DEBUG_INIT + +#define T(TYPE) testit##TYPE (); + +T(Ucs) +T(Uci) +T(Ucl) +T(Ucll) +T(Usi) +T(Usl) +T(Usll) +T(Uil) +T(Uill) +T(Ulll) + +DEBUG_FINI + +if (fails != 0) + abort (); + +#undef T +} diff --git a/gcc/testsuite/gcc.dg/compat/union-return-1_y.c b/gcc/testsuite/gcc.dg/compat/union-return-1_y.c new file mode 100644 index 00000000000..9eaa9777e0a --- /dev/null +++ b/gcc/testsuite/gcc.dg/compat/union-return-1_y.c @@ -0,0 +1,71 @@ +#include <stdarg.h> + +#include "compat-common.h" + +#include "union-defs.h" +#include "union-init.h" + +#define T(TYPE) \ +extern TYPE g01##TYPE, g02##TYPE, g03##TYPE, g04##TYPE; \ +extern TYPE g05##TYPE, g06##TYPE, g07##TYPE, g08##TYPE; \ +extern TYPE g09##TYPE, g10##TYPE, g11##TYPE, g12##TYPE; \ +extern TYPE g13##TYPE, g14##TYPE, g15##TYPE, g16##TYPE; \ + \ +extern void check##TYPE (TYPE x, int i); \ + \ +void \ +checkg##TYPE (void) \ +{ \ + check##TYPE (g01##TYPE, 1); \ + check##TYPE (g02##TYPE, 2); \ + check##TYPE (g03##TYPE, 3); \ + check##TYPE (g04##TYPE, 4); \ + check##TYPE (g05##TYPE, 5); \ + check##TYPE (g06##TYPE, 6); \ + check##TYPE (g07##TYPE, 7); \ + check##TYPE (g08##TYPE, 8); \ + check##TYPE (g09##TYPE, 9); \ + check##TYPE (g10##TYPE, 10); \ + check##TYPE (g11##TYPE, 11); \ + check##TYPE (g12##TYPE, 12); \ + check##TYPE (g13##TYPE, 13); \ + check##TYPE (g14##TYPE, 14); \ + check##TYPE (g15##TYPE, 15); \ + check##TYPE (g16##TYPE, 16); \ +} \ + \ +TYPE \ +test0##TYPE (void) \ +{ \ + return g01##TYPE; \ +} \ + \ +TYPE \ +test1##TYPE (TYPE x01) \ +{ \ + return x01; \ +} \ + \ +TYPE \ +testva##TYPE (int n, ...) \ +{ \ + int i; \ + TYPE rslt; \ + va_list ap; \ + va_start (ap, n); \ + for (i = 0; i < n; i++) \ + rslt = va_arg (ap, TYPE); \ + va_end (ap); \ + return rslt; \ +} + +T(Ucs) +T(Uci) +T(Ucl) +T(Ucll) +T(Usi) +T(Usl) +T(Usll) +T(Uil) +T(Uill) +T(Ulll) diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/c99-typedef1.c b/gcc/testsuite/gcc.dg/debug/dwarf2/c99-typedef1.c new file mode 100644 index 00000000000..b7bd66a6023 --- /dev/null +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/c99-typedef1.c @@ -0,0 +1,9 @@ +// { dg-options "-std=iso9899:1999 -gdwarf-2" } + +void f() { + int n = 3; + typedef int T[n++]; + + T t; + t[0] = 7; +} diff --git a/gcc/testsuite/gcc.dg/gnu89-dupqual-1.c b/gcc/testsuite/gcc.dg/gnu89-dupqual-1.c new file mode 100644 index 00000000000..9bd1db01569 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu89-dupqual-1.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-std=gnu89 -Werror" } */ + +typedef const int CI; +const const int c1; /* { dg-bogus "duplicate" } */ +const CI c2; /* { dg-bogus "duplicate" } */ +const CI *c3; /* { dg-bogus "duplicate" } */ + +typedef volatile int VI; +volatile volatile int v1; /* { dg-bogus "duplicate" } */ +volatile VI v2; /* { dg-bogus "duplicate" } */ +volatile VI *v3; /* { dg-bogus "duplicate" } */ diff --git a/gcc/testsuite/gcc.dg/local1.c b/gcc/testsuite/gcc.dg/local1.c new file mode 100644 index 00000000000..700070ae1d6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/local1.c @@ -0,0 +1,7 @@ +static int i; + +extern int i; + +static void f() { + extern int i; +} diff --git a/gcc/testsuite/gcc.dg/pr14289-1.c b/gcc/testsuite/gcc.dg/pr14289-1.c new file mode 100644 index 00000000000..652916325c2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr14289-1.c @@ -0,0 +1,12 @@ +/* PR middle-end/14289 */ +/* { dg-do compile { target i?86-*-* } } */ +/* { dg-options "-O0" } */ + +register int a[2] asm("ebx"); + +void Nase(void) +{ + int i=6; + a[i]=5; /* { dg-error "address of global" } */ +} + diff --git a/gcc/testsuite/gcc.dg/pr14289-2.c b/gcc/testsuite/gcc.dg/pr14289-2.c new file mode 100644 index 00000000000..7530b468cac --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr14289-2.c @@ -0,0 +1,12 @@ +/* PR middle-end/14289 */ +/* { dg-do compile { target i?86-*-* } } */ +/* { dg-options "-O0" } */ + +static register int a[2] asm("ebx"); /* { dg-error "multiple storage" } */ + +void Nase(void) +{ + int i=6; + a[i]=5; /* { dg-error "address of global" } */ +} + diff --git a/gcc/testsuite/gcc.dg/pr14289-3.c b/gcc/testsuite/gcc.dg/pr14289-3.c new file mode 100644 index 00000000000..7cfbf78ce05 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr14289-3.c @@ -0,0 +1,12 @@ +/* PR middle-end/14289 */ +/* { dg-do compile { target i?86-*-* } } */ +/* { dg-options "-O0" } */ + +extern register int a[2] asm("ebx"); /* { dg-error "multiple storage" } */ + +void Nase(void) +{ + int i=6; + a[i]=5; /* { dg-error "address of global" } */ +} + diff --git a/gcc/testsuite/gcc.dg/torture/builtin-integral-1.c b/gcc/testsuite/gcc.dg/torture/builtin-integral-1.c new file mode 100644 index 00000000000..1f2990dd2f0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/builtin-integral-1.c @@ -0,0 +1,58 @@ +/* Copyright (C) 2004 Free Software Foundation. + + Verify that integral FP expressions are optimized. + + Written by Kaveh Ghazi, 2004-03-16. */ + +/* { dg-do link } */ +/* { dg-options "-ffast-math" } */ + +#define PROTOTYPE1(FN) extern double FN(double); extern float FN##f(float); \ + extern long double FN##l(long double); + +PROTOTYPE1(fabs) + +void test(int i1, int i2) +{ + /* Test that the various FP truncation builtins detect integral + arguments. */ +#define CHECK_FN(MATHFN) \ + PROTOTYPE1 (MATHFN) \ + extern void link_failure_##MATHFN(void); \ + extern void link_failure_##MATHFN##f(void); \ + extern void link_failure_##MATHFN##l(void); \ + if (MATHFN(i1) != i1) link_failure_##MATHFN(); \ + if (MATHFN##f(i1) != i1) link_failure_##MATHFN##f(); \ + if (MATHFN##l(i1) != i1) link_failure_##MATHFN##l(); \ + + CHECK_FN(ceil); + CHECK_FN(floor); + CHECK_FN(nearbyint); + CHECK_FN(rint); + CHECK_FN(round); + CHECK_FN(trunc); + + /* Check that various other integral expressions are detected. */ +#define CHECK_EXPR(EXPR,NAME) \ + extern void link_failure_##NAME(void); \ + if (ceill(EXPR) != (EXPR)) link_failure_##NAME(); \ + + CHECK_EXPR (5.0, REAL_CST); + CHECK_EXPR (5.0F, REAL_CSTf); + CHECK_EXPR (5.0L, REAL_CSTl); + CHECK_EXPR ((double)i1, FLOAT_EXPR); + CHECK_EXPR ((float)i1, FLOAT_EXPRf); + CHECK_EXPR ((long double)i1, FLOAT_EXPRl); + CHECK_EXPR (fabs(i1), ABS_EXPR); + CHECK_EXPR (fabsf(i1), ABS_EXPRf); + CHECK_EXPR (fabsl(i1), ABS_EXPRl); + CHECK_EXPR (((void)i1,(double)i2), COMPOUND_EXPR); + CHECK_EXPR ((double)i1+i2, PLUS_EXPR); + CHECK_EXPR ((double)i1-i2, MINUS_EXPR); + CHECK_EXPR ((double)i1*i2, MULT_EXPR); +} + +int main (void) +{ + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/builtin-nonneg-1.c b/gcc/testsuite/gcc.dg/torture/builtin-nonneg-1.c new file mode 100644 index 00000000000..80cf3e3c83b --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/builtin-nonneg-1.c @@ -0,0 +1,172 @@ +/* Copyright (C) 2004 Free Software Foundation. + + Verify that GCC can determine which built-in functions produce a + nonnegative result. + + Written by Kaveh Ghazi, 2004-03-10. */ + +/* { dg-do link } */ +/* { dg-options "-ffast-math" } */ + +#define PROTOTYPE_RTYPE(FN,RTYPE) extern RTYPE FN(double); \ + extern RTYPE FN##f(float); \ + extern RTYPE FN##l(long double); +#define PROTOTYPE(FN) extern double FN(double); extern float FN##f(float); \ + extern long double FN##l(long double); +#define PROTOTYPE2(FN) extern double FN(double, double); \ + extern float FN##f(float, float); \ + extern long double FN##l(long double, long double); +#define CPROTOTYPE1(FN) extern double FN(_Complex double); \ + extern float FN##f(_Complex float); \ + extern long double FN##l(_Complex long double); +#define CPROTOTYPE1(FN) extern double FN(_Complex double); \ + extern float FN##f(_Complex float); \ + extern long double FN##l(_Complex long double); +#define IPROTOTYPE(FN) extern int FN(int); extern int FN##l(long); \ + extern int FN##ll(long long); +#define PROTOTYPE2TYPE2(FN,A2TYPE) extern double FN(double, A2TYPE); \ + extern float FN##f(float, A2TYPE); \ + extern long double FN##l(long double, A2TYPE); +#define PROTOTYPE2_A2FPTR(FN) extern double FN(double, double *); \ + extern float FN##f(float, float *); \ + extern long double FN##l(long double, long double *); + +extern int signbit (double); +extern int signbitf (float); +extern int signbitl (long double); + +void test(double d1, double d2, float f1, float f2, + long double ld1, long double ld2) +{ + /* These are always nonnegative. */ + +#define TEST1(FN) \ + extern void link_failure_##FN (void); PROTOTYPE(FN) \ + if (signbit(FN(d1)) || signbitf(FN##f(f1)) || signbitl(FN##l(ld1))) \ + link_failure_##FN() + +#define TEST2(FN) \ + extern void link_failure_##FN (void); PROTOTYPE2(FN) \ + if (signbit(FN(d1,d2)) || signbitf(FN##f(f1,f2)) || signbitl(FN##l(ld1,ld2))) \ + link_failure_##FN() + +#define CTEST1(FN) \ + extern void link_failure_##FN (void); CPROTOTYPE1(FN) \ + if (signbit(FN(d1)) || signbitf(FN##f(f1)) || signbitl(FN##l(ld1))) \ + link_failure_##FN() + +#define ITEST1(FN) \ + extern void link_failure_##FN (void); IPROTOTYPE(FN) \ + if (signbit(FN(d1)) || signbitf(FN##l(f1)) || signbitl(FN##ll(ld1))) \ + link_failure_##FN() + + TEST1 (acos); + TEST1 (acosh); + CTEST1 (cabs); + TEST1 (cosh); + TEST1 (erfc); + TEST1 (exp); + TEST1 (exp10); + TEST1 (exp2); + TEST1 (fabs); + TEST2 (fdim); + TEST2 (hypot); + TEST1 (pow10); + TEST1 (sqrt); + ITEST1 (ffs); + ITEST1 (__builtin_parity); + ITEST1 (__builtin_popcount); + + /* These are nonnegative if the first argument is. */ +#define ARG1TEST1(FN) \ + extern void link_failure_##FN (void); PROTOTYPE(FN) \ + if (signbit(FN(fabs(d1))) || signbitf(FN##f(fabsf(f1))) \ + || signbitl(FN##l(fabsl(ld1)))) \ + link_failure_##FN() + + /* Same, but allow specifying the return type. */ +#define ARG1TEST1_RTYPE(FN,RTYPE) \ + extern void link_failure_##FN (void); PROTOTYPE_RTYPE(FN,RTYPE) \ + if (signbit(FN(fabs(d1))) || signbitf(FN##f(fabsf(f1))) \ + || signbitl(FN##l(fabsl(ld1)))) \ + link_failure_##FN() + + /* These are nonnegative if the first argument is. */ +#define ARG1TEST2(FN) \ + extern void link_failure_##FN (void); PROTOTYPE2(FN) \ + if (signbit(FN(fabs(d1),d2)) || signbitf(FN##f(fabsf(f1),f2)) \ + || signbitl(FN##l(fabsl(ld1),ld2))) \ + link_failure_##FN() + + /* These are nonnegative if the second argument is. */ +#define ARG2TEST2(FN) \ + extern void link_failure_##FN (void); PROTOTYPE2(FN) \ + if (signbit(FN(d1,fabs(d2))) || signbitf(FN##f(f1,fabsf(f2))) \ + || signbitl(FN##l(ld1,fabsl(ld2)))) \ + link_failure_##FN() + + /* These are nonnegative if the first OR second argument is. */ +#define ARG2TESTor(FN) \ + extern void link_failure_##FN (void); PROTOTYPE2(FN) \ + if (signbit(FN(fabs(d1),d2)) || signbitf(FN##f(fabsf(f1),f2)) \ + || signbitl(FN##l(fabsl(ld1),ld2)) || signbit(FN(d1,fabs(d2))) \ + || signbitf(FN##f(f1,fabsf(f2))) || signbitl(FN##l(ld1,fabsl(ld2)))) \ + link_failure_##FN() + + /* These are nonnegative if the first AND second argument is. */ +#define ARG2TESTand(FN) \ + extern void link_failure_##FN (void); PROTOTYPE2(FN) \ + if (signbit(FN(fabs(d1),fabs(d2))) || signbitf(FN##f(fabsf(f1),fabsf(f2))) \ + || signbitl(FN##l(fabsl(ld1),fabsl(ld2)))) \ + link_failure_##FN() + + /* These are nonnegative if the first argument is, 2nd arg is int. */ +#define ARG2TEST1_A2INT(FN) \ + extern void link_failure_##FN (void); PROTOTYPE2TYPE2(FN, int) \ + if (signbit(FN(fabs(d1),d2)) || signbitf(FN##f(fabsf(f1),f2)) \ + || signbitl(FN##l(fabsl(ld1),ld2))) \ + link_failure_##FN() + + /* These are nonnegative if the first argument is, specify 2nd arg. */ +#define ARG2TEST1_A2FPTR(FN) \ + extern void link_failure_##FN (void); PROTOTYPE2_A2FPTR(FN) \ + if (signbit(FN(fabs(d1),&d2)) || signbitf(FN##f(fabsf(f1),&f2)) \ + || signbitl(FN##l(fabsl(ld1),&ld2))) \ + link_failure_##FN() + + ARG1TEST1 (asinh); + ARG1TEST1 (atan); + ARG1TEST1 (atanh); + ARG1TEST1 (cbrt); + ARG1TEST1 (ceil); + ARG1TEST1 (erf); + ARG1TEST1 (expm1); + ARG1TEST1 (floor); + ARG1TEST2 (fmod); + ARG2TEST1_A2INT (ldexp); + ARG1TEST1_RTYPE (llrint, long long); + ARG1TEST1_RTYPE (llround, long long); + ARG1TEST1_RTYPE (lrint, long); + ARG1TEST1_RTYPE (lround, long); + /* The modf* functions aren't ever "const" or "pure" even with + -ffast-math so they won't be eliminated and yield a link failure. */ + /* ARG2TEST1_A2FPTR (modf);*/ + ARG1TEST1 (nearbyint); + ARG1TEST2 (pow); + ARG1TEST1 (rint); + ARG1TEST1 (round); + ARG1TEST1_RTYPE (signbit, int); + ARG1TEST1 (sinh); + ARG1TEST1 (tanh); + ARG1TEST1 (trunc); + + ARG2TESTor (fmax); + ARG2TESTand (fmin); + ARG2TEST2 (copysign); + +} + +int main (void) +{ + return 0; +} diff --git a/libada/configure.ac b/libada/configure.ac new file mode 100644 index 00000000000..e2d6198e4e7 --- /dev/null +++ b/libada/configure.ac @@ -0,0 +1,65 @@ +# Configure script for libada. +# Copyright 2003, 2004 Free Software Foundation, Inc. +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +AC_INIT +AC_CONFIG_SRCDIR([Makefile.in]) + +# This is an autoconf 2.5x script. +AC_PREREQ([2.59]) + +# Very limited version of AC_MAINTAINER_MODE. +AC_ARG_ENABLE( + [maintainer-mode], + AC_HELP_STRING([--enable-maintainer-mode], + [enable make rules and dependencies not useful (and + sometimes confusing) to the casual installer]), + [case ${enable_maintainer_mode} in + yes) MAINT='' ;; + no) MAINT='#' ;; + *) AC_MSG_ERROR([--enable-maintainer-mode must be yes or no]) ;; + esac + maintainer_mode=${enableval}], + [MAINT='#']) +AC_SUBST([MAINT])dnl + +# Start of actual configure tests + +# Output: create a Makefile. +AC_CONFIG_FILES([Makefile]) + +AC_CANONICAL_SYSTEM + +AC_ARG_ENABLE(shared, +[ --disable-shared don't provide a shared libgnat], +[ + case $enable_shared in + yes | no) ;; + *) + enable_shared=no + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "$pkg" = "ada" || test "$pkg" = "libada"; then + enable_shared=yes + fi + done + IFS="$ac_save_ifs" + ;; + esac +], [enable_shared=yes]) +AC_SUBST(enable_shared) + +AC_OUTPUT diff --git a/libjava/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java b/libjava/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java new file mode 100644 index 00000000000..dbcd2d1c437 --- /dev/null +++ b/libjava/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java @@ -0,0 +1,87 @@ +/* GdkGraphicsEnvironment.java -- information about the graphics environment + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.*; +import java.awt.GraphicsEnvironment; +import java.awt.image.BufferedImage; +import java.util.Locale; + + +public class GdkGraphicsEnvironment extends GraphicsEnvironment +{ + + public GdkGraphicsEnvironment () + { + super(); + } + + public GraphicsDevice[] getScreenDevices () + { + throw new java.lang.UnsupportedOperationException (); + } + + public GraphicsDevice getDefaultScreenDevice () + { + throw new java.lang.UnsupportedOperationException (); + } + + public Graphics2D createGraphics (BufferedImage image) + { + return new GdkGraphics2D (image); + } + + public Font[] getAllFonts () + { + throw new java.lang.UnsupportedOperationException (); + } + + public String[] getAvailableFontFamilyNames () + { + throw new java.lang.UnsupportedOperationException (); + } + + public String[] getAvailableFontFamilyNames (Locale l) + { + throw new java.lang.UnsupportedOperationException (); + } + + +} // class GdkGraphicsEnvironment + diff --git a/libjava/gnu/regexp/CharIndexed.java b/libjava/gnu/regexp/CharIndexed.java new file mode 100644 index 00000000000..eb1be13fd78 --- /dev/null +++ b/libjava/gnu/regexp/CharIndexed.java @@ -0,0 +1,84 @@ +/* gnu/regexp/CharIndexed.java + Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.regexp; + +/** + * Defines the interface used internally so that different types of source + * text can be accessed in the same way. Built-in concrete classes provide + * support for String, StringBuffer, InputStream and char[] types. + * A class that is CharIndexed supports the notion of a cursor within a + * block of text. The cursor must be able to be advanced via the move() + * method. The charAt() method returns the character at the cursor position + * plus a given offset. + * + * @author <A HREF="mailto:wes@cacas.org">Wes Biggs</A> + */ +public interface CharIndexed { + /** + * Defines a constant (0xFFFF was somewhat arbitrarily chosen) + * that can be returned by the charAt() function indicating that + * the specified index is out of range. + */ + char OUT_OF_BOUNDS = '\uFFFF'; + + /** + * Returns the character at the given offset past the current cursor + * position in the input. The index of the current position is zero. + * It is possible for this method to be called with a negative index. + * This happens when using the '^' operator in multiline matching mode + * or the '\b' or '\<' word boundary operators. In any case, the lower + * bound is currently fixed at -2 (for '^' with a two-character newline). + * + * @param index the offset position in the character field to examine + * @return the character at the specified index, or the OUT_OF_BOUNDS + * character defined by this interface. + */ + char charAt(int index); + + /** + * Shifts the input buffer by a given number of positions. Returns + * true if the new cursor position is valid. + */ + boolean move(int index); + + /** + * Returns true if the most recent move() operation placed the cursor + * position at a valid position in the input. + */ + boolean isValid(); +} diff --git a/libjava/gnu/regexp/CharIndexedCharArray.java b/libjava/gnu/regexp/CharIndexedCharArray.java new file mode 100644 index 00000000000..dc488ba44ea --- /dev/null +++ b/libjava/gnu/regexp/CharIndexedCharArray.java @@ -0,0 +1,62 @@ +/* gnu/regexp/CharIndexedCharArray.java + Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.regexp; +import java.io.Serializable; + +class CharIndexedCharArray implements CharIndexed, Serializable { + private char[] s; + private int anchor; + + CharIndexedCharArray(char[] str, int index) { + s = str; + anchor = index; + } + + public char charAt(int index) { + int pos = anchor + index; + return ((pos < s.length) && (pos >= 0)) ? s[pos] : OUT_OF_BOUNDS; + } + + public boolean isValid() { + return (anchor < s.length); + } + + public boolean move(int index) { + return ((anchor += index) < s.length); + } +} diff --git a/libjava/gnu/regexp/CharIndexedInputStream.java b/libjava/gnu/regexp/CharIndexedInputStream.java new file mode 100644 index 00000000000..776f533ca81 --- /dev/null +++ b/libjava/gnu/regexp/CharIndexedInputStream.java @@ -0,0 +1,149 @@ +/* gnu/regexp/CharIndexedInputStream.java + Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.regexp; +import java.io.InputStream; +import java.io.BufferedInputStream; +import java.io.IOException; + +// TODO: move(x) shouldn't rely on calling next() x times + +class CharIndexedInputStream implements CharIndexed { + private static final int BUFFER_INCREMENT = 1024; + private static final int UNKNOWN = Integer.MAX_VALUE; // value for end + + private BufferedInputStream br; + + // so that we don't try to reset() right away + private int index = -1; + + private int bufsize = BUFFER_INCREMENT; + + private int end = UNKNOWN; + + private char cached = OUT_OF_BOUNDS; + + // Big enough for a \r\n pair + // lookBehind[0] = most recent + // lookBehind[1] = second most recent + private char[] lookBehind = new char[] { OUT_OF_BOUNDS, OUT_OF_BOUNDS }; + + CharIndexedInputStream(InputStream str, int index) { + if (str instanceof BufferedInputStream) br = (BufferedInputStream) str; + else br = new BufferedInputStream(str,BUFFER_INCREMENT); + next(); + if (index > 0) move(index); + } + + private boolean next() { + if (end == 1) return false; + end--; // closer to end + + try { + if (index != -1) { + br.reset(); + } + int i = br.read(); + br.mark(bufsize); + if (i == -1) { + end = 1; + cached = OUT_OF_BOUNDS; + return false; + } + cached = (char) i; + index = 1; + } catch (IOException e) { + e.printStackTrace(); + cached = OUT_OF_BOUNDS; + return false; + } + return true; + } + + public char charAt(int index) { + if (index == 0) { + return cached; + } else if (index >= end) { + return OUT_OF_BOUNDS; + } else if (index == -1) { + return lookBehind[0]; + } else if (index == -2) { + return lookBehind[1]; + } else if (index < -2) { + return OUT_OF_BOUNDS; + } else if (index >= bufsize) { + // Allocate more space in the buffer. + try { + while (bufsize <= index) bufsize += BUFFER_INCREMENT; + br.reset(); + br.mark(bufsize); + br.skip(index-1); + } catch (IOException e) { } + } else if (this.index != index) { + try { + br.reset(); + br.skip(index-1); + } catch (IOException e) { } + } + char ch = OUT_OF_BOUNDS; + + try { + int i = br.read(); + this.index = index+1; // this.index is index of next pos relative to charAt(0) + if (i == -1) { + // set flag that next should fail next time? + end = index; + return ch; + } + ch = (char) i; + } catch (IOException ie) { } + + return ch; + } + + public boolean move(int index) { + // move read position [index] clicks from 'charAt(0)' + boolean retval = true; + while (retval && (index-- > 0)) retval = next(); + return retval; + } + + public boolean isValid() { + return (cached != OUT_OF_BOUNDS); + } +} + diff --git a/libjava/gnu/regexp/CharIndexedReader.java b/libjava/gnu/regexp/CharIndexedReader.java new file mode 100644 index 00000000000..aa0fa5a313d --- /dev/null +++ b/libjava/gnu/regexp/CharIndexedReader.java @@ -0,0 +1,142 @@ +/* + * gnu/regexp/CharIndexedReader.java + * Copyright (C) 2001 Lee Sau Dan + * Based on gnu.regexp.CharIndexedInputStream by Wes Biggs + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +package gnu.regexp; +import java.io.Reader; +import java.io.BufferedReader; +import java.io.IOException; + +// TODO: move(x) shouldn't rely on calling next() x times + +class CharIndexedReader implements CharIndexed { + private static final int BUFFER_INCREMENT = 1024; + private static final int UNKNOWN = Integer.MAX_VALUE; // value for end + + private final BufferedReader br; + // so that we don't try to reset() right away + private int index = -1; + + private int bufsize = BUFFER_INCREMENT; + + private int end = UNKNOWN; + + private char cached = OUT_OF_BOUNDS; + + // Big enough for a \r\n pair + // lookBehind[0] = most recent + // lookBehind[1] = second most recent + private char[] lookBehind = new char[] { OUT_OF_BOUNDS, OUT_OF_BOUNDS }; + + CharIndexedReader(Reader reader, int index) { + if (reader instanceof BufferedReader) { + br = (BufferedReader) reader; + } else { + br = new BufferedReader(reader,BUFFER_INCREMENT); + } + next(); + if (index > 0) move(index); + } + + private boolean next() { + lookBehind[1] = lookBehind[0]; + lookBehind[0] = cached; + + if (end == 1) { + cached = OUT_OF_BOUNDS; + return false; + } + end--; // closer to end + + try { + if (index != -1) { + br.reset(); + } + int i = br.read(); + br.mark(bufsize); + if (i == -1) { + end = 1; + cached = OUT_OF_BOUNDS; + return false; + } + + // convert the byte read into a char + cached = (char) i; + index = 1; + } catch (IOException e) { + e.printStackTrace(); + cached = OUT_OF_BOUNDS; + return false; + } + return true; + } + + public char charAt(int index) { + if (index == 0) { + return cached; + } else if (index >= end) { + return OUT_OF_BOUNDS; + } else if (index >= bufsize) { + // Allocate more space in the buffer. + try { + while (bufsize <= index) bufsize += BUFFER_INCREMENT; + br.reset(); + br.mark(bufsize); + br.skip(index-1); + } catch (IOException e) { } + } else if (this.index != index) { + try { + br.reset(); + br.skip(index-1); + } catch (IOException e) { } + } else if (index == -1) { + return lookBehind[0]; + } else if (index == -2) { + return lookBehind[1]; + } else if (index < -2) { + return OUT_OF_BOUNDS; + } + + char ch = OUT_OF_BOUNDS; + + try { + int i = br.read(); + this.index = index+1; // this.index is index of next pos relative to charAt(0) + if (i == -1) { + // set flag that next should fail next time? + end = index; + return ch; + } + ch = (char) i; + } catch (IOException ie) { } + + return ch; + } + + public boolean move(int index) { + // move read position [index] clicks from 'charAt(0)' + boolean retval = true; + while (retval && (index-- > 0)) retval = next(); + return retval; + } + + public boolean isValid() { + return (cached != OUT_OF_BOUNDS); + } +} diff --git a/libjava/gnu/regexp/CharIndexedString.java b/libjava/gnu/regexp/CharIndexedString.java new file mode 100644 index 00000000000..adff7ac7186 --- /dev/null +++ b/libjava/gnu/regexp/CharIndexedString.java @@ -0,0 +1,64 @@ +/* gnu/regexp/CharIndexedString.java + Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.regexp; +import java.io.Serializable; + +class CharIndexedString implements CharIndexed, Serializable { + private String s; + private int anchor; + private int len; + + CharIndexedString(String str, int index) { + s = str; + len = s.length(); + anchor = index; + } + + public char charAt(int index) { + int pos = anchor + index; + return ((pos < len) && (pos >= 0)) ? s.charAt(pos) : OUT_OF_BOUNDS; + } + + public boolean isValid() { + return (anchor < len); + } + + public boolean move(int index) { + return ((anchor += index) < len); + } +} diff --git a/libjava/gnu/regexp/CharIndexedStringBuffer.java b/libjava/gnu/regexp/CharIndexedStringBuffer.java new file mode 100644 index 00000000000..2eb8c23f36a --- /dev/null +++ b/libjava/gnu/regexp/CharIndexedStringBuffer.java @@ -0,0 +1,62 @@ +/* gnu/regexp/CharIndexedStringBuffer.java + Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.regexp; +import java.io.Serializable; + +class CharIndexedStringBuffer implements CharIndexed, Serializable { + private StringBuffer s; + private int anchor; + + CharIndexedStringBuffer(StringBuffer str, int index) { + s = str; + anchor = index; + } + + public char charAt(int index) { + int pos = anchor + index; + return ((pos < s.length()) && (pos >= 0)) ? s.charAt(pos) : OUT_OF_BOUNDS; + } + + public boolean isValid() { + return (anchor < s.length()); + } + + public boolean move(int index) { + return ((anchor += index) < s.length()); + } +} diff --git a/libjava/gnu/regexp/MessagesBundle.properties b/libjava/gnu/regexp/MessagesBundle.properties new file mode 100644 index 00000000000..1e077a4033c --- /dev/null +++ b/libjava/gnu/regexp/MessagesBundle.properties @@ -0,0 +1,22 @@ +# Localized error messages for gnu.regexp + +# Prefix for REException messages +error.prefix=At position {0} in regular expression pattern: + +# REException (parse error) messages +repeat.assertion=repeated token is zero-width assertion +repeat.chained=attempted to repeat a token that is already repeated +repeat.no.token=quantifier (?*+{}) without preceding token +repeat.empty.token=repeated token may be empty +unmatched.brace=unmatched brace +unmatched.bracket=unmatched bracket +unmatched.paren=unmatched parenthesis +interval.no.end=expected end of interval +class.no.end=expected end of character class +subexpr.no.end=expected end of subexpression +interval.order=interval minimum is greater than maximum +interval.error=interval is empty or contains illegal characters +ends.with.backslash=backslash at end of pattern + +# RESyntax message +syntax.final=Syntax has been declared final and cannot be modified diff --git a/libjava/gnu/regexp/MessagesBundle_fr.properties b/libjava/gnu/regexp/MessagesBundle_fr.properties new file mode 100644 index 00000000000..8ab8356c17b --- /dev/null +++ b/libjava/gnu/regexp/MessagesBundle_fr.properties @@ -0,0 +1,22 @@ +# Localized error messages for gnu.regexp + +# Prefix for REException messages +error.prefix=A l''index {0} dans le modèle d''expression régulière: + +# REException (parse error) messages +repeat.assertion=l'élément répété est de largeur zéro +repeat.chained=tentative de répétition d'un élément déjà répété +repeat.no.token=quantifieur (?*+{}) sans élément précédent +repeat.empty.token=l'élément répété peut être vide +unmatched.brace=accolade inégalée +unmatched.bracket=crochet inégalé +unmatched.paren=parenthèse inégalée +interval.no.end=fin d'interval attendue +class.no.end=fin de classe de caractères attendue +subexpr.no.end=fin de sous-expression attendue +interval.order=l'interval minimum est supérieur à l'interval maximum +interval.error=l'interval est vide ou contient des caractères illégaux +ends.with.backslash=antislash à la fin du modèle + +# RESyntax message +syntax.final=La syntaxe a été déclarée finale et ne peut pas être modifiée diff --git a/libjava/gnu/regexp/RE.java b/libjava/gnu/regexp/RE.java new file mode 100644 index 00000000000..fdc00feb3fb --- /dev/null +++ b/libjava/gnu/regexp/RE.java @@ -0,0 +1,1350 @@ +/* gnu/regexp/RE.java + Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.regexp; +import java.io.InputStream; +import java.io.Serializable; +import java.util.Locale; +import java.util.PropertyResourceBundle; +import java.util.ResourceBundle; +import java.util.Vector; + +class IntPair implements Serializable { + public int first, second; +} + +class CharUnit implements Serializable { + public char ch; + public boolean bk; +} + +/** + * RE provides the user interface for compiling and matching regular + * expressions. + * <P> + * A regular expression object (class RE) is compiled by constructing it + * from a String, StringBuffer or character array, with optional + * compilation flags (below) + * and an optional syntax specification (see RESyntax; if not specified, + * <code>RESyntax.RE_SYNTAX_PERL5</code> is used). + * <P> + * Once compiled, a regular expression object is reusable as well as + * threadsafe: multiple threads can use the RE instance simultaneously + * to match against different input text. + * <P> + * Various methods attempt to match input text against a compiled + * regular expression. These methods are: + * <LI><code>isMatch</code>: returns true if the input text in its + * entirety matches the regular expression pattern. + * <LI><code>getMatch</code>: returns the first match found in the + * input text, or null if no match is found. + * <LI><code>getAllMatches</code>: returns an array of all + * non-overlapping matches found in the input text. If no matches are + * found, the array is zero-length. + * <LI><code>substitute</code>: substitute the first occurence of the + * pattern in the input text with a replacement string (which may + * include metacharacters $0-$9, see REMatch.substituteInto). + * <LI><code>substituteAll</code>: same as above, but repeat for each + * match before returning. + * <LI><code>getMatchEnumeration</code>: returns an REMatchEnumeration + * object that allows iteration over the matches (see + * REMatchEnumeration for some reasons why you may want to do this + * instead of using <code>getAllMatches</code>. + * <P> + * + * These methods all have similar argument lists. The input can be a + * String, a character array, a StringBuffer, or an + * InputStream of some sort. Note that when using an + * InputStream, the stream read position cannot be guaranteed after + * attempting a match (this is not a bug, but a consequence of the way + * regular expressions work). Using an REMatchEnumeration can + * eliminate most positioning problems. + * + * <P> + * + * The optional index argument specifies the offset from the beginning + * of the text at which the search should start (see the descriptions + * of some of the execution flags for how this can affect positional + * pattern operators). For an InputStream, this means an + * offset from the current read position, so subsequent calls with the + * same index argument on an InputStream will not + * necessarily access the same position on the stream, whereas + * repeated searches at a given index in a fixed string will return + * consistent results. + * + * <P> + * You can optionally affect the execution environment by using a + * combination of execution flags (constants listed below). + * + * <P> + * All operations on a regular expression are performed in a + * thread-safe manner. + * + * @author <A HREF="mailto:wes@cacas.org">Wes Biggs</A> + * @version 1.1.5-dev, to be released + */ + +public class RE extends REToken { + // This String will be returned by getVersion() + private static final String VERSION = "1.1.5-dev"; + + // The localized strings are kept in a separate file + private static ResourceBundle messages = PropertyResourceBundle.getBundle("gnu/regexp/MessagesBundle", Locale.getDefault()); + + // These are, respectively, the first and last tokens in our linked list + // If there is only one token, firstToken == lastToken + private REToken firstToken, lastToken; + + // This is the number of subexpressions in this regular expression, + // with a minimum value of zero. Returned by getNumSubs() + private int numSubs; + + /** Minimum length, in characters, of any possible match. */ + private int minimumLength; + + /** + * Compilation flag. Do not differentiate case. Subsequent + * searches using this RE will be case insensitive. + */ + public static final int REG_ICASE = 2; + + /** + * Compilation flag. The match-any-character operator (dot) + * will match a newline character. When set this overrides the syntax + * bit RE_DOT_NEWLINE (see RESyntax for details). This is equivalent to + * the "/s" operator in Perl. + */ + public static final int REG_DOT_NEWLINE = 4; + + /** + * Compilation flag. Use multiline mode. In this mode, the ^ and $ + * anchors will match based on newlines within the input. This is + * equivalent to the "/m" operator in Perl. + */ + public static final int REG_MULTILINE = 8; + + /** + * Execution flag. + * The match-beginning operator (^) will not match at the beginning + * of the input string. Useful for matching on a substring when you + * know the context of the input is such that position zero of the + * input to the match test is not actually position zero of the text. + * <P> + * This example demonstrates the results of various ways of matching on + * a substring. + * <P> + * <CODE> + * String s = "food bar fool";<BR> + * RE exp = new RE("^foo.");<BR> + * REMatch m0 = exp.getMatch(s);<BR> + * REMatch m1 = exp.getMatch(s.substring(8));<BR> + * REMatch m2 = exp.getMatch(s.substring(8),0,RE.REG_NOTBOL); <BR> + * REMatch m3 = exp.getMatch(s,8); <BR> + * REMatch m4 = exp.getMatch(s,8,RE.REG_ANCHORINDEX); <BR> + * <P> + * // Results:<BR> + * // m0.toString(): "food"<BR> + * // m1.toString(): "fool"<BR> + * // m2.toString(): null<BR> + * // m3.toString(): null<BR> + * // m4.toString(): "fool"<BR> + * </CODE> + */ + public static final int REG_NOTBOL = 16; + + /** + * Execution flag. + * The match-end operator ($) does not match at the end + * of the input string. Useful for matching on substrings. + */ + public static final int REG_NOTEOL = 32; + + /** + * Execution flag. + * When a match method is invoked that starts matching at a non-zero + * index into the input, treat the input as if it begins at the index + * given. The effect of this flag is that the engine does not "see" + * any text in the input before the given index. This is useful so + * that the match-beginning operator (^) matches not at position 0 + * in the input string, but at the position the search started at + * (based on the index input given to the getMatch function). See + * the example under REG_NOTBOL. It also affects the use of the \< + * and \b operators. + */ + public static final int REG_ANCHORINDEX = 64; + + /** + * Execution flag. + * The substitute and substituteAll methods will not attempt to + * interpolate occurrences of $1-$9 in the replacement text with + * the corresponding subexpressions. For example, you may want to + * replace all matches of "one dollar" with "$1". + */ + public static final int REG_NO_INTERPOLATE = 128; + + /** Returns a string representing the version of the gnu.regexp package. */ + public static final String version() { + return VERSION; + } + + // Retrieves a message from the ResourceBundle + static final String getLocalizedMessage(String key) { + return messages.getString(key); + } + + /** + * Constructs a regular expression pattern buffer without any compilation + * flags set, and using the default syntax (RESyntax.RE_SYNTAX_PERL5). + * + * @param pattern A regular expression pattern, in the form of a String, + * StringBuffer or char[]. Other input types will be converted to + * strings using the toString() method. + * @exception REException The input pattern could not be parsed. + * @exception NullPointerException The pattern was null. + */ + public RE(Object pattern) throws REException { + this(pattern,0,RESyntax.RE_SYNTAX_PERL5,0,0); + } + + /** + * Constructs a regular expression pattern buffer using the specified + * compilation flags and the default syntax (RESyntax.RE_SYNTAX_PERL5). + * + * @param pattern A regular expression pattern, in the form of a String, + * StringBuffer, or char[]. Other input types will be converted to + * strings using the toString() method. + * @param cflags The logical OR of any combination of the compilation flags listed above. + * @exception REException The input pattern could not be parsed. + * @exception NullPointerException The pattern was null. + */ + public RE(Object pattern, int cflags) throws REException { + this(pattern,cflags,RESyntax.RE_SYNTAX_PERL5,0,0); + } + + /** + * Constructs a regular expression pattern buffer using the specified + * compilation flags and regular expression syntax. + * + * @param pattern A regular expression pattern, in the form of a String, + * StringBuffer, or char[]. Other input types will be converted to + * strings using the toString() method. + * @param cflags The logical OR of any combination of the compilation flags listed above. + * @param syntax The type of regular expression syntax to use. + * @exception REException The input pattern could not be parsed. + * @exception NullPointerException The pattern was null. + */ + public RE(Object pattern, int cflags, RESyntax syntax) throws REException { + this(pattern,cflags,syntax,0,0); + } + + // internal constructor used for alternation + private RE(REToken first, REToken last,int subs, int subIndex, int minLength) { + super(subIndex); + firstToken = first; + lastToken = last; + numSubs = subs; + minimumLength = minLength; + addToken(new RETokenEndSub(subIndex)); + } + + private RE(Object patternObj, int cflags, RESyntax syntax, int myIndex, int nextSub) throws REException { + super(myIndex); // Subexpression index of this token. + initialize(patternObj, cflags, syntax, myIndex, nextSub); + } + + // For use by subclasses + protected RE() { super(0); } + + // The meat of construction + protected void initialize(Object patternObj, int cflags, RESyntax syntax, int myIndex, int nextSub) throws REException { + char[] pattern; + if (patternObj instanceof String) { + pattern = ((String) patternObj).toCharArray(); + } else if (patternObj instanceof char[]) { + pattern = (char[]) patternObj; + } else if (patternObj instanceof StringBuffer) { + pattern = new char [((StringBuffer) patternObj).length()]; + ((StringBuffer) patternObj).getChars(0,pattern.length,pattern,0); + } else { + pattern = patternObj.toString().toCharArray(); + } + + int pLength = pattern.length; + + numSubs = 0; // Number of subexpressions in this token. + Vector branches = null; + + // linked list of tokens (sort of -- some closed loops can exist) + firstToken = lastToken = null; + + // Precalculate these so we don't pay for the math every time we + // need to access them. + boolean insens = ((cflags & REG_ICASE) > 0); + + // Parse pattern into tokens. Does anyone know if it's more efficient + // to use char[] than a String.charAt()? I'm assuming so. + + // index tracks the position in the char array + int index = 0; + + // this will be the current parse character (pattern[index]) + CharUnit unit = new CharUnit(); + + // This is used for {x,y} calculations + IntPair minMax = new IntPair(); + + // Buffer a token so we can create a TokenRepeated, etc. + REToken currentToken = null; + char ch; + + while (index < pLength) { + // read the next character unit (including backslash escapes) + index = getCharUnit(pattern,index,unit); + + // ALTERNATION OPERATOR + // \| or | (if RE_NO_BK_VBAR) or newline (if RE_NEWLINE_ALT) + // not available if RE_LIMITED_OPS is set + + // TODO: the '\n' literal here should be a test against REToken.newline, + // which unfortunately may be more than a single character. + if ( ( (unit.ch == '|' && (syntax.get(RESyntax.RE_NO_BK_VBAR) ^ unit.bk)) + || (syntax.get(RESyntax.RE_NEWLINE_ALT) && (unit.ch == '\n') && !unit.bk) ) + && !syntax.get(RESyntax.RE_LIMITED_OPS)) { + // make everything up to here be a branch. create vector if nec. + addToken(currentToken); + RE theBranch = new RE(firstToken, lastToken, numSubs, subIndex, minimumLength); + minimumLength = 0; + if (branches == null) { + branches = new Vector(); + } + branches.addElement(theBranch); + firstToken = lastToken = currentToken = null; + } + + // INTERVAL OPERATOR: + // {x} | {x,} | {x,y} (RE_INTERVALS && RE_NO_BK_BRACES) + // \{x\} | \{x,\} | \{x,y\} (RE_INTERVALS && !RE_NO_BK_BRACES) + // + // OPEN QUESTION: + // what is proper interpretation of '{' at start of string? + + else if ((unit.ch == '{') && syntax.get(RESyntax.RE_INTERVALS) && (syntax.get(RESyntax.RE_NO_BK_BRACES) ^ unit.bk)) { + int newIndex = getMinMax(pattern,index,minMax,syntax); + if (newIndex > index) { + if (minMax.first > minMax.second) + throw new REException(getLocalizedMessage("interval.order"),REException.REG_BADRPT,newIndex); + if (currentToken == null) + throw new REException(getLocalizedMessage("repeat.no.token"),REException.REG_BADRPT,newIndex); + if (currentToken instanceof RETokenRepeated) + throw new REException(getLocalizedMessage("repeat.chained"),REException.REG_BADRPT,newIndex); + if (currentToken instanceof RETokenWordBoundary || currentToken instanceof RETokenWordBoundary) + throw new REException(getLocalizedMessage("repeat.assertion"),REException.REG_BADRPT,newIndex); + if ((currentToken.getMinimumLength() == 0) && (minMax.second == Integer.MAX_VALUE)) + throw new REException(getLocalizedMessage("repeat.empty.token"),REException.REG_BADRPT,newIndex); + index = newIndex; + currentToken = setRepeated(currentToken,minMax.first,minMax.second,index); + } + else { + addToken(currentToken); + currentToken = new RETokenChar(subIndex,unit.ch,insens); + } + } + + // LIST OPERATOR: + // [...] | [^...] + + else if ((unit.ch == '[') && !unit.bk) { + Vector options = new Vector(); + boolean negative = false; + char lastChar = 0; + if (index == pLength) throw new REException(getLocalizedMessage("unmatched.bracket"),REException.REG_EBRACK,index); + + // Check for initial caret, negation + if ((ch = pattern[index]) == '^') { + negative = true; + if (++index == pLength) throw new REException(getLocalizedMessage("class.no.end"),REException.REG_EBRACK,index); + ch = pattern[index]; + } + + // Check for leading right bracket literal + if (ch == ']') { + lastChar = ch; + if (++index == pLength) throw new REException(getLocalizedMessage("class.no.end"),REException.REG_EBRACK,index); + } + + while ((ch = pattern[index++]) != ']') { + if ((ch == '-') && (lastChar != 0)) { + if (index == pLength) throw new REException(getLocalizedMessage("class.no.end"),REException.REG_EBRACK,index); + if ((ch = pattern[index]) == ']') { + options.addElement(new RETokenChar(subIndex,lastChar,insens)); + lastChar = '-'; + } else { + options.addElement(new RETokenRange(subIndex,lastChar,ch,insens)); + lastChar = 0; + index++; + } + } else if ((ch == '\\') && syntax.get(RESyntax.RE_BACKSLASH_ESCAPE_IN_LISTS)) { + if (index == pLength) throw new REException(getLocalizedMessage("class.no.end"),REException.REG_EBRACK,index); + int posixID = -1; + boolean negate = false; + char asciiEsc = 0; + if (("dswDSW".indexOf(pattern[index]) != -1) && syntax.get(RESyntax.RE_CHAR_CLASS_ESC_IN_LISTS)) { + switch (pattern[index]) { + case 'D': + negate = true; + case 'd': + posixID = RETokenPOSIX.DIGIT; + break; + case 'S': + negate = true; + case 's': + posixID = RETokenPOSIX.SPACE; + break; + case 'W': + negate = true; + case 'w': + posixID = RETokenPOSIX.ALNUM; + break; + } + } + else if ("nrt".indexOf(pattern[index]) != -1) { + switch (pattern[index]) { + case 'n': + asciiEsc = '\n'; + break; + case 't': + asciiEsc = '\t'; + break; + case 'r': + asciiEsc = '\r'; + break; + } + } + if (lastChar != 0) options.addElement(new RETokenChar(subIndex,lastChar,insens)); + + if (posixID != -1) { + options.addElement(new RETokenPOSIX(subIndex,posixID,insens,negate)); + } else if (asciiEsc != 0) { + lastChar = asciiEsc; + } else { + lastChar = pattern[index]; + } + ++index; + } else if ((ch == '[') && (syntax.get(RESyntax.RE_CHAR_CLASSES)) && (index < pLength) && (pattern[index] == ':')) { + StringBuffer posixSet = new StringBuffer(); + index = getPosixSet(pattern,index+1,posixSet); + int posixId = RETokenPOSIX.intValue(posixSet.toString()); + if (posixId != -1) + options.addElement(new RETokenPOSIX(subIndex,posixId,insens,false)); + } else { + if (lastChar != 0) options.addElement(new RETokenChar(subIndex,lastChar,insens)); + lastChar = ch; + } + if (index == pLength) throw new REException(getLocalizedMessage("class.no.end"),REException.REG_EBRACK,index); + } // while in list + // Out of list, index is one past ']' + + if (lastChar != 0) options.addElement(new RETokenChar(subIndex,lastChar,insens)); + + // Create a new RETokenOneOf + addToken(currentToken); + options.trimToSize(); + currentToken = new RETokenOneOf(subIndex,options,negative); + } + + // SUBEXPRESSIONS + // (...) | \(...\) depending on RE_NO_BK_PARENS + + else if ((unit.ch == '(') && (syntax.get(RESyntax.RE_NO_BK_PARENS) ^ unit.bk)) { + boolean pure = false; + boolean comment = false; + if ((index+1 < pLength) && (pattern[index] == '?')) { + switch (pattern[index+1]) { + case ':': + if (syntax.get(RESyntax.RE_PURE_GROUPING)) { + pure = true; + index += 2; + } + break; + case '#': + if (syntax.get(RESyntax.RE_COMMENTS)) { + comment = true; + } + break; + default: + throw new REException(getLocalizedMessage("repeat.no.token"), REException.REG_BADRPT, index); + } + } + + if (index >= pLength) { + throw new REException(getLocalizedMessage("unmatched.paren"), REException.REG_ESUBREG,index); + } + + // find end of subexpression + int endIndex = index; + int nextIndex = index; + int nested = 0; + + while ( ((nextIndex = getCharUnit(pattern,endIndex,unit)) > 0) + && !(nested == 0 && (unit.ch == ')') && (syntax.get(RESyntax.RE_NO_BK_PARENS) ^ unit.bk)) ) + if ((endIndex = nextIndex) >= pLength) + throw new REException(getLocalizedMessage("subexpr.no.end"),REException.REG_ESUBREG,nextIndex); + else if (unit.ch == '(' && (syntax.get(RESyntax.RE_NO_BK_PARENS) ^ unit.bk)) + nested++; + else if (unit.ch == ')' && (syntax.get(RESyntax.RE_NO_BK_PARENS) ^ unit.bk)) + nested--; + + // endIndex is now position at a ')','\)' + // nextIndex is end of string or position after ')' or '\)' + + if (comment) index = nextIndex; + else { // not a comment + // create RE subexpression as token. + addToken(currentToken); + if (!pure) { + numSubs++; + } + + int useIndex = (pure) ? 0 : nextSub + numSubs; + currentToken = new RE(String.valueOf(pattern,index,endIndex-index).toCharArray(),cflags,syntax,useIndex,nextSub + numSubs); + numSubs += ((RE) currentToken).getNumSubs(); + + index = nextIndex; + } // not a comment + } // subexpression + + // UNMATCHED RIGHT PAREN + // ) or \) throw exception if + // !syntax.get(RESyntax.RE_UNMATCHED_RIGHT_PAREN_ORD) + else if (!syntax.get(RESyntax.RE_UNMATCHED_RIGHT_PAREN_ORD) && ((unit.ch == ')') && (syntax.get(RESyntax.RE_NO_BK_PARENS) ^ unit.bk))) { + throw new REException(getLocalizedMessage("unmatched.paren"),REException.REG_EPAREN,index); + } + + // START OF LINE OPERATOR + // ^ + + else if ((unit.ch == '^') && !unit.bk) { + addToken(currentToken); + currentToken = null; + addToken(new RETokenStart(subIndex,((cflags & REG_MULTILINE) > 0) ? syntax.getLineSeparator() : null)); + } + + // END OF LINE OPERATOR + // $ + + else if ((unit.ch == '$') && !unit.bk) { + addToken(currentToken); + currentToken = null; + addToken(new RETokenEnd(subIndex,((cflags & REG_MULTILINE) > 0) ? syntax.getLineSeparator() : null)); + } + + // MATCH-ANY-CHARACTER OPERATOR (except possibly newline and null) + // . + + else if ((unit.ch == '.') && !unit.bk) { + addToken(currentToken); + currentToken = new RETokenAny(subIndex,syntax.get(RESyntax.RE_DOT_NEWLINE) || ((cflags & REG_DOT_NEWLINE) > 0),syntax.get(RESyntax.RE_DOT_NOT_NULL)); + } + + // ZERO-OR-MORE REPEAT OPERATOR + // * + + else if ((unit.ch == '*') && !unit.bk) { + if (currentToken == null) + throw new REException(getLocalizedMessage("repeat.no.token"),REException.REG_BADRPT,index); + if (currentToken instanceof RETokenRepeated) + throw new REException(getLocalizedMessage("repeat.chained"),REException.REG_BADRPT,index); + if (currentToken instanceof RETokenWordBoundary || currentToken instanceof RETokenWordBoundary) + throw new REException(getLocalizedMessage("repeat.assertion"),REException.REG_BADRPT,index); + if (currentToken.getMinimumLength() == 0) + throw new REException(getLocalizedMessage("repeat.empty.token"),REException.REG_BADRPT,index); + currentToken = setRepeated(currentToken,0,Integer.MAX_VALUE,index); + } + + // ONE-OR-MORE REPEAT OPERATOR + // + | \+ depending on RE_BK_PLUS_QM + // not available if RE_LIMITED_OPS is set + + else if ((unit.ch == '+') && !syntax.get(RESyntax.RE_LIMITED_OPS) && (!syntax.get(RESyntax.RE_BK_PLUS_QM) ^ unit.bk)) { + if (currentToken == null) + throw new REException(getLocalizedMessage("repeat.no.token"),REException.REG_BADRPT,index); + if (currentToken instanceof RETokenRepeated) + throw new REException(getLocalizedMessage("repeat.chained"),REException.REG_BADRPT,index); + if (currentToken instanceof RETokenWordBoundary || currentToken instanceof RETokenWordBoundary) + throw new REException(getLocalizedMessage("repeat.assertion"),REException.REG_BADRPT,index); + if (currentToken.getMinimumLength() == 0) + throw new REException(getLocalizedMessage("repeat.empty.token"),REException.REG_BADRPT,index); + currentToken = setRepeated(currentToken,1,Integer.MAX_VALUE,index); + } + + // ZERO-OR-ONE REPEAT OPERATOR / STINGY MATCHING OPERATOR + // ? | \? depending on RE_BK_PLUS_QM + // not available if RE_LIMITED_OPS is set + // stingy matching if RE_STINGY_OPS is set and it follows a quantifier + + else if ((unit.ch == '?') && !syntax.get(RESyntax.RE_LIMITED_OPS) && (!syntax.get(RESyntax.RE_BK_PLUS_QM) ^ unit.bk)) { + if (currentToken == null) throw new REException(getLocalizedMessage("repeat.no.token"),REException.REG_BADRPT,index); + + // Check for stingy matching on RETokenRepeated + if (currentToken instanceof RETokenRepeated) { + if (syntax.get(RESyntax.RE_STINGY_OPS) && !((RETokenRepeated)currentToken).isStingy()) + ((RETokenRepeated)currentToken).makeStingy(); + else + throw new REException(getLocalizedMessage("repeat.chained"),REException.REG_BADRPT,index); + } + else if (currentToken instanceof RETokenWordBoundary || currentToken instanceof RETokenWordBoundary) + throw new REException(getLocalizedMessage("repeat.assertion"),REException.REG_BADRPT,index); + else + currentToken = setRepeated(currentToken,0,1,index); + } + + // BACKREFERENCE OPERATOR + // \1 \2 ... \9 + // not available if RE_NO_BK_REFS is set + + else if (unit.bk && Character.isDigit(unit.ch) && !syntax.get(RESyntax.RE_NO_BK_REFS)) { + addToken(currentToken); + currentToken = new RETokenBackRef(subIndex,Character.digit(unit.ch,10),insens); + } + + // START OF STRING OPERATOR + // \A if RE_STRING_ANCHORS is set + + else if (unit.bk && (unit.ch == 'A') && syntax.get(RESyntax.RE_STRING_ANCHORS)) { + addToken(currentToken); + currentToken = new RETokenStart(subIndex,null); + } + + // WORD BREAK OPERATOR + // \b if ???? + + else if (unit.bk && (unit.ch == 'b') && syntax.get(RESyntax.RE_STRING_ANCHORS)) { + addToken(currentToken); + currentToken = new RETokenWordBoundary(subIndex, RETokenWordBoundary.BEGIN | RETokenWordBoundary.END, false); + } + + // WORD BEGIN OPERATOR + // \< if ???? + else if (unit.bk && (unit.ch == '<')) { + addToken(currentToken); + currentToken = new RETokenWordBoundary(subIndex, RETokenWordBoundary.BEGIN, false); + } + + // WORD END OPERATOR + // \> if ???? + else if (unit.bk && (unit.ch == '>')) { + addToken(currentToken); + currentToken = new RETokenWordBoundary(subIndex, RETokenWordBoundary.END, false); + } + + // NON-WORD BREAK OPERATOR + // \B if ???? + + else if (unit.bk && (unit.ch == 'B') && syntax.get(RESyntax.RE_STRING_ANCHORS)) { + addToken(currentToken); + currentToken = new RETokenWordBoundary(subIndex, RETokenWordBoundary.BEGIN | RETokenWordBoundary.END, true); + } + + + // DIGIT OPERATOR + // \d if RE_CHAR_CLASS_ESCAPES is set + + else if (unit.bk && (unit.ch == 'd') && syntax.get(RESyntax.RE_CHAR_CLASS_ESCAPES)) { + addToken(currentToken); + currentToken = new RETokenPOSIX(subIndex,RETokenPOSIX.DIGIT,insens,false); + } + + // NON-DIGIT OPERATOR + // \D + + else if (unit.bk && (unit.ch == 'D') && syntax.get(RESyntax.RE_CHAR_CLASS_ESCAPES)) { + addToken(currentToken); + currentToken = new RETokenPOSIX(subIndex,RETokenPOSIX.DIGIT,insens,true); + } + + // NEWLINE ESCAPE + // \n + + else if (unit.bk && (unit.ch == 'n')) { + addToken(currentToken); + currentToken = new RETokenChar(subIndex,'\n',false); + } + + // RETURN ESCAPE + // \r + + else if (unit.bk && (unit.ch == 'r')) { + addToken(currentToken); + currentToken = new RETokenChar(subIndex,'\r',false); + } + + // WHITESPACE OPERATOR + // \s if RE_CHAR_CLASS_ESCAPES is set + + else if (unit.bk && (unit.ch == 's') && syntax.get(RESyntax.RE_CHAR_CLASS_ESCAPES)) { + addToken(currentToken); + currentToken = new RETokenPOSIX(subIndex,RETokenPOSIX.SPACE,insens,false); + } + + // NON-WHITESPACE OPERATOR + // \S + + else if (unit.bk && (unit.ch == 'S') && syntax.get(RESyntax.RE_CHAR_CLASS_ESCAPES)) { + addToken(currentToken); + currentToken = new RETokenPOSIX(subIndex,RETokenPOSIX.SPACE,insens,true); + } + + // TAB ESCAPE + // \t + + else if (unit.bk && (unit.ch == 't')) { + addToken(currentToken); + currentToken = new RETokenChar(subIndex,'\t',false); + } + + // ALPHANUMERIC OPERATOR + // \w + + else if (unit.bk && (unit.ch == 'w') && syntax.get(RESyntax.RE_CHAR_CLASS_ESCAPES)) { + addToken(currentToken); + currentToken = new RETokenPOSIX(subIndex,RETokenPOSIX.ALNUM,insens,false); + } + + // NON-ALPHANUMERIC OPERATOR + // \W + + else if (unit.bk && (unit.ch == 'W') && syntax.get(RESyntax.RE_CHAR_CLASS_ESCAPES)) { + addToken(currentToken); + currentToken = new RETokenPOSIX(subIndex,RETokenPOSIX.ALNUM,insens,true); + } + + // END OF STRING OPERATOR + // \Z + + else if (unit.bk && (unit.ch == 'Z') && syntax.get(RESyntax.RE_STRING_ANCHORS)) { + addToken(currentToken); + currentToken = new RETokenEnd(subIndex,null); + } + + // NON-SPECIAL CHARACTER (or escape to make literal) + // c | \* for example + + else { // not a special character + addToken(currentToken); + currentToken = new RETokenChar(subIndex,unit.ch,insens); + } + } // end while + + // Add final buffered token and an EndSub marker + addToken(currentToken); + + if (branches != null) { + branches.addElement(new RE(firstToken,lastToken,numSubs,subIndex,minimumLength)); + branches.trimToSize(); // compact the Vector + minimumLength = 0; + firstToken = lastToken = null; + addToken(new RETokenOneOf(subIndex,branches,false)); + } + else addToken(new RETokenEndSub(subIndex)); + + } + + private static int getCharUnit(char[] input, int index, CharUnit unit) throws REException { + unit.ch = input[index++]; + if (unit.bk = (unit.ch == '\\')) + if (index < input.length) + unit.ch = input[index++]; + else throw new REException(getLocalizedMessage("ends.with.backslash"),REException.REG_ESCAPE,index); + return index; + } + + /** + * Checks if the regular expression matches the input in its entirety. + * + * @param input The input text. + */ + public boolean isMatch(Object input) { + return isMatch(input,0,0); + } + + /** + * Checks if the input string, starting from index, is an exact match of + * this regular expression. + * + * @param input The input text. + * @param index The offset index at which the search should be begin. + */ + public boolean isMatch(Object input,int index) { + return isMatch(input,index,0); + } + + + /** + * Checks if the input, starting from index and using the specified + * execution flags, is an exact match of this regular expression. + * + * @param input The input text. + * @param index The offset index at which the search should be begin. + * @param eflags The logical OR of any execution flags above. + */ + public boolean isMatch(Object input,int index,int eflags) { + return isMatchImpl(makeCharIndexed(input,index),index,eflags); + } + + private boolean isMatchImpl(CharIndexed input, int index, int eflags) { + if (firstToken == null) // Trivial case + return (input.charAt(0) == CharIndexed.OUT_OF_BOUNDS); + REMatch m = new REMatch(numSubs, index, eflags); + if (firstToken.match(input, m)) { + while (m != null) { + if (input.charAt(m.index) == CharIndexed.OUT_OF_BOUNDS) { + return true; + } + m = m.next; + } + } + return false; + } + + /** + * Returns the maximum number of subexpressions in this regular expression. + * If the expression contains branches, the value returned will be the + * maximum subexpressions in any of the branches. + */ + public int getNumSubs() { + return numSubs; + } + + // Overrides REToken.setUncle + void setUncle(REToken uncle) { + if (lastToken != null) { + lastToken.setUncle(uncle); + } else super.setUncle(uncle); // to deal with empty subexpressions + } + + // Overrides REToken.chain + + boolean chain(REToken next) { + super.chain(next); + setUncle(next); + return true; + } + + /** + * Returns the minimum number of characters that could possibly + * constitute a match of this regular expression. + */ + public int getMinimumLength() { + return minimumLength; + } + + /** + * Returns an array of all matches found in the input. + * + * If the regular expression allows the empty string to match, it will + * substitute matches at all positions except the end of the input. + * + * @param input The input text. + * @return a non-null (but possibly zero-length) array of matches + */ + public REMatch[] getAllMatches(Object input) { + return getAllMatches(input,0,0); + } + + /** + * Returns an array of all matches found in the input, + * beginning at the specified index position. + * + * If the regular expression allows the empty string to match, it will + * substitute matches at all positions except the end of the input. + * + * @param input The input text. + * @param index The offset index at which the search should be begin. + * @return a non-null (but possibly zero-length) array of matches + */ + public REMatch[] getAllMatches(Object input, int index) { + return getAllMatches(input,index,0); + } + + /** + * Returns an array of all matches found in the input string, + * beginning at the specified index position and using the specified + * execution flags. + * + * If the regular expression allows the empty string to match, it will + * substitute matches at all positions except the end of the input. + * + * @param input The input text. + * @param index The offset index at which the search should be begin. + * @param eflags The logical OR of any execution flags above. + * @return a non-null (but possibly zero-length) array of matches + */ + public REMatch[] getAllMatches(Object input, int index, int eflags) { + return getAllMatchesImpl(makeCharIndexed(input,index),index,eflags); + } + + // this has been changed since 1.03 to be non-overlapping matches + private REMatch[] getAllMatchesImpl(CharIndexed input, int index, int eflags) { + Vector all = new Vector(); + REMatch m = null; + while ((m = getMatchImpl(input,index,eflags,null)) != null) { + all.addElement(m); + index = m.getEndIndex(); + if (m.end[0] == 0) { // handle pathological case of zero-length match + index++; + input.move(1); + } else { + input.move(m.end[0]); + } + if (!input.isValid()) break; + } + REMatch[] mset = new REMatch[all.size()]; + all.copyInto(mset); + return mset; + } + + /* Implements abstract method REToken.match() */ + boolean match(CharIndexed input, REMatch mymatch) { + if (firstToken == null) return next(input, mymatch); + + // Note the start of this subexpression + mymatch.start[subIndex] = mymatch.index; + + return firstToken.match(input, mymatch); + } + + /** + * Returns the first match found in the input. If no match is found, + * null is returned. + * + * @param input The input text. + * @return An REMatch instance referencing the match, or null if none. + */ + public REMatch getMatch(Object input) { + return getMatch(input,0,0); + } + + /** + * Returns the first match found in the input, beginning + * the search at the specified index. If no match is found, + * returns null. + * + * @param input The input text. + * @param index The offset within the text to begin looking for a match. + * @return An REMatch instance referencing the match, or null if none. + */ + public REMatch getMatch(Object input, int index) { + return getMatch(input,index,0); + } + + /** + * Returns the first match found in the input, beginning + * the search at the specified index, and using the specified + * execution flags. If no match is found, returns null. + * + * @param input The input text. + * @param index The offset index at which the search should be begin. + * @param eflags The logical OR of any execution flags above. + * @return An REMatch instance referencing the match, or null if none. + */ + public REMatch getMatch(Object input, int index, int eflags) { + return getMatch(input,index,eflags,null); + } + + /** + * Returns the first match found in the input, beginning the search + * at the specified index, and using the specified execution flags. + * If no match is found, returns null. If a StringBuffer is + * provided and is non-null, the contents of the input text from the + * index to the beginning of the match (or to the end of the input, + * if there is no match) are appended to the StringBuffer. + * + * @param input The input text. + * @param index The offset index at which the search should be begin. + * @param eflags The logical OR of any execution flags above. + * @param buffer The StringBuffer to save pre-match text in. + * @return An REMatch instance referencing the match, or null if none. */ + public REMatch getMatch(Object input, int index, int eflags, StringBuffer buffer) { + return getMatchImpl(makeCharIndexed(input,index),index,eflags,buffer); + } + + REMatch getMatchImpl(CharIndexed input, int anchor, int eflags, StringBuffer buffer) { + // Create a new REMatch to hold results + REMatch mymatch = new REMatch(numSubs, anchor, eflags); + do { + // Optimization: check if anchor + minimumLength > length + if (minimumLength == 0 || input.charAt(minimumLength-1) != CharIndexed.OUT_OF_BOUNDS) { + if (match(input, mymatch)) { + // Find longest match of them all to observe leftmost longest + REMatch longest = mymatch; + while ((mymatch = mymatch.next) != null) { + if (mymatch.index > longest.index) { + longest = mymatch; + } + } + + longest.end[0] = longest.index; + longest.finish(input); + return longest; + } + } + mymatch.clear(++anchor); + // Append character to buffer if needed + if (buffer != null && input.charAt(0) != CharIndexed.OUT_OF_BOUNDS) { + buffer.append(input.charAt(0)); + } + } while (input.move(1)); + + // Special handling at end of input for e.g. "$" + if (minimumLength == 0) { + if (match(input, mymatch)) { + mymatch.finish(input); + return mymatch; + } + } + + return null; + } + + /** + * Returns an REMatchEnumeration that can be used to iterate over the + * matches found in the input text. + * + * @param input The input text. + * @return A non-null REMatchEnumeration instance. + */ + public REMatchEnumeration getMatchEnumeration(Object input) { + return getMatchEnumeration(input,0,0); + } + + + /** + * Returns an REMatchEnumeration that can be used to iterate over the + * matches found in the input text. + * + * @param input The input text. + * @param index The offset index at which the search should be begin. + * @return A non-null REMatchEnumeration instance, with its input cursor + * set to the index position specified. + */ + public REMatchEnumeration getMatchEnumeration(Object input, int index) { + return getMatchEnumeration(input,index,0); + } + + /** + * Returns an REMatchEnumeration that can be used to iterate over the + * matches found in the input text. + * + * @param input The input text. + * @param index The offset index at which the search should be begin. + * @param eflags The logical OR of any execution flags above. + * @return A non-null REMatchEnumeration instance, with its input cursor + * set to the index position specified. + */ + public REMatchEnumeration getMatchEnumeration(Object input, int index, int eflags) { + return new REMatchEnumeration(this,makeCharIndexed(input,index),index,eflags); + } + + + /** + * Substitutes the replacement text for the first match found in the input. + * + * @param input The input text. + * @param replace The replacement text, which may contain $x metacharacters (see REMatch.substituteInto). + * @return A String interpolating the substituted text. + * @see REMatch#substituteInto + */ + public String substitute(Object input,String replace) { + return substitute(input,replace,0,0); + } + + /** + * Substitutes the replacement text for the first match found in the input + * beginning at the specified index position. Specifying an index + * effectively causes the regular expression engine to throw away the + * specified number of characters. + * + * @param input The input text. + * @param replace The replacement text, which may contain $x metacharacters (see REMatch.substituteInto). + * @param index The offset index at which the search should be begin. + * @return A String containing the substring of the input, starting + * at the index position, and interpolating the substituted text. + * @see REMatch#substituteInto + */ + public String substitute(Object input,String replace,int index) { + return substitute(input,replace,index,0); + } + + /** + * Substitutes the replacement text for the first match found in the input + * string, beginning at the specified index position and using the + * specified execution flags. + * + * @param input The input text. + * @param replace The replacement text, which may contain $x metacharacters (see REMatch.substituteInto). + * @param index The offset index at which the search should be begin. + * @param eflags The logical OR of any execution flags above. + * @return A String containing the substring of the input, starting + * at the index position, and interpolating the substituted text. + * @see REMatch#substituteInto + */ + public String substitute(Object input,String replace,int index,int eflags) { + return substituteImpl(makeCharIndexed(input,index),replace,index,eflags); + } + + private String substituteImpl(CharIndexed input,String replace,int index,int eflags) { + StringBuffer buffer = new StringBuffer(); + REMatch m = getMatchImpl(input,index,eflags,buffer); + if (m==null) return buffer.toString(); + buffer.append( ((eflags & REG_NO_INTERPOLATE) > 0) ? + replace : m.substituteInto(replace) ); + if (input.move(m.end[0])) { + do { + buffer.append(input.charAt(0)); + } while (input.move(1)); + } + return buffer.toString(); + } + + /** + * Substitutes the replacement text for each non-overlapping match found + * in the input text. + * + * @param input The input text. + * @param replace The replacement text, which may contain $x metacharacters (see REMatch.substituteInto). + * @return A String interpolating the substituted text. + * @see REMatch#substituteInto + */ + public String substituteAll(Object input,String replace) { + return substituteAll(input,replace,0,0); + } + + /** + * Substitutes the replacement text for each non-overlapping match found + * in the input text, starting at the specified index. + * + * If the regular expression allows the empty string to match, it will + * substitute matches at all positions except the end of the input. + * + * @param input The input text. + * @param replace The replacement text, which may contain $x metacharacters (see REMatch.substituteInto). + * @param index The offset index at which the search should be begin. + * @return A String containing the substring of the input, starting + * at the index position, and interpolating the substituted text. + * @see REMatch#substituteInto + */ + public String substituteAll(Object input,String replace,int index) { + return substituteAll(input,replace,index,0); + } + + /** + * Substitutes the replacement text for each non-overlapping match found + * in the input text, starting at the specified index and using the + * specified execution flags. + * + * @param input The input text. + * @param replace The replacement text, which may contain $x metacharacters (see REMatch.substituteInto). + * @param index The offset index at which the search should be begin. + * @param eflags The logical OR of any execution flags above. + * @return A String containing the substring of the input, starting + * at the index position, and interpolating the substituted text. + * @see REMatch#substituteInto + */ + public String substituteAll(Object input,String replace,int index,int eflags) { + return substituteAllImpl(makeCharIndexed(input,index),replace,index,eflags); + } + + private String substituteAllImpl(CharIndexed input,String replace,int index,int eflags) { + StringBuffer buffer = new StringBuffer(); + REMatch m; + while ((m = getMatchImpl(input,index,eflags,buffer)) != null) { + buffer.append( ((eflags & REG_NO_INTERPOLATE) > 0) ? + replace : m.substituteInto(replace) ); + index = m.getEndIndex(); + if (m.end[0] == 0) { + char ch = input.charAt(0); + if (ch != CharIndexed.OUT_OF_BOUNDS) + buffer.append(ch); + input.move(1); + } else { + input.move(m.end[0]); + } + + if (!input.isValid()) break; + } + return buffer.toString(); + } + + /* Helper function for constructor */ + private void addToken(REToken next) { + if (next == null) return; + minimumLength += next.getMinimumLength(); + if (firstToken == null) { + lastToken = firstToken = next; + } else { + // if chain returns false, it "rejected" the token due to + // an optimization, and next was combined with lastToken + if (lastToken.chain(next)) { + lastToken = next; + } + } + } + + private static REToken setRepeated(REToken current, int min, int max, int index) throws REException { + if (current == null) throw new REException(getLocalizedMessage("repeat.no.token"),REException.REG_BADRPT,index); + return new RETokenRepeated(current.subIndex,current,min,max); + } + + private static int getPosixSet(char[] pattern,int index,StringBuffer buf) { + // Precondition: pattern[index-1] == ':' + // we will return pos of closing ']'. + int i; + for (i=index; i<(pattern.length-1); i++) { + if ((pattern[i] == ':') && (pattern[i+1] == ']')) + return i+2; + buf.append(pattern[i]); + } + return index; // didn't match up + } + + private int getMinMax(char[] input,int index,IntPair minMax,RESyntax syntax) throws REException { + // Precondition: input[index-1] == '{', minMax != null + + boolean mustMatch = !syntax.get(RESyntax.RE_NO_BK_BRACES); + int startIndex = index; + if (index == input.length) { + if (mustMatch) + throw new REException(getLocalizedMessage("unmatched.brace"),REException.REG_EBRACE,index); + else + return startIndex; + } + + int min,max=0; + CharUnit unit = new CharUnit(); + StringBuffer buf = new StringBuffer(); + + // Read string of digits + do { + index = getCharUnit(input,index,unit); + if (Character.isDigit(unit.ch)) + buf.append(unit.ch); + } while ((index != input.length) && Character.isDigit(unit.ch)); + + // Check for {} tomfoolery + if (buf.length() == 0) { + if (mustMatch) + throw new REException(getLocalizedMessage("interval.error"),REException.REG_EBRACE,index); + else + return startIndex; + } + + min = Integer.parseInt(buf.toString()); + + if ((unit.ch == '}') && (syntax.get(RESyntax.RE_NO_BK_BRACES) ^ unit.bk)) + max = min; + else if (index == input.length) + if (mustMatch) + throw new REException(getLocalizedMessage("interval.no.end"),REException.REG_EBRACE,index); + else + return startIndex; + else if ((unit.ch == ',') && !unit.bk) { + buf = new StringBuffer(); + // Read string of digits + while (((index = getCharUnit(input,index,unit)) != input.length) && Character.isDigit(unit.ch)) + buf.append(unit.ch); + + if (!((unit.ch == '}') && (syntax.get(RESyntax.RE_NO_BK_BRACES) ^ unit.bk))) + if (mustMatch) + throw new REException(getLocalizedMessage("interval.error"),REException.REG_EBRACE,index); + else + return startIndex; + + // This is the case of {x,} + if (buf.length() == 0) max = Integer.MAX_VALUE; + else max = Integer.parseInt(buf.toString()); + } else + if (mustMatch) + throw new REException(getLocalizedMessage("interval.error"),REException.REG_EBRACE,index); + else + return startIndex; + + // We know min and max now, and they are valid. + + minMax.first = min; + minMax.second = max; + + // return the index following the '}' + return index; + } + + /** + * Return a human readable form of the compiled regular expression, + * useful for debugging. + */ + public String toString() { + StringBuffer sb = new StringBuffer(); + dump(sb); + return sb.toString(); + } + + void dump(StringBuffer os) { + os.append('('); + if (subIndex == 0) + os.append("?:"); + if (firstToken != null) + firstToken.dumpAll(os); + os.append(')'); + } + + // Cast input appropriately or throw exception + private static CharIndexed makeCharIndexed(Object input, int index) { + // We could let a String fall through to final input, but since + // it's the most likely input type, we check it first. + if (input instanceof String) + return new CharIndexedString((String) input,index); + else if (input instanceof char[]) + return new CharIndexedCharArray((char[]) input,index); + else if (input instanceof StringBuffer) + return new CharIndexedStringBuffer((StringBuffer) input,index); + else if (input instanceof InputStream) + return new CharIndexedInputStream((InputStream) input,index); + else if (input instanceof CharIndexed) + return (CharIndexed) input; // do we lose index info? + else + return new CharIndexedString(input.toString(), index); + } +} diff --git a/libjava/gnu/regexp/REException.java b/libjava/gnu/regexp/REException.java new file mode 100644 index 00000000000..a10d2fc71fe --- /dev/null +++ b/libjava/gnu/regexp/REException.java @@ -0,0 +1,182 @@ +/* gnu/regexp/REException.java + Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.regexp; + +import java.text.MessageFormat; + +/** + * This is the regular expression exception class. An exception of this type + * defines the three attributes: + * <OL> + * <LI> A descriptive message of the error. + * <LI> An integral type code equivalent to one of the statically + * defined symbols listed below. + * <LI> The approximate position in the input string where the error + * occurred. + * </OL> + * + * @author <A HREF="mailto:wes@cacas.org">Wes Biggs</A> + */ + +public class REException extends Exception { + private int type; + private int pos; + + // Error conditions from GNU regcomp(3) manual + + /** + * Error flag. + * Invalid use of repetition operators such as using + * `*' as the first character. + */ + public static final int REG_BADRPT = 1; + + /** + * Error flag. + * Invalid use of back reference operator. + */ + public static final int REG_BADBR = 2; + + /** + * Error flag. + * Un-matched brace interval operators. + */ + public static final int REG_EBRACE = 3; + + /** + * Error flag. + * Un-matched bracket list operators. + */ + public static final int REG_EBRACK = 4; + + /** + * Error flag. + * Invalid use of the range operator, eg. the ending + * point of the range occurs prior to the starting + * point. + */ + public static final int REG_ERANGE = 5; + + /** + * Error flag. + * Unknown character class name. <B>Not implemented</B>. + */ + public static final int REG_ECTYPE = 6; + + /** + * Error flag. + * Un-matched parenthesis group operators. + */ + public static final int REG_EPAREN = 7; + + /** + * Error flag. + * Invalid back reference to a subexpression. + */ + public static final int REG_ESUBREG = 8; + + /** + * Error flag. + * Non specific error. <B>Not implemented</B>. + */ + public static final int REG_EEND = 9; + + /** + * Error flag. + * Invalid escape sequence. <B>Not implemented</B>. + */ + public static final int REG_ESCAPE = 10; + + /** + * Error flag. + * Invalid use of pattern operators such as group or list. + */ + public static final int REG_BADPAT = 11; + + /** + * Error flag. + * Compiled regular expression requires a pattern + * buffer larger than 64Kb. <B>Not implemented</B>. + */ + public static final int REG_ESIZE = 12; + + /** + * Error flag. + * The regex routines ran out of memory. <B>Not implemented</B>. + */ + public static final int REG_ESPACE = 13; + + REException(String msg, int type, int position) { + super(msg); + this.type = type; + this.pos = position; + } + + /** + * Returns the type of the exception, one of the constants listed above. + */ + + public int getType() { + return type; + } + + /** + * Returns the position, relative to the string or character array being + * compiled, where the error occurred. This position is generally the point + * where the error was detected, not necessarily the starting index of + * a bad subexpression. + */ + public int getPosition() { + return pos; + } + + /** + * Reports the descriptive message associated with this exception + * as well as its index position in the string or character array + * being compiled. + */ + public String getMessage() { + Object[] args = {new Integer(pos)}; + StringBuffer sb = new StringBuffer(); + String prefix = RE.getLocalizedMessage("error.prefix"); + sb.append(MessageFormat.format(prefix, args)); + sb.append('\n'); + sb.append(super.getMessage()); + return sb.toString(); + } +} diff --git a/libjava/gnu/regexp/REFilterInputStream.java b/libjava/gnu/regexp/REFilterInputStream.java new file mode 100644 index 00000000000..f56a9a2a9cb --- /dev/null +++ b/libjava/gnu/regexp/REFilterInputStream.java @@ -0,0 +1,140 @@ +/* gnu/regexp/REFilterInputStream.java + Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.regexp; +import java.io.FilterInputStream; +import java.io.InputStream; + +/** + * Replaces instances of a given RE found within an InputStream + * with replacement text. The replacements are interpolated into the + * stream when a match is found. + * + * @author <A HREF="mailto:wes@cacas.org">Wes Biggs</A> + * @deprecated This class cannot properly handle all character + * encodings. For proper handling, use the REFilterReader + * class instead. + */ + +public class REFilterInputStream extends FilterInputStream { + + private RE expr; + private String replace; + private String buffer; + private int bufpos; + private int offset; + private CharIndexedInputStream stream; + + /** + * Creates an REFilterInputStream. When reading from this stream, + * occurrences of patterns matching the supplied regular expression + * will be replaced with the supplied replacement text (the + * metacharacters $0 through $9 may be used to refer to the full + * match or subexpression matches). + * + * @param stream The InputStream to be filtered. + * @param expr The regular expression to search for. + * @param replace The text pattern to replace matches with. + */ + public REFilterInputStream(InputStream stream, RE expr, String replace) { + super(stream); + this.stream = new CharIndexedInputStream(stream,0); + this.expr = expr; + this.replace = replace; + } + + /** + * Reads the next byte from the stream per the general contract of + * InputStream.read(). Returns -1 on error or end of stream. + */ + public int read() { + // If we have buffered replace data, use it. + if ((buffer != null) && (bufpos < buffer.length())) { + return (int) buffer.charAt(bufpos++); + } + + // check if input is at a valid position + if (!stream.isValid()) return -1; + + REMatch mymatch = new REMatch(expr.getNumSubs(),offset,0); + if (expr.match(stream, mymatch)) { + mymatch.end[0] = mymatch.index; + mymatch.finish(stream); + stream.move(mymatch.toString().length()); + offset += mymatch.toString().length(); + buffer = mymatch.substituteInto(replace); + bufpos = 1; + + // This is prone to infinite loops if replace string turns out empty. + if (buffer.length() > 0) { + return buffer.charAt(0); + } + } + char ch = stream.charAt(0); + if (ch == CharIndexed.OUT_OF_BOUNDS) return -1; + stream.move(1); + offset++; + return ch; + } + + /** + * Returns false. REFilterInputStream does not support mark() and + * reset() methods. + */ + public boolean markSupported() { + return false; + } + + /** Reads from the stream into the provided array. */ + public int read(byte[] b, int off, int len) { + int i; + int ok = 0; + while (len-- > 0) { + i = read(); + if (i == -1) return (ok == 0) ? -1 : ok; + b[off++] = (byte) i; + ok++; + } + return ok; + } + + /** Reads from the stream into the provided array. */ + public int read(byte[] b) { + return read(b,0,b.length); + } +} diff --git a/libjava/gnu/regexp/REFilterReader.java b/libjava/gnu/regexp/REFilterReader.java new file mode 100644 index 00000000000..449efcc9b1c --- /dev/null +++ b/libjava/gnu/regexp/REFilterReader.java @@ -0,0 +1,117 @@ +/* + * gnu/regexp/REFilterReader.java + * Copyright (C) 2001 Lee Sau Dan + * Based on gnu.regexp.REFilterInputStream by Wes Biggs + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +package gnu.regexp; +import java.io.FilterReader; +import java.io.Reader; + +/** + * Replaces instances of a given RE with replacement text. + * + * @author <A HREF="http://www.csis.hku.hk/~sdlee/">Lee Sau Dan</A> + * @since gnu.regexp 1.1.0 + */ + +public class REFilterReader extends FilterReader { + + private RE expr; + private String replace; + private String buffer; + private int bufpos; + private int offset; + private CharIndexedReader stream; + + /** + * Creates an REFilterReader. When reading from this stream, + * occurrences of patterns matching the supplied regular expression + * will be replaced with the supplied replacement text (the + * metacharacters $0 through $9 may be used to refer to the full + * match or subexpression matches. + * + * @param stream The Reader to be filtered. + * @param expr The regular expression to search for. + * @param replace The text pattern to replace matches with. + */ + public REFilterReader(Reader stream, RE expr, String replace) { + super(stream); + this.stream = new CharIndexedReader(stream,0); + this.expr = expr; + this.replace = replace; + } + + /** + * Reads the next character from the stream per the general contract of + * Reader.read(). Returns -1 on error or end of stream. + */ + public int read() { + // If we have buffered replace data, use it. + if ((buffer != null) && (bufpos < buffer.length())) { + return (int) buffer.charAt(bufpos++); + } + + // check if input is at a valid position + if (!stream.isValid()) return -1; + + REMatch mymatch = new REMatch(expr.getNumSubs(),offset,0); + if (expr.match(stream,mymatch)) { + mymatch.end[0] = mymatch.index; + mymatch.finish(stream); + stream.move(mymatch.toString().length()); + offset += mymatch.toString().length(); + buffer = mymatch.substituteInto(replace); + bufpos = 1; + + if (buffer.length() > 0) { + return buffer.charAt(0); + } + } + char ch = stream.charAt(0); + if (ch == CharIndexed.OUT_OF_BOUNDS) return -1; + stream.move(1); + offset++; + return ch; + } + + /** + * Returns false. REFilterReader does not support mark() and + * reset() methods. + */ + public boolean markSupported() { + return false; + } + + /** Reads from the stream into the provided array. */ + public int read(char[] b, int off, int len) { + int i; + int ok = 0; + while (len-- > 0) { + i = read(); + if (i == -1) return (ok == 0) ? -1 : ok; + b[off++] = (char) i; + ok++; + } + return ok; + } + + /** Reads from the stream into the provided array. */ + public int read(char[] b) { + return read(b,0,b.length); + } +} diff --git a/libjava/gnu/regexp/REMatch.java b/libjava/gnu/regexp/REMatch.java new file mode 100644 index 00000000000..ac6c80e9196 --- /dev/null +++ b/libjava/gnu/regexp/REMatch.java @@ -0,0 +1,263 @@ +/* gnu/regexp/REMatch.java + Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.regexp; +import java.io.Serializable; + +/** + * An instance of this class represents a match + * completed by a gnu.regexp matching function. It can be used + * to obtain relevant information about the location of a match + * or submatch. + * + * @author <A HREF="mailto:wes@cacas.org">Wes Biggs</A> + */ +public final class REMatch implements Serializable, Cloneable { + private String matchedText; + + // These variables are package scope for fast access within the engine + int eflags; // execution flags this match was made using + + // Offset in source text where match was tried. This is zero-based; + // the actual position in the source text is given by (offset + anchor). + int offset; + + // Anchor position refers to the index into the source input + // at which the matching operation began. + // This is also useful for the ANCHORINDEX option. + int anchor; + + // Package scope; used by RE. + int index; // used while matching to mark current match position in input + int[] start; // start positions (relative to offset) for each (sub)exp. + int[] end; // end positions for the same + REMatch next; // other possibility (to avoid having to use arrays) + + public Object clone() { + try { + REMatch copy = (REMatch) super.clone(); + copy.next = null; + + copy.start = (int[]) start.clone(); + copy.end = (int[]) end.clone(); + + return copy; + } catch (CloneNotSupportedException e) { + throw new Error(); // doesn't happen + } + } + + void assignFrom(REMatch other) { + start = other.start; + end = other.end; + index = other.index; + // need to deep clone? + next = other.next; + } + + REMatch(int subs, int anchor, int eflags) { + start = new int[subs+1]; + end = new int[subs+1]; + this.anchor = anchor; + this.eflags = eflags; + clear(anchor); + } + + void finish(CharIndexed text) { + start[0] = 0; + StringBuffer sb = new StringBuffer(); + int i; + for (i = 0; i < end[0]; i++) + sb.append(text.charAt(i)); + matchedText = sb.toString(); + for (i = 0; i < start.length; i++) { + // If any subexpressions didn't terminate, they don't count + // TODO check if this code ever gets hit + if ((start[i] == -1) ^ (end[i] == -1)) { + start[i] = -1; + end[i] = -1; + } + } + next = null; // cut off alternates + } + + /** Clears the current match and moves the offset to the new index. */ + void clear(int index) { + offset = index; + this.index = 0; + for (int i = 0; i < start.length; i++) { + start[i] = end[i] = -1; + } + next = null; // cut off alternates + } + + /** + * Returns the string matching the pattern. This makes it convenient + * to write code like the following: + * <P> + * <code> + * REMatch myMatch = myExpression.getMatch(myString);<br> + * if (myMatch != null) System.out.println("Regexp found: "+myMatch); + * </code> + */ + public String toString() { + return matchedText; + } + + /** + * Returns the index within the input text where the match in its entirety + * began. + */ + public int getStartIndex() { + return offset + start[0]; + } + + /** + * Returns the index within the input string where the match in + * its entirety ends. The return value is the next position after + * the end of the string; therefore, a match created by the + * following call: + * + * <P> + * <code>REMatch myMatch = myExpression.getMatch(myString);</code> + * <P> + * can be viewed (given that myMatch is not null) by creating + * <P> + * <code>String theMatch = myString.substring(myMatch.getStartIndex(), + * myMatch.getEndIndex());</code> + * <P> + * But you can save yourself that work, since the <code>toString()</code> + * method (above) does exactly that for you. + */ + public int getEndIndex() { + return offset + end[0]; + } + + /** + * Returns the string matching the given subexpression. The subexpressions + * are indexed starting with one, not zero. That is, the subexpression + * identified by the first set of parentheses in a regular expression + * could be retrieved from an REMatch by calling match.toString(1). + * + * @param sub Index of the subexpression. + */ + public String toString(int sub) { + if ((sub >= start.length) || (start[sub] == -1)) return ""; + return (matchedText.substring(start[sub],end[sub])); + } + + /** + * Returns the index within the input string used to generate this match + * where subexpression number <i>sub</i> begins, or <code>-1</code> if + * the subexpression does not exist. The initial position is zero. + * + * @param sub Subexpression index + * @deprecated Use getStartIndex(int) instead. + */ + public int getSubStartIndex(int sub) { + if (sub >= start.length) return -1; + int x = start[sub]; + return (x == -1) ? x : offset + x; + } + + /** + * Returns the index within the input string used to generate this match + * where subexpression number <i>sub</i> begins, or <code>-1</code> if + * the subexpression does not exist. The initial position is zero. + * + * @param sub Subexpression index + * @since gnu.regexp 1.1.0 + */ + public int getStartIndex(int sub) { + if (sub >= start.length) return -1; + int x = start[sub]; + return (x == -1) ? x : offset + x; + } + + /** + * Returns the index within the input string used to generate this match + * where subexpression number <i>sub</i> ends, or <code>-1</code> if + * the subexpression does not exist. The initial position is zero. + * + * @param sub Subexpression index + * @deprecated Use getEndIndex(int) instead + */ + public int getSubEndIndex(int sub) { + if (sub >= start.length) return -1; + int x = end[sub]; + return (x == -1) ? x : offset + x; + } + + /** + * Returns the index within the input string used to generate this match + * where subexpression number <i>sub</i> ends, or <code>-1</code> if + * the subexpression does not exist. The initial position is zero. + * + * @param sub Subexpression index + */ + public int getEndIndex(int sub) { + if (sub >= start.length) return -1; + int x = end[sub]; + return (x == -1) ? x : offset + x; + } + + /** + * Substitute the results of this match to create a new string. + * This is patterned after PERL, so the tokens to watch out for are + * <code>$0</code> through <code>$9</code>. <code>$0</code> matches + * the full substring matched; <code>$<i>n</i></code> matches + * subexpression number <i>n</i>. + * + * @param input A string consisting of literals and <code>$<i>n</i></code> tokens. + */ + public String substituteInto(String input) { + // a la Perl, $0 is whole thing, $1 - $9 are subexpressions + StringBuffer output = new StringBuffer(); + int pos; + for (pos = 0; pos < input.length()-1; pos++) { + if ((input.charAt(pos) == '$') && (Character.isDigit(input.charAt(pos+1)))) { + int val = Character.digit(input.charAt(++pos),10); + if (val < start.length) { + output.append(toString(val)); + } + } else output.append(input.charAt(pos)); + } + if (pos < input.length()) output.append(input.charAt(pos)); + return output.toString(); + } +} diff --git a/libjava/gnu/regexp/REMatchEnumeration.java b/libjava/gnu/regexp/REMatchEnumeration.java new file mode 100644 index 00000000000..c8e208a9438 --- /dev/null +++ b/libjava/gnu/regexp/REMatchEnumeration.java @@ -0,0 +1,135 @@ +/* gnu/regexp/REMatchEnumeration.java + Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.regexp; +import java.io.Serializable; +import java.util.Enumeration; +import java.util.NoSuchElementException; + +/** + * An REMatchEnumeration enumerates regular expression matches over a + * given input text. You obtain a reference to an enumeration using + * the <code>getMatchEnumeration()</code> methods on an instance of + * RE. + * + * <P> + * + * REMatchEnumeration does lazy computation; that is, it will not + * search for a match until it needs to. If you'd rather just get all + * the matches at once in a big array, use the + * <code>getAllMatches()</code> methods on RE. However, using an + * enumeration can help speed performance when the entire text does + * not need to be searched immediately. + * + * <P> + * + * The enumerated type is especially useful when searching on a Reader + * or InputStream, because the InputStream read position cannot be + * guaranteed after calling <code>getMatch()</code> (see the + * description of that method for an explanation of why). Enumeration + * also saves a lot of overhead required when calling + * <code>getMatch()</code> multiple times. + * + * @author <A HREF="mailto:wes@cacas.org">Wes Biggs</A> + */ +public class REMatchEnumeration implements Enumeration, Serializable { + private static final int YES = 1; + private static final int MAYBE = 0; + private static final int NO = -1; + + private int more; + private REMatch match; + private RE expr; + private CharIndexed input; + private int eflags; + private int index; + + // Package scope constructor is used by RE.getMatchEnumeration() + REMatchEnumeration(RE expr, CharIndexed input, int index, int eflags) { + more = MAYBE; + this.expr = expr; + this.input = input; + this.index = index; + this.eflags = eflags; + } + + /** Returns true if there are more matches in the input text. */ + public boolean hasMoreElements() { + return hasMoreMatches(null); + } + + /** Returns true if there are more matches in the input text. */ + public boolean hasMoreMatches() { + return hasMoreMatches(null); + } + + /** Returns true if there are more matches in the input text. + * Saves the text leading up to the match (or to the end of the input) + * in the specified buffer. + */ + public boolean hasMoreMatches(StringBuffer buffer) { + if (more == MAYBE) { + match = expr.getMatchImpl(input,index,eflags,buffer); + if (match != null) { + input.move((match.end[0] > 0) ? match.end[0] : 1); + + index = (match.end[0] > 0) ? match.end[0] + match.offset : index + 1; + more = YES; + } else more = NO; + } + return (more == YES); + } + + /** Returns the next match in the input text. */ + public Object nextElement() throws NoSuchElementException { + return nextMatch(); + } + + /** + * Returns the next match in the input text. This method is provided + * for convenience to avoid having to explicitly cast the return value + * to class REMatch. + */ + public REMatch nextMatch() throws NoSuchElementException { + if (hasMoreElements()) { + more = (input.isValid()) ? MAYBE : NO; + return match; + } + throw new NoSuchElementException(); + } +} + diff --git a/libjava/gnu/regexp/RESyntax.java b/libjava/gnu/regexp/RESyntax.java new file mode 100644 index 00000000000..649bd0df584 --- /dev/null +++ b/libjava/gnu/regexp/RESyntax.java @@ -0,0 +1,521 @@ +/* gnu/regexp/RESyntax.java + Copyright (C) 1998-2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.regexp; +import java.io.Serializable; +import java.util.BitSet; + +/** + * An RESyntax specifies the way a regular expression will be compiled. + * This class provides a number of predefined useful constants for + * emulating popular regular expression syntaxes. Additionally the + * user may construct his or her own syntax, using any combination of the + * syntax bit constants. The syntax is an optional argument to any of the + * matching methods on class RE. + * + * @author <A HREF="mailto:wes@cacas.org">Wes Biggs</A> + */ + +public final class RESyntax implements Serializable { + static final String DEFAULT_LINE_SEPARATOR = System.getProperty("line.separator"); + + private static final String SYNTAX_IS_FINAL = RE.getLocalizedMessage("syntax.final"); + + private BitSet bits; + + // true for the constant defined syntaxes + private boolean isFinal = false; + + private String lineSeparator = DEFAULT_LINE_SEPARATOR; + + // Values for constants are bit indexes + + /** + * Syntax bit. Backslash is an escape character in lists. + */ + public static final int RE_BACKSLASH_ESCAPE_IN_LISTS = 0; + + /** + * Syntax bit. Use \? instead of ? and \+ instead of +. + */ + public static final int RE_BK_PLUS_QM = 1; + + /** + * Syntax bit. POSIX character classes ([:...:]) in lists are allowed. + */ + public static final int RE_CHAR_CLASSES = 2; + + /** + * Syntax bit. ^ and $ are special everywhere. + * <B>Not implemented.</B> + */ + public static final int RE_CONTEXT_INDEP_ANCHORS = 3; + + /** + * Syntax bit. Repetition operators are only special in valid positions. + * <B>Not implemented.</B> + */ + public static final int RE_CONTEXT_INDEP_OPS = 4; + + /** + * Syntax bit. Repetition and alternation operators are invalid + * at start and end of pattern and other places. + * <B>Not implemented</B>. + */ + public static final int RE_CONTEXT_INVALID_OPS = 5; + + /** + * Syntax bit. Match-any-character operator (.) matches a newline. + */ + public static final int RE_DOT_NEWLINE = 6; + + /** + * Syntax bit. Match-any-character operator (.) does not match a null. + */ + public static final int RE_DOT_NOT_NULL = 7; + + /** + * Syntax bit. Intervals ({x}, {x,}, {x,y}) are allowed. + */ + public static final int RE_INTERVALS = 8; + + /** + * Syntax bit. No alternation (|), match one-or-more (+), or + * match zero-or-one (?) operators. + */ + public static final int RE_LIMITED_OPS = 9; + + /** + * Syntax bit. Newline is an alternation operator. + */ + public static final int RE_NEWLINE_ALT = 10; // impl. + + /** + * Syntax bit. Intervals use { } instead of \{ \} + */ + public static final int RE_NO_BK_BRACES = 11; + + /** + * Syntax bit. Grouping uses ( ) instead of \( \). + */ + public static final int RE_NO_BK_PARENS = 12; + + /** + * Syntax bit. Backreferences not allowed. + */ + public static final int RE_NO_BK_REFS = 13; + + /** + * Syntax bit. Alternation uses | instead of \| + */ + public static final int RE_NO_BK_VBAR = 14; + + /** + * Syntax bit. <B>Not implemented</B>. + */ + public static final int RE_NO_EMPTY_RANGES = 15; + + /** + * Syntax bit. An unmatched right parenthesis (')' or '\)', depending + * on RE_NO_BK_PARENS) will throw an exception when compiling. + */ + public static final int RE_UNMATCHED_RIGHT_PAREN_ORD = 16; + + /** + * Syntax bit. <B>Not implemented.</B> + */ + public static final int RE_HAT_LISTS_NOT_NEWLINE = 17; + + /** + * Syntax bit. Stingy matching is allowed (+?, *?, ??, {x,y}?). + */ + public static final int RE_STINGY_OPS = 18; + + /** + * Syntax bit. Allow character class escapes (\d, \D, \s, \S, \w, \W). + */ + public static final int RE_CHAR_CLASS_ESCAPES = 19; + + /** + * Syntax bit. Allow use of (?:xxx) grouping (subexpression is not saved). + */ + public static final int RE_PURE_GROUPING = 20; + + /** + * Syntax bit. Allow use of (?=xxx) and (?!xxx) apply the subexpression + * to the text following the current position without consuming that text. + */ + public static final int RE_LOOKAHEAD = 21; + + /** + * Syntax bit. Allow beginning- and end-of-string anchors (\A, \Z). + */ + public static final int RE_STRING_ANCHORS = 22; + + /** + * Syntax bit. Allow embedded comments, (?#comment), as in Perl5. + */ + public static final int RE_COMMENTS = 23; + + /** + * Syntax bit. Allow character class escapes within lists, as in Perl5. + */ + public static final int RE_CHAR_CLASS_ESC_IN_LISTS = 24; + + private static final int BIT_TOTAL = 25; + + /** + * Predefined syntax. + * Emulates regular expression support in the awk utility. + */ + public static final RESyntax RE_SYNTAX_AWK; + + /** + * Predefined syntax. + * Emulates regular expression support in the ed utility. + */ + public static final RESyntax RE_SYNTAX_ED; + + /** + * Predefined syntax. + * Emulates regular expression support in the egrep utility. + */ + public static final RESyntax RE_SYNTAX_EGREP; + + /** + * Predefined syntax. + * Emulates regular expression support in the GNU Emacs editor. + */ + public static final RESyntax RE_SYNTAX_EMACS; + + /** + * Predefined syntax. + * Emulates regular expression support in the grep utility. + */ + public static final RESyntax RE_SYNTAX_GREP; + + /** + * Predefined syntax. + * Emulates regular expression support in the POSIX awk specification. + */ + public static final RESyntax RE_SYNTAX_POSIX_AWK; + + /** + * Predefined syntax. + * Emulates POSIX basic regular expression support. + */ + public static final RESyntax RE_SYNTAX_POSIX_BASIC; + + /** + * Predefined syntax. + * Emulates regular expression support in the POSIX egrep specification. + */ + public static final RESyntax RE_SYNTAX_POSIX_EGREP; + + /** + * Predefined syntax. + * Emulates POSIX extended regular expression support. + */ + public static final RESyntax RE_SYNTAX_POSIX_EXTENDED; + + /** + * Predefined syntax. + * Emulates POSIX basic minimal regular expressions. + */ + public static final RESyntax RE_SYNTAX_POSIX_MINIMAL_BASIC; + + /** + * Predefined syntax. + * Emulates POSIX extended minimal regular expressions. + */ + public static final RESyntax RE_SYNTAX_POSIX_MINIMAL_EXTENDED; + + /** + * Predefined syntax. + * Emulates regular expression support in the sed utility. + */ + public static final RESyntax RE_SYNTAX_SED; + + /** + * Predefined syntax. + * Emulates regular expression support in Larry Wall's perl, version 4, + */ + public static final RESyntax RE_SYNTAX_PERL4; + + /** + * Predefined syntax. + * Emulates regular expression support in Larry Wall's perl, version 4, + * using single line mode (/s modifier). + */ + public static final RESyntax RE_SYNTAX_PERL4_S; // single line mode (/s) + + /** + * Predefined syntax. + * Emulates regular expression support in Larry Wall's perl, version 5. + */ + public static final RESyntax RE_SYNTAX_PERL5; + + /** + * Predefined syntax. + * Emulates regular expression support in Larry Wall's perl, version 5, + * using single line mode (/s modifier). + */ + public static final RESyntax RE_SYNTAX_PERL5_S; + + /** + * Predefined syntax. + * Emulates regular expression support in Java 1.4's java.util.regex + * package. + */ + public static final RESyntax RE_SYNTAX_JAVA_1_4; + + static { + // Define syntaxes + + RE_SYNTAX_EMACS = new RESyntax().makeFinal(); + + RESyntax RE_SYNTAX_POSIX_COMMON = new RESyntax() + .set(RE_CHAR_CLASSES) + .set(RE_DOT_NEWLINE) + .set(RE_DOT_NOT_NULL) + .set(RE_INTERVALS) + .set(RE_NO_EMPTY_RANGES) + .makeFinal(); + + RE_SYNTAX_POSIX_BASIC = new RESyntax(RE_SYNTAX_POSIX_COMMON) + .set(RE_BK_PLUS_QM) + .makeFinal(); + + RE_SYNTAX_POSIX_EXTENDED = new RESyntax(RE_SYNTAX_POSIX_COMMON) + .set(RE_CONTEXT_INDEP_ANCHORS) + .set(RE_CONTEXT_INDEP_OPS) + .set(RE_NO_BK_BRACES) + .set(RE_NO_BK_PARENS) + .set(RE_NO_BK_VBAR) + .set(RE_UNMATCHED_RIGHT_PAREN_ORD) + .makeFinal(); + + RE_SYNTAX_AWK = new RESyntax() + .set(RE_BACKSLASH_ESCAPE_IN_LISTS) + .set(RE_DOT_NOT_NULL) + .set(RE_NO_BK_PARENS) + .set(RE_NO_BK_REFS) + .set(RE_NO_BK_VBAR) + .set(RE_NO_EMPTY_RANGES) + .set(RE_UNMATCHED_RIGHT_PAREN_ORD) + .makeFinal(); + + RE_SYNTAX_POSIX_AWK = new RESyntax(RE_SYNTAX_POSIX_EXTENDED) + .set(RE_BACKSLASH_ESCAPE_IN_LISTS) + .makeFinal(); + + RE_SYNTAX_GREP = new RESyntax() + .set(RE_BK_PLUS_QM) + .set(RE_CHAR_CLASSES) + .set(RE_HAT_LISTS_NOT_NEWLINE) + .set(RE_INTERVALS) + .set(RE_NEWLINE_ALT) + .makeFinal(); + + RE_SYNTAX_EGREP = new RESyntax() + .set(RE_CHAR_CLASSES) + .set(RE_CONTEXT_INDEP_ANCHORS) + .set(RE_CONTEXT_INDEP_OPS) + .set(RE_HAT_LISTS_NOT_NEWLINE) + .set(RE_NEWLINE_ALT) + .set(RE_NO_BK_PARENS) + .set(RE_NO_BK_VBAR) + .makeFinal(); + + RE_SYNTAX_POSIX_EGREP = new RESyntax(RE_SYNTAX_EGREP) + .set(RE_INTERVALS) + .set(RE_NO_BK_BRACES) + .makeFinal(); + + /* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */ + + RE_SYNTAX_ED = new RESyntax(RE_SYNTAX_POSIX_BASIC) + .makeFinal(); + + RE_SYNTAX_SED = new RESyntax(RE_SYNTAX_POSIX_BASIC) + .makeFinal(); + + RE_SYNTAX_POSIX_MINIMAL_BASIC = new RESyntax(RE_SYNTAX_POSIX_COMMON) + .set(RE_LIMITED_OPS) + .makeFinal(); + + /* Differs from RE_SYNTAX_POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS + replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */ + + RE_SYNTAX_POSIX_MINIMAL_EXTENDED = new RESyntax(RE_SYNTAX_POSIX_COMMON) + .set(RE_CONTEXT_INDEP_ANCHORS) + .set(RE_CONTEXT_INVALID_OPS) + .set(RE_NO_BK_BRACES) + .set(RE_NO_BK_PARENS) + .set(RE_NO_BK_REFS) + .set(RE_NO_BK_VBAR) + .set(RE_UNMATCHED_RIGHT_PAREN_ORD) + .makeFinal(); + + /* There is no official Perl spec, but here's a "best guess" */ + + RE_SYNTAX_PERL4 = new RESyntax() + .set(RE_BACKSLASH_ESCAPE_IN_LISTS) + .set(RE_CONTEXT_INDEP_ANCHORS) + .set(RE_CONTEXT_INDEP_OPS) // except for '{', apparently + .set(RE_INTERVALS) + .set(RE_NO_BK_BRACES) + .set(RE_NO_BK_PARENS) + .set(RE_NO_BK_VBAR) + .set(RE_NO_EMPTY_RANGES) + .set(RE_CHAR_CLASS_ESCAPES) // \d,\D,\w,\W,\s,\S + .makeFinal(); + + RE_SYNTAX_PERL4_S = new RESyntax(RE_SYNTAX_PERL4) + .set(RE_DOT_NEWLINE) + .makeFinal(); + + RE_SYNTAX_PERL5 = new RESyntax(RE_SYNTAX_PERL4) + .set(RE_PURE_GROUPING) // (?:) + .set(RE_STINGY_OPS) // *?,??,+?,{}? + .set(RE_LOOKAHEAD) // (?=)(?!) + .set(RE_STRING_ANCHORS) // \A,\Z + .set(RE_CHAR_CLASS_ESC_IN_LISTS)// \d,\D,\w,\W,\s,\S within [] + .set(RE_COMMENTS) // (?#) + .makeFinal(); + + RE_SYNTAX_PERL5_S = new RESyntax(RE_SYNTAX_PERL5) + .set(RE_DOT_NEWLINE) + .makeFinal(); + + RE_SYNTAX_JAVA_1_4 = new RESyntax(RE_SYNTAX_PERL5) + // XXX + .makeFinal(); + } + + /** + * Construct a new syntax object with all bits turned off. + * This is equivalent to RE_SYNTAX_EMACS. + */ + public RESyntax() { + bits = new BitSet(BIT_TOTAL); + } + + /** + * Called internally when constructing predefined syntaxes + * so their interpretation cannot vary. Conceivably useful + * for your syntaxes as well. Causes IllegalAccessError to + * be thrown if any attempt to modify the syntax is made. + * + * @return this object for convenient chaining + */ + public RESyntax makeFinal() { + isFinal = true; + return this; + } + + /** + * Construct a new syntax object with all bits set the same + * as the other syntax. + */ + public RESyntax(RESyntax other) { + bits = (BitSet) other.bits.clone(); + } + + /** + * Check if a given bit is set in this syntax. + */ + public boolean get(int index) { + return bits.get(index); + } + + /** + * Set a given bit in this syntax. + * + * @param index the constant (RESyntax.RE_xxx) bit to set. + * @return a reference to this object for easy chaining. + */ + public RESyntax set(int index) { + if (isFinal) throw new IllegalAccessError(SYNTAX_IS_FINAL); + bits.set(index); + return this; + } + + /** + * Clear a given bit in this syntax. + * + * @param index the constant (RESyntax.RE_xxx) bit to clear. + * @return a reference to this object for easy chaining. + */ + public RESyntax clear(int index) { + if (isFinal) throw new IllegalAccessError(SYNTAX_IS_FINAL); + bits.clear(index); + return this; + } + + /** + * Changes the line separator string for regular expressions + * created using this RESyntax. The default separator is the + * value returned by the system property "line.separator", which + * should be correct when reading platform-specific files from a + * filesystem. However, many programs may collect input from + * sources where the line separator is differently specified (for + * example, in the applet environment, the text box widget + * interprets line breaks as single-character newlines, + * regardless of the host platform. + * + * Note that setting the line separator to a character or + * characters that have specific meaning within the current syntax + * can cause unexpected chronosynclastic infundibula. + * + * @return this object for convenient chaining + */ + public RESyntax setLineSeparator(String aSeparator) { + if (isFinal) throw new IllegalAccessError(SYNTAX_IS_FINAL); + lineSeparator = aSeparator; + return this; + } + + /** + * Returns the currently active line separator string. The default + * is the platform-dependent system property "line.separator". + */ + public String getLineSeparator() { + return lineSeparator; + } +} diff --git a/libjava/gnu/regexp/REToken.java b/libjava/gnu/regexp/REToken.java new file mode 100644 index 00000000000..aa576a5adde --- /dev/null +++ b/libjava/gnu/regexp/REToken.java @@ -0,0 +1,86 @@ +/* gnu/regexp/REToken.java + Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.regexp; +import java.io.Serializable; + +abstract class REToken implements Serializable { + + protected REToken next = null; + protected REToken uncle = null; + protected int subIndex; + + protected REToken(int subIndex) { + this.subIndex = subIndex; + } + + int getMinimumLength() { + return 0; + } + + void setUncle(REToken anUncle) { + uncle = anUncle; + } + + /** Returns true if the match succeeded, false if it failed. */ + abstract boolean match(CharIndexed input, REMatch mymatch); + + /** Returns true if the rest of the tokens match, false if they fail. */ + protected boolean next(CharIndexed input, REMatch mymatch) { + if (next == null) { + if (uncle == null) { + return true; + } else { + return uncle.match(input, mymatch); + } + } else { + return next.match(input, mymatch); + } + } + + boolean chain(REToken token) { + next = token; + return true; // Token was accepted + } + + abstract void dump(StringBuffer os); + + void dumpAll(StringBuffer os) { + dump(os); + if (next != null) next.dumpAll(os); + } +} diff --git a/libjava/gnu/regexp/RETokenAny.java b/libjava/gnu/regexp/RETokenAny.java new file mode 100644 index 00000000000..42fdd9e284c --- /dev/null +++ b/libjava/gnu/regexp/RETokenAny.java @@ -0,0 +1,73 @@ +/* gnu/regexp/RETokenAny.java + Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.regexp; + +final class RETokenAny extends REToken { + /** True if '.' can match a newline (RE_DOT_NEWLINE) */ + private boolean newline; + + /** True if '.' can't match a null (RE_DOT_NOT_NULL) */ + private boolean matchNull; + + RETokenAny(int subIndex, boolean newline, boolean matchNull) { + super(subIndex); + this.newline = newline; + this.matchNull = matchNull; + } + + int getMinimumLength() { + return 1; + } + + boolean match(CharIndexed input, REMatch mymatch) { + char ch = input.charAt(mymatch.index); + if ((ch == CharIndexed.OUT_OF_BOUNDS) + || (!newline && (ch == '\n')) + || (matchNull && (ch == 0))) { + return false; + } + ++mymatch.index; + return next(input, mymatch); + } + + void dump(StringBuffer os) { + os.append('.'); + } +} + diff --git a/libjava/gnu/regexp/RETokenBackRef.java b/libjava/gnu/regexp/RETokenBackRef.java new file mode 100644 index 00000000000..a811e16a7b3 --- /dev/null +++ b/libjava/gnu/regexp/RETokenBackRef.java @@ -0,0 +1,72 @@ +/* gnu/regexp/RETokenBackRef.java + Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.regexp; + +final class RETokenBackRef extends REToken { + private int num; + private boolean insens; + + RETokenBackRef(int subIndex, int num, boolean insens) { + super(subIndex); + this.num = num; + this.insens = insens; + } + + // should implement getMinimumLength() -- any ideas? + + boolean match(CharIndexed input, REMatch mymatch) { + int b,e; + b = mymatch.start[num]; + e = mymatch.end[num]; + if ((b==-1)||(e==-1)) return false; // this shouldn't happen, but... + for (int i=b; i<e; i++) { + if (input.charAt(mymatch.index+i-b) != input.charAt(i)) { + return false; + } + } + mymatch.index += e-b; + return next(input, mymatch); + } + + void dump(StringBuffer os) { + os.append('\\').append(num); + } +} + + diff --git a/libjava/gnu/regexp/RETokenChar.java b/libjava/gnu/regexp/RETokenChar.java new file mode 100644 index 00000000000..17712e34787 --- /dev/null +++ b/libjava/gnu/regexp/RETokenChar.java @@ -0,0 +1,91 @@ +/* gnu/regexp/RETokenChar.java + Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.regexp; + +final class RETokenChar extends REToken { + private char[] ch; + private boolean insens; + + RETokenChar(int subIndex, char c, boolean ins) { + super(subIndex); + ch = new char [1]; + ch[0] = (insens = ins) ? Character.toLowerCase(c) : c; + } + + int getMinimumLength() { + return ch.length; + } + + boolean match(CharIndexed input, REMatch mymatch) { + int z = ch.length; + char c; + for (int i=0; i<z; i++) { + c = input.charAt(mymatch.index+i); + if (( (insens) ? Character.toLowerCase(c) : c ) != ch[i]) { + return false; + } + } + mymatch.index += z; + + return next(input, mymatch); + } + + // Overrides REToken.chain() to optimize for strings + boolean chain(REToken next) { + if (next instanceof RETokenChar) { + RETokenChar cnext = (RETokenChar) next; + // assume for now that next can only be one character + int newsize = ch.length + cnext.ch.length; + + char[] chTemp = new char [newsize]; + + System.arraycopy(ch,0,chTemp,0,ch.length); + System.arraycopy(cnext.ch,0,chTemp,ch.length,cnext.ch.length); + + ch = chTemp; + return false; + } else return super.chain(next); + } + + void dump(StringBuffer os) { + os.append(ch); + } +} + + diff --git a/libjava/gnu/regexp/RETokenEnd.java b/libjava/gnu/regexp/RETokenEnd.java new file mode 100644 index 00000000000..08e57084da1 --- /dev/null +++ b/libjava/gnu/regexp/RETokenEnd.java @@ -0,0 +1,75 @@ +/* gnu/regexp/RETokenEnd.java + Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.regexp; + +final class RETokenEnd extends REToken { + /** + * Indicates whether this token should match on a line break. + */ + private String newline; + + RETokenEnd(int subIndex,String newline) { + super(subIndex); + this.newline = newline; + } + + boolean match(CharIndexed input, REMatch mymatch) { + char ch = input.charAt(mymatch.index); + if (ch == CharIndexed.OUT_OF_BOUNDS) + return ((mymatch.eflags & RE.REG_NOTEOL)>0) ? + false : next(input, mymatch); + if (newline != null) { + char z; + int i = 0; // position in newline + do { + z = newline.charAt(i); + if (ch != z) return false; + ++i; + ch = input.charAt(mymatch.index + i); + } while (i < newline.length()); + + return next(input, mymatch); + } + return false; + } + + void dump(StringBuffer os) { + os.append('$'); + } +} diff --git a/libjava/gnu/regexp/RETokenEndSub.java b/libjava/gnu/regexp/RETokenEndSub.java new file mode 100644 index 00000000000..913d3f85c05 --- /dev/null +++ b/libjava/gnu/regexp/RETokenEndSub.java @@ -0,0 +1,53 @@ +/* gnu/regexp/RETokenEndSub.java + Copyright (C) 2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.regexp; + +final class RETokenEndSub extends REToken { + RETokenEndSub(int subIndex) { + super(subIndex); + } + + boolean match(CharIndexed input, REMatch mymatch) { + mymatch.end[subIndex] = mymatch.index; + return next(input, mymatch); + } + + void dump(StringBuffer os) { + // handled by RE + } +} diff --git a/libjava/gnu/regexp/RETokenLookAhead.java b/libjava/gnu/regexp/RETokenLookAhead.java new file mode 100644 index 00000000000..74a9bfe2465 --- /dev/null +++ b/libjava/gnu/regexp/RETokenLookAhead.java @@ -0,0 +1,68 @@ +/* + * gnu/regexp/RETokenOneOf.java + * Copyright (C) 1998-2001 Wes Biggs + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +package gnu.regexp; + +/** + * @since gnu.regexp 1.1.3 + * @author Shashank Bapat + */ +final class RETokenLookAhead extends REToken +{ + REToken re; + boolean negative; + + RETokenLookAhead(REToken re, boolean negative) throws REException { + super(0); + this.re = re; + this.negative = negative; + } + + boolean match(CharIndexed input, REMatch mymatch) + { + REMatch trymatch = (REMatch)mymatch.clone(); + REMatch trymatch1 = (REMatch)mymatch.clone(); + REMatch newMatch = null; + if (re.match(input, trymatch)) { + if (negative) return false; + if (next(input, trymatch1)) + newMatch = trymatch1; + } + + if (newMatch != null) { + if (negative) return false; + //else + mymatch.assignFrom(newMatch); + return true; + } + else { // no match + if (negative) + return next(input, mymatch); + //else + return false; + } + } + + void dump(StringBuffer os) { + os.append("(?"); + os.append(negative ? '!' : '='); + re.dumpAll(os); + os.append(')'); + } +} + diff --git a/libjava/gnu/regexp/RETokenOneOf.java b/libjava/gnu/regexp/RETokenOneOf.java new file mode 100644 index 00000000000..7752b25771c --- /dev/null +++ b/libjava/gnu/regexp/RETokenOneOf.java @@ -0,0 +1,130 @@ +/* gnu/regexp/RETokenOneOf.java + Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.regexp; +import java.util.Vector; + +final class RETokenOneOf extends REToken { + private Vector options; + private boolean negative; + + // This constructor is used for convenience when we know the set beforehand, + // e.g. \d --> new RETokenOneOf("0123456789",false, ..) + // \D --> new RETokenOneOf("0123456789",true, ..) + + RETokenOneOf(int subIndex, String optionsStr, boolean negative, boolean insens) { + super(subIndex); + options = new Vector(); + this.negative = negative; + for (int i = 0; i < optionsStr.length(); i++) + options.addElement(new RETokenChar(subIndex,optionsStr.charAt(i),insens)); + } + + RETokenOneOf(int subIndex, Vector options, boolean negative) { + super(subIndex); + this.options = options; + this.negative = negative; + } + + int getMinimumLength() { + int min = Integer.MAX_VALUE; + int x; + for (int i=0; i < options.size(); i++) { + if ((x = ((REToken) options.elementAt(i)).getMinimumLength()) < min) + min = x; + } + return min; + } + + boolean match(CharIndexed input, REMatch mymatch) { + if (negative && (input.charAt(mymatch.index) == CharIndexed.OUT_OF_BOUNDS)) + return false; + + REMatch newMatch = null; + REMatch last = null; + REToken tk; + boolean isMatch; + for (int i=0; i < options.size(); i++) { + tk = (REToken) options.elementAt(i); + REMatch tryMatch = (REMatch) mymatch.clone(); + if (tk.match(input, tryMatch)) { // match was successful + if (negative) return false; + + if (next(input, tryMatch)) { + // Add tryMatch to list of possibilities. + if (last == null) { + newMatch = tryMatch; + last = tryMatch; + } else { + last.next = tryMatch; + last = tryMatch; + } + } // next succeeds + } // is a match + } // try next option + + if (newMatch != null) { + if (negative) { + return false; + } else { + // set contents of mymatch equal to newMatch + + // try each one that matched + mymatch.assignFrom(newMatch); + return true; + } + } else { + if (negative) { + ++mymatch.index; + return next(input, mymatch); + } else { + return false; + } + } + + // index+1 works for [^abc] lists, not for generic lookahead (--> index) + } + + void dump(StringBuffer os) { + os.append(negative ? "[^" : "(?:"); + for (int i = 0; i < options.size(); i++) { + if (!negative && (i > 0)) os.append('|'); + ((REToken) options.elementAt(i)).dumpAll(os); + } + os.append(negative ? ']' : ')'); + } +} diff --git a/libjava/gnu/regexp/RETokenPOSIX.java b/libjava/gnu/regexp/RETokenPOSIX.java new file mode 100644 index 00000000000..00fcf301ad9 --- /dev/null +++ b/libjava/gnu/regexp/RETokenPOSIX.java @@ -0,0 +1,144 @@ +/* gnu/regexp/RETokenPOSIX.java + Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.regexp; + +final class RETokenPOSIX extends REToken { + int type; + boolean insens; + boolean negated; + + static final int ALNUM = 0; + static final int ALPHA = 1; + static final int BLANK = 2; + static final int CNTRL = 3; + static final int DIGIT = 4; + static final int GRAPH = 5; + static final int LOWER = 6; + static final int PRINT = 7; + static final int PUNCT = 8; + static final int SPACE = 9; + static final int UPPER = 10; + static final int XDIGIT = 11; + + // Array indices correspond to constants defined above. + static final String[] s_nameTable = { + "alnum", "alpha", "blank", "cntrl", "digit", "graph", "lower", + "print", "punct", "space", "upper", "xdigit" + }; + + // The RE constructor uses this to look up the constant for a string + static int intValue(String key) { + for (int i = 0; i < s_nameTable.length; i++) { + if (s_nameTable[i].equals(key)) return i; + } + return -1; + } + + RETokenPOSIX(int subIndex, int type, boolean insens, boolean negated) { + super(subIndex); + this.type = type; + this.insens = insens; + this.negated = negated; + } + + int getMinimumLength() { + return 1; + } + + boolean match(CharIndexed input, REMatch mymatch) { + char ch = input.charAt(mymatch.index); + if (ch == CharIndexed.OUT_OF_BOUNDS) + return false; + + boolean retval = false; + switch (type) { + case ALNUM: + // Note that there is some debate over whether '_' should be included + retval = Character.isLetterOrDigit(ch) || (ch == '_'); + break; + case ALPHA: + retval = Character.isLetter(ch); + break; + case BLANK: + retval = ((ch == ' ') || (ch == '\t')); + break; + case CNTRL: + retval = Character.isISOControl(ch); + break; + case DIGIT: + retval = Character.isDigit(ch); + break; + case GRAPH: + retval = (!(Character.isWhitespace(ch) || Character.isISOControl(ch))); + break; + case LOWER: + retval = ((insens && Character.isLetter(ch)) || Character.isLowerCase(ch)); + break; + case PRINT: + retval = (!(Character.isWhitespace(ch) || Character.isISOControl(ch))) + || (ch == ' '); + break; + case PUNCT: + // This feels sloppy, especially for non-U.S. locales. + retval = ("`~!@#$%^&*()-_=+[]{}\\|;:'\"/?,.<>".indexOf(ch)!=-1); + break; + case SPACE: + retval = Character.isWhitespace(ch); + break; + case UPPER: + retval = ((insens && Character.isLetter(ch)) || Character.isUpperCase(ch)); + break; + case XDIGIT: + retval = (Character.isDigit(ch) || ("abcdefABCDEF".indexOf(ch)!=-1)); + break; + } + + if (negated) retval = !retval; + if (retval) { + ++mymatch.index; + return next(input, mymatch); + } + else return false; + } + + void dump(StringBuffer os) { + if (negated) os.append('^'); + os.append("[:" + s_nameTable[type] + ":]"); + } +} diff --git a/libjava/gnu/regexp/RETokenRange.java b/libjava/gnu/regexp/RETokenRange.java new file mode 100644 index 00000000000..9ce3be926b9 --- /dev/null +++ b/libjava/gnu/regexp/RETokenRange.java @@ -0,0 +1,69 @@ +/* gnu/regexp/RETokenRange.java + Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.regexp; + +final class RETokenRange extends REToken { + private char lo, hi; + private boolean insens; + + RETokenRange(int subIndex, char lo, char hi, boolean ins) { + super(subIndex); + this.lo = (insens = ins) ? Character.toLowerCase(lo) : lo; + this.hi = ins ? Character.toLowerCase(hi) : hi; + } + + int getMinimumLength() { + return 1; + } + + boolean match(CharIndexed input, REMatch mymatch) { + char c = input.charAt(mymatch.index); + if (c == CharIndexed.OUT_OF_BOUNDS) return false; + if (insens) c = Character.toLowerCase(c); + if ((c >= lo) && (c <= hi)) { + ++mymatch.index; + return next(input, mymatch); + } + return false; + } + + void dump(StringBuffer os) { + os.append(lo).append('-').append(hi); + } +} + diff --git a/libjava/gnu/regexp/RETokenRepeated.java b/libjava/gnu/regexp/RETokenRepeated.java new file mode 100644 index 00000000000..8c789271220 --- /dev/null +++ b/libjava/gnu/regexp/RETokenRepeated.java @@ -0,0 +1,227 @@ +/* gnu/regexp/RETokenRepeated.java + Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.regexp; + +import java.util.Vector; + +final class RETokenRepeated extends REToken { + private REToken token; + private int min,max; + private boolean stingy; + + RETokenRepeated(int subIndex, REToken token, int min, int max) { + super(subIndex); + this.token = token; + this.min = min; + this.max = max; + } + + /** Sets the minimal matching mode to true. */ + void makeStingy() { + stingy = true; + } + + /** Queries if this token has minimal matching enabled. */ + boolean isStingy() { + return stingy; + } + + /** + * The minimum length of a repeated token is the minimum length + * of the token multiplied by the minimum number of times it must + * match. + */ + int getMinimumLength() { + return (min * token.getMinimumLength()); + } + + // We do need to save every possible point, but the number of clone() + // invocations here is really a killer for performance on non-stingy + // repeat operators. I'm open to suggestions... + + // Hypothetical question: can you have a RE that matches 1 times, + // 3 times, 5 times, but not 2 times or 4 times? Does having + // the subexpression back-reference operator allow that? + + boolean match(CharIndexed input, REMatch mymatch) { + // number of times we've matched so far + int numRepeats = 0; + + // Possible positions for the next repeat to match at + REMatch newMatch = mymatch; + REMatch last = null; + REMatch current; + + // Add the '0-repeats' index + // positions.elementAt(z) == position [] in input after <<z>> matches + Vector positions = new Vector(); + positions.addElement(newMatch); + + // Declare variables used in loop + REMatch doables; + REMatch doablesLast; + REMatch recurrent; + + do { + // Check for stingy match for each possibility. + if (stingy && (numRepeats >= min)) { + REMatch result = matchRest(input, newMatch); + if (result != null) { + mymatch.assignFrom(result); + return true; + } + } + + doables = null; + doablesLast = null; + + // try next repeat at all possible positions + for (current = newMatch; current != null; current = current.next) { + recurrent = (REMatch) current.clone(); + if (token.match(input, recurrent)) { + // add all items in current to doables array + if (doables == null) { + doables = recurrent; + doablesLast = recurrent; + } else { + // Order these from longest to shortest + // Start by assuming longest (more repeats) + doablesLast.next = recurrent; + } + // Find new doablesLast + while (doablesLast.next != null) { + doablesLast = doablesLast.next; + } + } + } + // if none of the possibilities worked out, break out of do/while + if (doables == null) break; + + // reassign where the next repeat can match + newMatch = doables; + + // increment how many repeats we've successfully found + ++numRepeats; + + positions.addElement(newMatch); + } while (numRepeats < max); + + // If there aren't enough repeats, then fail + if (numRepeats < min) return false; + + // We're greedy, but ease off until a true match is found + int posIndex = positions.size(); + + // At this point we've either got too many or just the right amount. + // See if this numRepeats works with the rest of the regexp. + REMatch allResults = null; + REMatch allResultsLast = null; + + REMatch results = null; + while (--posIndex >= min) { + newMatch = (REMatch) positions.elementAt(posIndex); + results = matchRest(input, newMatch); + if (results != null) { + if (allResults == null) { + allResults = results; + allResultsLast = results; + } else { + // Order these from longest to shortest + // Start by assuming longest (more repeats) + allResultsLast.next = results; + } + // Find new doablesLast + while (allResultsLast.next != null) { + allResultsLast = allResultsLast.next; + } + } + // else did not match rest of the tokens, try again on smaller sample + } + if (allResults != null) { + mymatch.assignFrom(allResults); // does this get all? + return true; + } + // If we fall out, no matches. + return false; + } + + private REMatch matchRest(CharIndexed input, final REMatch newMatch) { + REMatch current, single; + REMatch doneIndex = null; + REMatch doneIndexLast = null; + // Test all possible matches for this number of repeats + for (current = newMatch; current != null; current = current.next) { + // clone() separates a single match from the chain + single = (REMatch) current.clone(); + if (next(input, single)) { + // chain results to doneIndex + if (doneIndex == null) { + doneIndex = single; + doneIndexLast = single; + } else { + doneIndexLast.next = single; + } + // Find new doneIndexLast + while (doneIndexLast.next != null) { + doneIndexLast = doneIndexLast.next; + } + } + } + return doneIndex; + } + + void dump(StringBuffer os) { + os.append("(?:"); + token.dumpAll(os); + os.append(')'); + if ((max == Integer.MAX_VALUE) && (min <= 1)) + os.append( (min == 0) ? '*' : '+' ); + else if ((min == 0) && (max == 1)) + os.append('?'); + else { + os.append('{').append(min); + if (max > min) { + os.append(','); + if (max != Integer.MAX_VALUE) os.append(max); + } + os.append('}'); + } + if (stingy) os.append('?'); + } +} diff --git a/libjava/gnu/regexp/RETokenStart.java b/libjava/gnu/regexp/RETokenStart.java new file mode 100644 index 00000000000..8adb8c89ce2 --- /dev/null +++ b/libjava/gnu/regexp/RETokenStart.java @@ -0,0 +1,87 @@ +/* gnu/regexp/RETokenStart.java + Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.regexp; + +class RETokenStart extends REToken { + private String newline; // matches after a newline + + RETokenStart(int subIndex, String newline) { + super(subIndex); + this.newline = newline; + } + + boolean match(CharIndexed input, REMatch mymatch) { + // charAt(index-n) may be unknown on a Reader/InputStream. FIXME + // Match after a newline if in multiline mode + + if (newline != null) { + int len = newline.length(); + if (mymatch.offset >= len) { + boolean found = true; + char z; + int i = 0; // position in REToken.newline + char ch = input.charAt(mymatch.index - len); + do { + z = newline.charAt(i); + if (ch != z) { + found = false; + break; + } + ++i; + ch = input.charAt(mymatch.index - len + i); + } while (i < len); + + if (found) return next(input, mymatch); + } + } + + // Don't match at all if REG_NOTBOL is set. + if ((mymatch.eflags & RE.REG_NOTBOL) > 0) return false; + + if ((mymatch.eflags & RE.REG_ANCHORINDEX) > 0) + return (mymatch.anchor == mymatch.offset) ? + next(input, mymatch) : false; + else + return ((mymatch.index == 0) && (mymatch.offset == 0)) ? + next(input, mymatch) : false; + } + + void dump(StringBuffer os) { + os.append('^'); + } +} diff --git a/libjava/gnu/regexp/RETokenWordBoundary.java b/libjava/gnu/regexp/RETokenWordBoundary.java new file mode 100644 index 00000000000..38baaec13d5 --- /dev/null +++ b/libjava/gnu/regexp/RETokenWordBoundary.java @@ -0,0 +1,104 @@ +/* gnu/regexp/RETokenWordBoundary.java + Copyright (C) 2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.regexp; + +/** + * Represents a combination lookahead/lookbehind for POSIX [:alnum:]. + */ +final class RETokenWordBoundary extends REToken { + private boolean negated; + private int where; + static final int BEGIN = 1; + static final int END = 2; + + RETokenWordBoundary(int subIndex, int where, boolean negated) { + super(subIndex); + this.where = where; + this.negated = negated; + } + + boolean match(CharIndexed input, REMatch mymatch) { + // Word boundary means input[index-1] was a word character + // and input[index] is not, or input[index] is a word character + // and input[index-1] was not + // In the string "one two three", these positions match: + // |o|n|e| |t|w|o| |t|h|r|e|e| + // ^ ^ ^ ^ ^ ^ + boolean after = false; // is current character a letter or digit? + boolean before = false; // is previous character a letter or digit? + char ch; + + // TODO: Also check REG_ANCHORINDEX vs. anchor + if (((mymatch.eflags & RE.REG_ANCHORINDEX) != RE.REG_ANCHORINDEX) + || (mymatch.offset + mymatch.index > mymatch.anchor)) { + if ((ch = input.charAt(mymatch.index - 1)) != CharIndexed.OUT_OF_BOUNDS) { + before = Character.isLetterOrDigit(ch) || (ch == '_'); + } + } + + if ((ch = input.charAt(mymatch.index)) != CharIndexed.OUT_OF_BOUNDS) { + after = Character.isLetterOrDigit(ch) || (ch == '_'); + } + + // if (before) and (!after), we're at end (\>) + // if (after) and (!before), we're at beginning (\<) + boolean doNext = false; + + if ((where & BEGIN) == BEGIN) { + doNext = after && !before; + } + if ((where & END) == END) { + doNext ^= before && !after; + } + + if (negated) doNext = !doNext; + + return (doNext ? next(input, mymatch) : false); + } + + void dump(StringBuffer os) { + if (where == (BEGIN | END)) { + os.append( negated ? "\\B" : "\\b" ); + } else if (where == BEGIN) { + os.append("\\<"); + } else { + os.append("\\>"); + } + } +} diff --git a/libjava/gnu/regexp/UncheckedRE.java b/libjava/gnu/regexp/UncheckedRE.java new file mode 100644 index 00000000000..660466eabbb --- /dev/null +++ b/libjava/gnu/regexp/UncheckedRE.java @@ -0,0 +1,109 @@ +/* gnu/regexp/UncheckedRE.java + Copyright (C) 2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.regexp; + +/** + * UncheckedRE is a subclass of RE that allows programmers an easier means + * of programmatically precompiling regular expressions. It is constructed + * and used in exactly the same manner as an instance of the RE class; the + * only difference is that its constructors do not throw REException. + * Instead, if a syntax error is encountered during construction, a + * RuntimeException will be thrown. + * <P> + * Note that this makes UncheckedRE dangerous if constructed with + * dynamic data. Do not use UncheckedRE unless you are completely sure + * that all input being passed to it contains valid, well-formed + * regular expressions for the syntax specified. + * + * @author <A HREF="mailto:wes@cacas.org">Wes Biggs</A> + * @see gnu.regexp.RE + * @since gnu.regexp 1.1.4 + */ + +public final class UncheckedRE extends RE { + /** + * Constructs a regular expression pattern buffer without any compilation + * flags set, and using the default syntax (RESyntax.RE_SYNTAX_PERL5). + * + * @param pattern A regular expression pattern, in the form of a String, + * StringBuffer or char[]. Other input types will be converted to + * strings using the toString() method. + * @exception RuntimeException The input pattern could not be parsed. + * @exception NullPointerException The pattern was null. + */ + public UncheckedRE(Object pattern) { + this(pattern,0,RESyntax.RE_SYNTAX_PERL5); + } + + /** + * Constructs a regular expression pattern buffer using the specified + * compilation flags and the default syntax (RESyntax.RE_SYNTAX_PERL5). + * + * @param pattern A regular expression pattern, in the form of a String, + * StringBuffer, or char[]. Other input types will be converted to + * strings using the toString() method. + * @param cflags The logical OR of any combination of the compilation flags in the RE class. + * @exception RuntimeException The input pattern could not be parsed. + * @exception NullPointerException The pattern was null. + */ + public UncheckedRE(Object pattern, int cflags) { + this(pattern,cflags,RESyntax.RE_SYNTAX_PERL5); + } + + /** + * Constructs a regular expression pattern buffer using the specified + * compilation flags and regular expression syntax. + * + * @param pattern A regular expression pattern, in the form of a String, + * StringBuffer, or char[]. Other input types will be converted to + * strings using the toString() method. + * @param cflags The logical OR of any combination of the compilation flags in the RE class. + * @param syntax The type of regular expression syntax to use. + * @exception RuntimeException The input pattern could not be parsed. + * @exception NullPointerException The pattern was null. + */ + public UncheckedRE(Object pattern, int cflags, RESyntax syntax) { + try { + initialize(pattern,cflags,syntax,0,0); + } catch (REException e) { + throw new RuntimeException(e.getMessage()); + } + } +} + + diff --git a/libjava/javax/swing/plaf/basic/BasicProgressBarUI.java b/libjava/javax/swing/plaf/basic/BasicProgressBarUI.java new file mode 100644 index 00000000000..bf5cd0a7aa9 --- /dev/null +++ b/libjava/javax/swing/plaf/basic/BasicProgressBarUI.java @@ -0,0 +1,820 @@ +/* BasicProgressBarUI.java + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import javax.swing.JComponent; +import javax.swing.JProgressBar; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.Timer; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.ProgressBarUI; + + +/** + * The Basic Look and Feel UI delegate for the + * JProgressBar. + */ +public class BasicProgressBarUI extends ProgressBarUI +{ + /** + * A helper class that listens for ChangeEvents + * from the progressBar's model. + */ + protected class ChangeHandler implements ChangeListener + { + /** + * Called every time the state of the model changes. + * + * @param e The ChangeEvent given by the model. + */ + public void stateChanged(ChangeEvent e) + { + // Nothing to do but repaint. + progressBar.repaint(); + } + } + + /** + * This helper class is used to listen for + * PropertyChangeEvents from the progressBar. + */ + private class PropertyChangeHandler implements PropertyChangeListener + { + /** + * Called every time the properties of the + * progressBar change. + * + * @param e The PropertyChangeEvent given by the progressBar. + */ + public void propertyChange(PropertyChangeEvent e) + { + // Only need to listen for indeterminate changes. + // All other things are done on a repaint. + if (e.getPropertyName().equals(JProgressBar.INDETERMINATE_CHANGED_PROPERTY)) + if (((Boolean) e.getNewValue()).booleanValue()) + startAnimationTimer(); + else + stopAnimationTimer(); + else + progressBar.repaint(); + } + } + + /** + * This helper class is used to listen for + * the animationTimer's intervals. On every interval, + * the bouncing box should move. + */ + private class Animator implements ActionListener + { + /** + * Called every time the animationTimer reaches + * its interval. + * + * @param e The ActionEvent given by the timer. + */ + public void actionPerformed(ActionEvent e) + { + // Incrementing the animation index will cause + // a repaint. + incrementAnimationIndex(); + } + } + + /** The timer used to move the bouncing box. */ + private transient Timer animationTimer = new Timer(); + + + // The total number of frames must be an even number. + // The total number of frames is calculated from + // the cycleTime and repaintInterval given by + // the basic L&F's defaults. + // + // +-----------------------------------------------+ + // | frame0 | frame1 | frame2 | frame 3 | frame 4 | + // | | frame7 | frame6 | frame 5 | | + // +-----------------------------------------------+ + + /** The current animation index. */ + private transient int animationIndex; + + /** The total number of frames.*/ + private transient int numFrames; + + /** The helper that moves the bouncing box. */ + private transient Animator animation; + + /** The helper that listens for property change events. */ + private transient PropertyChangeHandler propertyListener; + + /** The Listener for the model. */ + protected ChangeListener changeListener; + + /** The progressBar for this UI. */ + protected JProgressBar progressBar; + + /** The length of the cell. The cell is the painted part. */ + private transient int cellLength; + + /** The gap between cells. */ + private transient int cellSpacing; + + /** The color of the text when the bar is not over it.*/ + private transient Color selectionBackground; + + /** The color of the text when the bar is over it. */ + private transient Color selectionForeground; + + /** + * Creates a new BasicProgressBarUI object. + */ + public BasicProgressBarUI() + { + super(); + } + + /** + * Creates a new BasicProgressBarUI for the component. + * + * @param x The JComponent to create the UI for. + * + * @return A new BasicProgressBarUI. + */ + public static ComponentUI createUI(JComponent x) + { + return new BasicProgressBarUI(); + } + + /** + * This method returns the length of the bar (from the minimum) + * in pixels (or units that the Graphics object draws in) based + * on the progressBar's getPercentComplete() value. + * + * @param b The insets of the progressBar. + * @param width The width of the progressBar. + * @param height The height of the progressBar. + * + * @return The length of the bar that should be painted in pixels. + */ + protected int getAmountFull(Insets b, int width, int height) + { + double percentDone = progressBar.getPercentComplete(); + if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) + return (int) (percentDone * (width - b.left - b.right)); + else + return (int) (percentDone * (height - b.top - b.bottom)); + } + + /** + * The current animation index. + * + * @return The current animation index. + */ + protected int getAnimationIndex() + { + return animationIndex; + } + + /** + * This method returns the size and position of the bouncing box + * for the current animation index. It stores the values in the + * given rectangle and returns it. It returns null if no box should + * be drawn. + * + * @param r The bouncing box rectangle. + * + * @return The bouncing box rectangle. + */ + protected Rectangle getBox(Rectangle r) + { + if (!progressBar.isIndeterminate()) + return null; + //numFrames has to be an even number as defined by spec. + int iterations = numFrames / 2 + 1; + + double boxDependent; + double boxIndependent; + + if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) + { + Dimension dims = getPreferredInnerHorizontal(); + boxDependent = (double) dims.width / iterations; + boxIndependent = dims.height; + } + else + { + Dimension dims = getPreferredInnerVertical(); + boxDependent = (double) dims.height / iterations; + boxIndependent = dims.width; + } + + Rectangle vr = new Rectangle(); + SwingUtilities.calculateInnerArea(progressBar, vr); + + int index = getAnimationIndex(); + if (animationIndex > (numFrames + 1) / 2) + index = numFrames - getAnimationIndex(); + + if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) + { + r.x = vr.x + (int) (index * boxDependent); + r.y = vr.y; + r.width = (int) boxDependent; + r.height = (int) boxIndependent; + } + else + { + index++; + r.x = vr.x; + r.y = vr.height - (int) (index * boxDependent) + vr.y; + r.width = (int) boxIndependent; + r.height = (int) boxDependent; + } + + return r; + } + + /** + * This method returns the length of the cells. + * + * @return The cell length. + */ + protected int getCellLength() + { + return cellLength; + } + + /** + * This method returns the spacing between cells. + * + * @return The cell gap. + */ + protected int getCellSpacing() + { + return cellSpacing; + } + + /** + * This method returns the maximum size of the JComponent. + * If it returns null, it is up to the LayoutManager + * to give it a size. + * + * @param c The component to find a maximum size for. + * + * @return The maximum size. + */ + public Dimension getMaximumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * This method returns the minimum size of the JComponent. + * If it returns null, it is up to the LayoutManager to + * give it a size. + * + * @param c The component to find a minimum size for. + * + * @return The minimum size. + */ + public Dimension getMinimumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * This method returns the preferred size of the inner + * rectangle (the bounds without the insets) if the + * progressBar is horizontal. + * + * @return The preferred size of the progressBar minus + * insets if it's horizontal. + */ + protected Dimension getPreferredInnerHorizontal() + { + Rectangle vr = new Rectangle(); + + SwingUtilities.calculateInnerArea(progressBar, vr); + + return new Dimension(vr.width, vr.height); + } + + /** + * This method returns the preferred size of the inner + * rectangle (the bounds without insets) if the + * progressBar is vertical. + * + * @return The preferred size of the progressBar minus + * insets if it's vertical. + */ + protected Dimension getPreferredInnerVertical() + { + Rectangle vr = new Rectangle(); + + SwingUtilities.calculateInnerArea(progressBar, vr); + + return new Dimension(vr.width, vr.height); + } + + /** + * This method returns the preferred size of the + * given JComponent. If it returns null, then it + * is up to the LayoutManager to give it a size. + * + * @param c The component to find the preferred size for. + * + * @return The preferred size of the component. + */ + public Dimension getPreferredSize(JComponent c) + { + // The only thing we need to worry about is + // the text size. + Graphics g = progressBar.getGraphics(); + + Insets insets = c.getInsets(); + + FontMetrics fm = g.getFontMetrics(c.getFont()); + + int textW = fm.stringWidth(progressBar.getString()); + int textH = fm.getHeight(); + + g.dispose(); + + if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) + { + if (textH < 20) + textH = 20; + if (textW < 200) + textW = 200; + } + else + { + if (textH < 200) + textH = 200; + if (textW < 20) + textW = 20; + } + textW += insets.left + insets.right; + textH += insets.top + insets.bottom; + return new Dimension(textW, textH); + } + + /** + * This method returns the Color that the text is shown in when the bar is + * not over the text. + * + * @return The color of the text when the bar is not over it. + */ + protected Color getSelectionBackground() + { + return selectionBackground; + } + + /** + * This method returns the Color that the text is shown in when the bar is + * over the text. + * + * @return The color of the text when the bar is over it. + */ + protected Color getSelectionForeground() + { + return selectionForeground; + } + + /** + * This method returns the point (the top left of the bounding box) + * where the text should be painted. + * + * @param g The Graphics object to measure FontMetrics with. + * @param progressString The string to paint. + * @param x The x coordinate of the overall bounds box. + * @param y The y coordinate of the overall bounds box. + * @param width The width of the overall bounds box. + * @param height The height of the overall bounds box. + * + * @return The top left of the bounding box where text should be painted. + */ + protected Point getStringPlacement(Graphics g, String progressString, int x, + int y, int width, int height) + { + Rectangle tr = new Rectangle(); + Rectangle vr = new Rectangle(x, y, width, height); + Rectangle ir = new Rectangle(); + + Font f = g.getFont(); + FontMetrics fm = g.getFontMetrics(f); + + SwingUtilities.layoutCompoundLabel(progressBar, fm, progressString, null, + SwingConstants.CENTER, + SwingConstants.CENTER, + SwingConstants.CENTER, + SwingConstants.CENTER, vr, ir, tr, 0); + return new Point(tr.x, tr.y); + } + + /** + * This method increments the animation index. + */ + public void incrementAnimationIndex() + { + animationIndex++; + //numFrames is like string length, it should be named numFrames or something + if (animationIndex >= numFrames) + animationIndex = 0; + progressBar.repaint(); + } + + /** + * This method paints the progressBar. It delegates its responsibilities + * to paintDeterminate and paintIndeterminate. + * + * @param g The Graphics object to paint with. + * @param c The JComponent to paint. + */ + public void paint(Graphics g, JComponent c) + { + if (! progressBar.isIndeterminate()) + paintDeterminate(g, c); + else + paintIndeterminate(g, c); + + if (progressBar.isBorderPainted()) + progressBar.getBorder().paintBorder(progressBar, g, 0, 0, + progressBar.getWidth(), + progressBar.getHeight()); + } + + /** + * This method is called if the painting to be done is + * for a determinate progressBar. + * + * @param g The Graphics object to paint with. + * @param c The JComponent to paint. + */ + protected void paintDeterminate(Graphics g, JComponent c) + { + Color saved = g.getColor(); + int space = getCellSpacing(); + int len = getCellLength(); + int max = progressBar.getMaximum(); + int min = progressBar.getMinimum(); + int value = progressBar.getValue(); + + Rectangle vr = new Rectangle(); + SwingUtilities.calculateInnerArea(c, vr); + + Rectangle or = c.getBounds(); + + Insets insets = c.getInsets(); + + int amountFull = getAmountFull(insets, or.width, or.height); + + g.setColor(c.getBackground()); + g.fill3DRect(vr.x, vr.y, vr.width, vr.height, false); + + if (max != min && len != 0 && value > min) + { + int iterations = value / (space + len); + + if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) + { + double spaceInUnits = space * (double) vr.width / (max - min); + double lenInUnits = len * (double) vr.width / (max - min); + double currX = vr.x; + + g.setColor(c.getForeground()); + g.fill3DRect(vr.x, vr.y, amountFull, vr.height, true); + + g.setColor(c.getBackground()); + if (spaceInUnits != 0) + { + for (int i = 0; i < iterations; i++) + { + currX += lenInUnits; + g.fill3DRect((int) currX, vr.y, (int) spaceInUnits, + vr.height, true); + currX += spaceInUnits; + } + } + } + else + { + double currY = vr.y; + double spaceInUnits = space * (double) vr.height / (max - min); + double lenInUnits = len * (double) vr.height / (max - min); + + g.setColor(c.getForeground()); + g.fill3DRect(vr.x, vr.y + vr.height - amountFull, vr.width, + amountFull, true); + + g.setColor(c.getBackground()); + + if (spaceInUnits != 0) + { + for (int i = 0; i < iterations; i++) + { + currY -= lenInUnits + spaceInUnits; + g.fill3DRect(vr.x, (int) currY, vr.width, + (int) spaceInUnits, true); + } + } + } + } + + if (progressBar.isStringPainted()) + paintString(g, 0, 0, or.width, or.height, amountFull, insets); + g.setColor(saved); + } + + /** + * This method is called if the painting to be done is for + * an indeterminate progressBar. + * + * @param g The Graphics object to paint with. + * @param c The JComponent to paint. + */ + protected void paintIndeterminate(Graphics g, JComponent c) + { + //need to paint the box at it's current position. no text is painted since + //all we're doing is bouncing back and forth + Color saved = g.getColor(); + Insets insets = c.getInsets(); + + Rectangle or = c.getBounds(); + Rectangle vr = new Rectangle(); + SwingUtilities.calculateInnerArea(c, vr); + + g.setColor(c.getBackground()); + g.fill3DRect(vr.x, vr.y, vr.width, vr.height, false); + + Rectangle box = new Rectangle(); + getBox(box); + + g.setColor(c.getForeground()); + g.fill3DRect(box.x, box.y, box.width, box.height, true); + + if (progressBar.isStringPainted()) + paintString(g, 0, 0, or.width, or.height, + getAmountFull(insets, or.width, or.height), insets); + + g.setColor(saved); + } + + /** + * This method paints the string for the progressBar. + * + * @param g The Graphics object to paint with. + * @param x The x coordinate of the progressBar. + * @param y The y coordinate of the progressBar. + * @param width The width of the progressBar. + * @param height The height of the progressBar. + * @param amountFull The amount of the progressBar that has its bar filled. + * @param b The insets of the progressBar. + */ + protected void paintString(Graphics g, int x, int y, int width, int height, + int amountFull, Insets b) + { + // We want to place in the exact center of the bar. + Point placement = getStringPlacement(g, progressBar.getString(), + x + b.left, y + b.top, + width - b.left - b.right, + height - b.top - b.bottom); + Color saved = g.getColor(); + + // FIXME: The Color of the text should use selectionForeground and selectionBackground + // but that can't be done right now, so we'll use white in the mean time. + g.setColor(Color.WHITE); + + FontMetrics fm = g.getFontMetrics(progressBar.getFont()); + + g.drawString(progressBar.getString(), placement.x, + placement.y + fm.getAscent()); + + g.setColor(saved); + } + + /** + * This method sets the current animation index. If the index + * is greater than the number of frames, it resets to 0. + * + * @param newValue The new animation index. + */ + protected void setAnimationIndex(int newValue) + { + animationIndex = (newValue <= numFrames) ? newValue : 0; + progressBar.repaint(); + } + + /** + * This method sets the cell length. + * + * @param cellLen The cell length. + */ + protected void setCellLength(int cellLen) + { + cellLength = cellLen; + } + + /** + * This method sets the cell spacing. + * + * @param cellSpace The cell spacing. + */ + protected void setCellSpacing(int cellSpace) + { + cellSpacing = cellSpace; + } + + /** + * This method starts the animation timer. It is called + * when the propertyChangeListener detects that the progressBar + * has changed to indeterminate mode. + */ + protected void startAnimationTimer() + { + if (animationTimer != null) + animationTimer.start(); + } + + /** + * This method stops the animation timer. It is called when + * the propertyChangeListener detects that the progressBar + * has changed to determinate mode. + */ + protected void stopAnimationTimer() + { + if (animationTimer != null) + animationTimer.stop(); + setAnimationIndex(0); + } + + /** + * This method changes the settings for the progressBar to + * the defaults provided by the current Look and Feel. + */ + protected void installDefaults() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + progressBar.setFont(defaults.getFont("ProgressBar.font")); + progressBar.setForeground(defaults.getColor("ProgressBar.foreground")); + progressBar.setBackground(defaults.getColor("ProgressBar.background")); + progressBar.setBorder(defaults.getBorder("ProgressBar.border")); + + selectionForeground = defaults.getColor("ProgressBar.selectionForeground"); + selectionBackground = defaults.getColor("ProgressBar.selectionBackground"); + cellLength = defaults.getInt("ProgressBar.cellLength"); + cellSpacing = defaults.getInt("ProgressBar.cellSpacing"); + + int repaintInterval = defaults.getInt("ProgressBar.repaintInterval"); + int cycleTime = defaults.getInt("ProgressBar.cycleTime"); + + if (cycleTime % repaintInterval != 0 + && (cycleTime / repaintInterval) % 2 != 0) + { + int div = (cycleTime / repaintInterval) + 2; + div /= 2; + div *= 2; + cycleTime = div * repaintInterval; + } + setAnimationIndex(0); + numFrames = cycleTime / repaintInterval; + animationTimer.setDelay(repaintInterval); + } + + /** + * The method uninstalls any defaults that were + * set by the current Look and Feel. + */ + protected void uninstallDefaults() + { + progressBar.setFont(null); + progressBar.setForeground(null); + progressBar.setBackground(null); + + selectionForeground = null; + selectionBackground = null; + } + + /** + * This method registers listeners to all the + * components that this UI delegate needs to listen to. + */ + protected void installListeners() + { + changeListener = new ChangeHandler(); + propertyListener = new PropertyChangeHandler(); + animation = new Animator(); + + progressBar.addChangeListener(changeListener); + progressBar.addPropertyChangeListener(propertyListener); + animationTimer.addActionListener(animation); + } + + /** + * This method unregisters listeners to all the + * components that were listened to. + */ + protected void uninstallListeners() + { + progressBar.removeChangeListener(changeListener); + progressBar.removePropertyChangeListener(propertyListener); + animationTimer.removeActionListener(animation); + + changeListener = null; + propertyListener = null; + animation = null; + } + + /** + * This method installs the UI for the given JComponent. + * This includes setting up defaults and listeners as + * well as initializing any values or objects that + * the UI may need. + * + * @param c The JComponent that is having this UI installed. + */ + public void installUI(JComponent c) + { + super.installUI(c); + if (c instanceof JProgressBar) + { + progressBar = (JProgressBar) c; + + animationTimer = new Timer(); + animationTimer.setRepeats(true); + + installDefaults(); + installListeners(); + } + } + + /** + * This method removes the UI for the given JComponent. + * This includes removing any listeners or defaults + * that the installUI may have set up. + * + * @param c The JComponent that is having this UI uninstalled. + */ + public void uninstallUI(JComponent c) + { + super.uninstallUI(c); + uninstallListeners(); + uninstallDefaults(); + + animationTimer = null; + progressBar = null; + } +} diff --git a/libjava/javax/swing/plaf/basic/BasicSeparatorUI.java b/libjava/javax/swing/plaf/basic/BasicSeparatorUI.java new file mode 100644 index 00000000000..b7df0acb27d --- /dev/null +++ b/libjava/javax/swing/plaf/basic/BasicSeparatorUI.java @@ -0,0 +1,266 @@ +/* BasicSeparatorUI.java + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf.basic; + +import java.awt.Dimension; +import java.awt.Color; +import java.awt.Rectangle; +import java.awt.Graphics; +import java.awt.Insets; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.SeparatorUI; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.JComponent; +import javax.swing.JSeparator; +import javax.swing.SwingUtilities; + +/** + * The Basic L&F UI delegate for JSeparator. + */ +public class BasicSeparatorUI extends SeparatorUI +{ + /** The shadow color. */ + protected Color shadow; + + /** The highlight color. */ + protected Color highlight; + + /** + * Creates a new UI delegate for the given JComponent. + * + * @param c The JComponent to create a delegate for. + * + * @return A new BasicSeparatorUI. + */ + public static ComponentUI createUI(JComponent c) + { + return new BasicSeparatorUI(); + } + + /** + * This method installs the UI for the given JComponent. + * This can include installing defaults, listeners, and + * initializing any instance data. + * + * @param c The JComponent that is having this UI installed. + */ + public void installUI(JComponent c) + { + super.installUI(c); + + if (c instanceof JSeparator) + { + JSeparator s = (JSeparator) c; + + installDefaults(s); + installListeners(s); + } + } + + /** + * Uninstalls the UI for the given JComponent. This + * method reverses what was done when installing + * the UI on the JComponent. + * + * @param c The JComponent that is having this UI uninstalled. + */ + public void uninstallUI(JComponent c) + { + if (c instanceof JSeparator) + { + JSeparator s = (JSeparator) c; + + uninstallListeners(s); + uninstallDefaults(s); + } + } + + /** + * This method installs the defaults that are given by + * the Basic L&F. + * + * @param s The JSeparator that is being installed. + */ + protected void installDefaults(JSeparator s) + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + shadow = defaults.getColor("Separator.shadow"); + highlight = defaults.getColor("Separator.highlight"); + } + + /** + * This method removes the defaults that were given + * by the Basic L&F. + * + * @param s The JSeparator that is being uninstalled. + */ + protected void uninstallDefaults(JSeparator s) + { + shadow = null; + highlight = null; + } + + /** + * This method installs any listeners that need + * to be attached to the JSeparator or any of its + * components. + * + * @param s The JSeparator that is being installed. + */ + protected void installListeners(JSeparator s) + { + // Separators don't receive events. + } + + /** + * This method uninstalls any listeners that + * were installed during the install UI process. + * + * @param s The JSeparator that is being uninstalled. + */ + protected void uninstallListeners(JSeparator s) + { + // Separators don't receive events. + } + + /** + * The separator is made of two lines. The top line will be + * the highlight color (or left line if it's vertical). The bottom + * or right line will be the shadow color. The two lines will + * be centered inside the bounds box. If the separator is horizontal, + * then it will be vertically centered, or if it's vertical, it will + * be horizontally centered. + * + * @param g The Graphics object to paint with + * @param c The JComponent to paint. + */ + public void paint(Graphics g, JComponent c) + { + Rectangle r = new Rectangle(); + SwingUtilities.calculateInnerArea(c, r); + Color saved = g.getColor(); + + int midAB = r.width / 2 + r.x; + int midAD = r.height / 2 + r.y; + + JSeparator s; + if (c instanceof JSeparator) + s = (JSeparator) c; + else + return; + + if (s.getOrientation() == JSeparator.HORIZONTAL) + { + g.setColor(highlight); + g.drawLine(r.x, midAD, r.x + r.width, midAD); + + g.setColor(shadow); + g.drawLine(r.x, midAD + 1, r.x + r.width, midAD + 1); + } + else + { + g.setColor(highlight); + g.drawLine(midAB, r.y, midAB, r.y + r.height); + + g.setColor(shadow); + g.drawLine(midAB + 1, r.y, midAB + 1, r.y + r.height); + } + } + + /** + * This method returns the preferred size of the + * JComponent. + * + * @param c The JComponent to measure. + * + * @return The preferred size. + */ + public Dimension getPreferredSize(JComponent c) + { + Dimension dims = new Dimension(0, 0); + Insets insets = c.getInsets(); + + if (c instanceof JSeparator) + { + JSeparator s = (JSeparator) c; + + if (s.getOrientation() == JSeparator.HORIZONTAL) + { + dims.height = 2; + dims.width = 40; + } + else + { + dims.width = 2; + dims.height = 40; + } + } + dims.width += insets.left + insets.right; + dims.height += insets.top + insets.bottom; + + return dims; + } + + /** + * This method returns the minimum size of the + * JComponent. + * + * @param c The JComponent to measure. + * + * @return The minimum size. + */ + public Dimension getMinimumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * This method returns the maximum size of the + * JComponent. + * + * @param c The JComponent to measure. + * + * @return The maximum size. + */ + public Dimension getMaximumSize(JComponent c) + { + return getPreferredSize(c); + } +} diff --git a/libjava/javax/swing/plaf/basic/BasicSliderUI.java b/libjava/javax/swing/plaf/basic/BasicSliderUI.java new file mode 100644 index 00000000000..2ee481e317d --- /dev/null +++ b/libjava/javax/swing/plaf/basic/BasicSliderUI.java @@ -0,0 +1,2213 @@ +/* BasicSliderUI.java + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Component; +import java.awt.ComponentOrientation; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.Dictionary; +import java.util.Enumeration; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JSlider; +import javax.swing.KeyStroke; +import javax.swing.SwingUtilities; +import javax.swing.Timer; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.BoundedRangeModel; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.MouseInputAdapter; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.SliderUI; + + +/** + * <p> + * BasicSliderUI.java This is the UI delegate in the Basic look and feel that + * paints JSliders. + * </p> + * + * <p> + * The UI delegate keeps track of 6 rectangles that place the various parts of + * the JSlider inside the component. + * </p> + * + * <p> + * The rectangles are organized as follows: + * </p> + * <pre> + * +-------------------------------------------------------+ <-- focusRect + * | | + * | +==+-------------------+==+--------------------+==+<------ contentRect + * | | | | |<---thumbRect | | | + * | | | TRACK | | |<--------- trackRect + * | | +-------------------+==+--------------------+ | | + * | | | | | | + * | | | TICKS GO HERE |<-------- tickRect + * | | | | | | + * | +==+-------------------------------------------+==+ | + * | | | | | | + * | | | | |<----- labelRect + * | | | LABELS GO HERE | | | + * | | | | | | + * | | | | | | + * | | | | | | + * | | | | | | + * | | | | | + * </pre> + * + * <p> + * The space between the contentRect and the focusRect are the FocusInsets. + * </p> + * + * <p> + * The space between the focusRect and the component bounds is the insetCache + * which are the component's insets. + * </p> + * + * <p> + * The top of the thumb is the top of the contentRect. The trackRect has to be + * as tall as the thumb. + * </p> + * + * <p> + * The trackRect and tickRect do not start from the left edge of the + * focusRect. They are trackBuffer away from each side of the focusRect. This + * is so that the thumb has room to move. + * </p> + * + * <p> + * The labelRect does start right against the contentRect's left and right + * edges and it gets all remaining space. + * </p> + */ +public class BasicSliderUI extends SliderUI +{ + /** + * Helper class that listens to the {@link JSlider}'s model for changes. + */ + protected class ChangeHandler implements ChangeListener + { + /** + * Called when the slider's model has been altered. The UI delegate should + * recalculate any rectangles that are dependent on the model for their + * positions and repaint. + * + * @param e A static {@link ChangeEvent} passed from the model. + */ + public void stateChanged(ChangeEvent e) + { + // Maximum, minimum, and extent values will be taken + // care of automatically when the slider is repainted. + + // Only thing that needs recalculation is the thumb. + calculateThumbLocation(); + slider.repaint(); + } + } + + /** + * Helper class that listens for resize events. + */ + protected class ComponentHandler extends ComponentAdapter + { + /** + * Called when the size of the component changes. The UI delegate should + * recalculate any rectangles that are dependent on the model for their + * positions and repaint. + * + * @param e A {@link ComponentEvent}. + */ + public void componentResized(ComponentEvent e) + { + calculateGeometry(); + + slider.revalidate(); + slider.repaint(); + } + } + + /** + * Helper class that listens for focus events. + */ + protected class FocusHandler implements FocusListener + { + /** + * Called when the {@link JSlider} has gained focus. It should repaint + * the slider with the focus drawn. + * + * @param e A {@link FocusEvent}. + */ + public void focusGained(FocusEvent e) + { + // FIXME: implement. + } + + /** + * Called when the {@link JSlider} has lost focus. It should repaint the + * slider without the focus drawn. + * + * @param e A {@link FocusEvent}. + */ + public void focusLost(FocusEvent e) + { + // FIXME: implement. + } + } + + /** + * Helper class that listens for changes to the properties of the {@link + * JSlider}. + */ + protected class PropertyChangeHandler implements PropertyChangeListener + { + /** + * Called when one of the properties change. The UI should recalculate any + * rectangles if necessary and repaint. + * + * @param e A {@link PropertyChangeEvent}. + */ + public void propertyChange(PropertyChangeEvent e) + { + // Check for orientation changes. + if (e.getPropertyName().equals(JSlider.ORIENTATION_CHANGED_PROPERTY)) + recalculateIfOrientationChanged(); + else if (e.getPropertyName().equals(JSlider.MODEL_CHANGED_PROPERTY)) + { + BoundedRangeModel oldModel = (BoundedRangeModel) e.getOldValue(); + oldModel.removeChangeListener(changeListener); + slider.getModel().addChangeListener(changeListener); + calculateThumbLocation(); + } + // elif the componentOrientation changes (this is a bound property, + // just undocumented) we change leftToRightCache. In Sun's + // implementation, the LTR cache changes on a repaint. This is strange + // since there is no need to do so. We could events here and + // update the cache. + + // elif the border/insets change, we recalculateInsets. + slider.repaint(); + } + } + + /** + * Helper class that listens to our swing timer. This class is responsible + * for listening to the timer and moving the thumb in the proper direction + * every interval. + */ + protected class ScrollListener implements ActionListener + { + /** Indicates which direction the thumb should scroll. */ + private transient int direction; + + /** Indicates whether we should scroll in blocks or in units. */ + private transient boolean block; + + /** + * Creates a new ScrollListener object. + */ + public ScrollListener() + { + direction = POSITIVE_SCROLL; + block = false; + } + + /** + * Creates a new ScrollListener object. + * + * @param dir The direction to scroll in. + * @param block If movement will be in blocks. + */ + public ScrollListener(int dir, boolean block) + { + direction = dir; + this.block = block; + } + + /** + * Called every time the swing timer reaches its interval. If the thumb + * needs to move, then this method will move the thumb one block or unit + * in the direction desired. Otherwise, the timer can be stopped. + * + * @param e An {@link ActionEvent}. + */ + public void actionPerformed(ActionEvent e) + { + if (! trackListener.shouldScroll(direction)) + { + scrollTimer.stop(); + return; + } + + if (block) + scrollByBlock(direction); + else + scrollByUnit(direction); + } + + /** + * Sets the direction to scroll in. + * + * @param direction The direction to scroll in. + */ + public void setDirection(int direction) + { + this.direction = direction; + } + + /** + * Sets whether movement will be in blocks. + * + * @param block If movement will be in blocks. + */ + public void setScrollByBlock(boolean block) + { + this.block = block; + } + } + + /** + * Helper class that listens for mouse events. + */ + protected class TrackListener extends MouseInputAdapter + { + /** The current X position of the mouse. */ + protected int currentMouseX; + + /** The current Y position of the mouse. */ + protected int currentMouseY; + + /** The offset between the current slider value + and the cursor's position. */ + protected int offset; + + /** + * Called when the mouse has been dragged. This should find the mouse's + * current position and adjust the value of the {@link JSlider} + * accordingly. + * + * @param e A {@link MouseEvent} + */ + public void mouseDragged(MouseEvent e) + { + currentMouseX = e.getX(); + currentMouseY = e.getY(); + if (slider.getValueIsAdjusting()) + { + int value; + if (slider.getOrientation() == JSlider.HORIZONTAL) + value = valueForXPosition(currentMouseX) - offset; + else + value = valueForYPosition(currentMouseY) - offset; + + slider.setValue(value); + } + } + + /** + * Called when the mouse has moved over a component but no buttons have + * been pressed yet. + * + * @param e A {@link MouseEvent} + */ + public void mouseMoved(MouseEvent e) + { + // Don't care that we're moved unless we're dragging. + } + + /** + * Called when the mouse is pressed. When the press occurs on the thumb + * itself, the {@link JSlider} should have its value set to where the + * mouse was pressed. If the press occurs on the track, then the thumb + * should move one block towards the direction of the mouse. + * + * @param e A {@link MouseEvent} + */ + public void mousePressed(MouseEvent e) + { + currentMouseX = e.getX(); + currentMouseY = e.getY(); + + int value; + if (slider.getOrientation() == JSlider.HORIZONTAL) + value = valueForXPosition(currentMouseX); + else + value = valueForYPosition(currentMouseY); + + if (slider.getSnapToTicks()) + value = findClosestTick(value); + + if (value == slider.getValue()) + return; + + // If the thumb is hit, then we don't need to set the timers to move it. + if (!thumbRect.contains(e.getPoint())) + { + // The mouse has hit some other part of the slider. + // The value moves no matter where in the slider you hit. + if (value > slider.getValue()) + scrollDueToClickInTrack(POSITIVE_SCROLL); + else + scrollDueToClickInTrack(NEGATIVE_SCROLL); + } + else + { + slider.setValueIsAdjusting(true); + offset = value - slider.getValue(); + } + } + + /** + * Called when the mouse is released. This should stop the timer that + * scrolls the thumb. + * + * @param e A {@link MouseEvent} + */ + public void mouseReleased(MouseEvent e) + { + currentMouseX = e.getX(); + currentMouseY = e.getY(); + + if (slider.getValueIsAdjusting()) + { + slider.setValueIsAdjusting(false); + if (slider.getSnapToTicks()) + slider.setValue(findClosestTick(slider.getValue())); + } + if (scrollTimer != null) + scrollTimer.stop(); + } + + /** + * Indicates whether the thumb should scroll in the given direction. + * + * @param direction The direction to check. + * + * @return True if the thumb should move in that direction. + */ + public boolean shouldScroll(int direction) + { + int value; + if (slider.getOrientation() == JSlider.HORIZONTAL) + value = valueForXPosition(currentMouseX); + else + value = valueForYPosition(currentMouseY); + + if (direction == POSITIVE_SCROLL) + return (value > slider.getValue()); + else + return (value < slider.getValue()); + } + } + + /** The preferred height of the thumb. */ + private transient int thumbHeight; + + /** The preferred width of the thumb. */ + private transient int thumbWidth; + + /** The preferred height of the tick rectangle. */ + private transient int tickHeight; + + /** Listener for changes from the model. */ + protected ChangeListener changeListener; + + /** Listener for changes to the {@link JSlider}. */ + protected PropertyChangeListener propertyChangeListener; + + /** Listener for the scrollTimer. */ + protected ScrollListener scrollListener; + + /** Listener for component resizing. */ + protected ComponentListener componentListener; + + /** Listener for focus handling. */ + protected FocusListener focusListener; + + /** Listener for mouse events. */ + protected TrackListener trackListener; + + /** The insets between the FocusRectangle and the ContentRectangle. */ + protected Insets focusInsets; + + /** The {@link JSlider}'s insets. */ + protected Insets insetCache; + + /** Rectangle describing content bounds. See diagram above. */ + protected Rectangle contentRect; + + /** Rectangle describing focus bounds. See diagram above. */ + protected Rectangle focusRect; + + /** Rectangle describing the thumb's bounds. See diagram above. */ + protected Rectangle thumbRect; + + /** Rectangle describing the tick bounds. See diagram above. */ + protected Rectangle tickRect; + + /** Rectangle describing the label bounds. See diagram above. */ + protected Rectangle labelRect; + + /** Rectangle describing the track bounds. See diagram above. */ + protected Rectangle trackRect; + + /** FIXME: use this somewhere. */ + public static final int MAX_SCROLL = 2; + + /** FIXME: use this somewhere. */ + public static final int MIN_SCROLL = -2; + + /** A constant describing scrolling towards the minimum. */ + public static final int NEGATIVE_SCROLL = -1; + + /** A constant describing scrolling towards the maximum. */ + public static final int POSITIVE_SCROLL = 1; + + /** The gap between the edges of the contentRect and trackRect. */ + protected int trackBuffer; + + /** Whether this slider is actually drawn left to right. */ + protected boolean leftToRightCache; + + /** A timer that periodically moves the thumb. */ + protected Timer scrollTimer; + + /** A reference to the {@link JSlider} that this UI was created for. */ + protected JSlider slider; + + /** The shadow color. */ + private transient Color shadowColor; + + /** The highlight color. */ + private transient Color highlightColor; + + /** The focus color. */ + private transient Color focusColor; + + /** + * Creates a new Basic look and feel Slider UI. + * + * @param b The {@link JSlider} that this UI was created for. + */ + public BasicSliderUI(JSlider b) + { + super(); + } + + /** + * Gets the shadow color to be used for this slider. The shadow color is the + * color used for drawing the top and left edges of the track. + * + * @return The shadow color. + */ + protected Color getShadowColor() + { + return shadowColor; + } + + /** + * Gets the highlight color to be used for this slider. The highlight color + * is the color used for drawing the bottom and right edges of the track. + * + * @return The highlight color. + */ + protected Color getHighlightColor() + { + return highlightColor; + } + + /** + * Gets the focus color to be used for this slider. The focus color is the + * color used for drawing the focus rectangle when the component gains + * focus. + * + * @return The focus color. + */ + protected Color getFocusColor() + { + return focusColor; + } + + /** + * Factory method to create a BasicSliderUI for the given {@link + * JComponent}, which should be a {@link JSlider}. + * + * @param b The {@link JComponent} a UI is being created for. + * + * @return A BasicSliderUI for the {@link JComponent}. + */ + public static ComponentUI createUI(JComponent b) + { + return new BasicSliderUI((JSlider) b); + } + + /** + * Installs and initializes all fields for this UI delegate. Any properties + * of the UI that need to be initialized and/or set to defaults will be + * done now. It will also install any listeners necessary. + * + * @param c The {@link JComponent} that is having this UI installed. + */ + public void installUI(JComponent c) + { + super.installUI(c); + if (c instanceof JSlider) + { + slider = (JSlider) c; + + focusRect = new Rectangle(); + contentRect = new Rectangle(); + thumbRect = new Rectangle(); + trackRect = new Rectangle(); + tickRect = new Rectangle(); + labelRect = new Rectangle(); + + insetCache = slider.getInsets(); + leftToRightCache = ! slider.getInverted(); + + scrollTimer = new Timer(); + scrollTimer.setDelay(200); + scrollTimer.setRepeats(true); + + installDefaults(slider); + installListeners(slider); + installKeyboardActions(slider); + + calculateFocusRect(); + + calculateContentRect(); + calculateThumbSize(); + calculateTrackBuffer(); + calculateTrackRect(); + calculateThumbLocation(); + + calculateTickRect(); + calculateLabelRect(); + } + } + + /** + * Performs the opposite of installUI. Any properties or resources that need + * to be cleaned up will be done now. It will also uninstall any listeners + * it has. In addition, any properties of this UI will be nulled. + * + * @param c The {@link JComponent} that is having this UI uninstalled. + */ + public void uninstallUI(JComponent c) + { + super.uninstallUI(c); + + uninstallKeyboardActions(slider); + uninstallListeners(slider); + + scrollTimer = null; + + focusRect = null; + contentRect = null; + thumbRect = null; + trackRect = null; + tickRect = null; + labelRect = null; + + focusInsets = null; + } + + /** + * Initializes any default properties that this UI has from the defaults for + * the Basic look and feel. + * + * @param slider The {@link JSlider} that is having this UI installed. + */ + protected void installDefaults(JSlider slider) + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + slider.setForeground(defaults.getColor("Slider.foreground")); + slider.setBackground(defaults.getColor("Slider.background")); + shadowColor = defaults.getColor("Slider.shadow"); + highlightColor = defaults.getColor("Slider.highlight"); + focusColor = defaults.getColor("Slider.focus"); + slider.setBorder(defaults.getBorder("Slider.border")); + + thumbHeight = defaults.getInt("Slider.thumbHeight"); + thumbWidth = defaults.getInt("Slider.thumbWidth"); + tickHeight = defaults.getInt("Slider.tickHeight"); + + focusInsets = defaults.getInsets("Slider.focusInsets"); + } + + /** + * Creates a new {@link TrackListener}. + * + * @param slider The {@link JSlider} that this {@link TrackListener} is + * created for. + * + * @return A new {@link TrackListener}. + */ + protected TrackListener createTrackListener(JSlider slider) + { + return new TrackListener(); + } + + /** + * Creates a new {@link ChangeListener}. + * + * @param slider The {@link JSlider} that this {@link ChangeListener} is + * created for. + * + * @return A new {@link ChangeListener}. + */ + protected ChangeListener createChangeListener(JSlider slider) + { + return new ChangeHandler(); + } + + /** + * Creates a new {@link ComponentListener}. + * + * @param slider The {@link JSlider} that this {@link ComponentListener} is + * created for. + * + * @return A new {@link ComponentListener}. + */ + protected ComponentListener createComponentListener(JSlider slider) + { + return new ComponentHandler(); + } + + /** + * Creates a new {@link FocusListener}. + * + * @param slider The {@link JSlider} that this {@link FocusListener} is + * created for. + * + * @return A new {@link FocusListener}. + */ + protected FocusListener createFocusListener(JSlider slider) + { + return new FocusHandler(); + } + + /** + * Creates a new {@link ScrollListener}. + * + * @param slider The {@link JSlider} that this {@link ScrollListener} is + * created for. + * + * @return A new {@link ScrollListener}. + */ + protected ScrollListener createScrollListener(JSlider slider) + { + return new ScrollListener(); + } + + /** + * Creates a new {@link PropertyChangeListener}. + * + * @param slider The {@link JSlider} that this {@link + * PropertyChangeListener} is created for. + * + * @return A new {@link PropertyChangeListener}. + */ + protected PropertyChangeListener createPropertyChangeListener(JSlider slider) + { + return new PropertyChangeHandler(); + } + + /** + * Creates and registers all the listeners for this UI delegate. This + * includes creating the ScrollListener and registering it to the timer. + * + * @param slider The {@link JSlider} is having listeners installed. + */ + protected void installListeners(JSlider slider) + { + propertyChangeListener = createPropertyChangeListener(slider); + componentListener = createComponentListener(slider); + trackListener = createTrackListener(slider); + focusListener = createFocusListener(slider); + changeListener = createChangeListener(slider); + scrollListener = createScrollListener(slider); + + slider.addPropertyChangeListener(propertyChangeListener); + slider.addComponentListener(componentListener); + slider.addMouseListener(trackListener); + slider.addMouseMotionListener(trackListener); + slider.addFocusListener(focusListener); + slider.getModel().addChangeListener(changeListener); + + scrollTimer.addActionListener(scrollListener); + } + + /** + * Unregisters all the listeners that this UI delegate was using. In + * addition, it will also null any listeners that it was using. + * + * @param slider The {@link JSlider} that is having listeners removed. + */ + protected void uninstallListeners(JSlider slider) + { + slider.removePropertyChangeListener(propertyChangeListener); + slider.removeComponentListener(componentListener); + slider.removeMouseListener(trackListener); + slider.removeMouseMotionListener(trackListener); + slider.removeFocusListener(focusListener); + slider.getModel().removeChangeListener(changeListener); + + scrollTimer.removeActionListener(scrollListener); + + propertyChangeListener = null; + componentListener = null; + trackListener = null; + focusListener = null; + changeListener = null; + scrollListener = null; + } + + /** + * Installs any keyboard actions. The list of keys that need to be bound are + * listed in Basic look and feel's defaults. + * + * @param slider The {@link JSlider} that is having keyboard actions + * installed. + */ + protected void installKeyboardActions(JSlider slider) + { + // FIXME: implement. + } + + /** + * Uninstalls any keyboard actions. The list of keys used are listed in + * Basic look and feel's defaults. + * + * @param slider The {@link JSlider} that is having keyboard actions + * uninstalled. + */ + protected void uninstallKeyboardActions(JSlider slider) + { + // FIXME: implement. + } + + /* XXX: This is all after experimentation with SUN's implementation. + + PreferredHorizontalSize seems to be 200x21. + PreferredVerticalSize seems to be 21x200. + + MinimumHorizontalSize seems to be 36x21. + MinimumVerticalSize seems to be 21x36. + + PreferredSize seems to be 200x63. Or Components.getBounds? + + MinimumSize seems to be 36x63. + + MaximumSize seems to be 32767x63. + */ + + /** + * This method returns the preferred size when the slider is + * horizontally oriented. + * + * @return The dimensions of the preferred horizontal size. + */ + public Dimension getPreferredHorizontalSize() + { + Insets insets = slider.getInsets(); + + // The width should cover all the labels (which are usually the + // deciding factor of the width) + int width = getWidthOfWidestLabel() * (slider.getLabelTable() == null ? + 0 : slider.getLabelTable().size()); + + // If there are not enough labels. + // This number is pretty much arbitrary, but it looks nice. + if (width < 200) + width = 200; + + // We can only draw inside of the focusRectangle, so we have to + // pad it with insets. + width += insets.left + insets.right + focusInsets.left + + focusInsets.right; + + // Height is determined by the thumb, the ticks and the labels. + int height = thumbHeight; + + if (slider.getPaintTicks() && slider.getMajorTickSpacing() > 0 || + slider.getMinorTickSpacing() > 0) + height += tickHeight; + + if (slider.getPaintLabels()) + height += getHeightOfTallestLabel(); + + height += insets.top + insets.bottom + focusInsets.top + + focusInsets.bottom; + + return new Dimension(width, height); + } + + /** + * This method returns the preferred size when the slider is + * vertically oriented. + * + * @return The dimensions of the preferred vertical size. + */ + public Dimension getPreferredVerticalSize() + { + Insets insets = slider.getInsets(); + + int height = getHeightOfTallestLabel() * (slider.getLabelTable() == null ? + 0 : slider.getLabelTable().size()); + + if (height < 200) + height = 200; + + height += insets.top + insets.bottom + focusInsets.top + + focusInsets.bottom; + + int width = thumbHeight; + + if (slider.getPaintTicks() && slider.getMajorTickSpacing() > 0 || + slider.getMinorTickSpacing() > 0) + width += tickHeight; + + if (slider.getPaintLabels()) + width += getWidthOfWidestLabel(); + + width += insets.left + insets.right + focusInsets.left + + focusInsets.right; + + return new Dimension(width, height); + } + + /** + * This method returns the minimum size when the slider is + * horizontally oriented. + * + * @return The dimensions of the minimum horizontal size. + */ + public Dimension getMinimumHorizontalSize() + { + return getPreferredHorizontalSize(); + } + + /** + * This method returns the minimum size of the slider when it + * is vertically oriented. + * + * @return The dimensions of the minimum vertical size. + */ + public Dimension getMinimumVerticalSize() + { + return getPreferredVerticalSize(); + } + + /** + * This method returns the preferred size of the component. If it returns + * null, then it is up to the Layout Manager to give the {@link JComponent} + * a size. + * + * @param c The {@link JComponent} to find the preferred size for. + * + * @return The dimensions of the preferred size. + */ + public Dimension getPreferredSize(JComponent c) + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + return getPreferredHorizontalSize(); + else + return getPreferredVerticalSize(); + } + + /** + * This method returns the minimum size for this {@link JSlider} for this + * look and feel. If it returns null, then it is up to the Layout Manager + * to give the {@link JComponent} a size. + * + * @param c The {@link JComponent} to find the minimum size for. + * + * @return The dimensions of the minimum size. + */ + public Dimension getMinimumSize(JComponent c) + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + return getPreferredHorizontalSize(); + else + return getPreferredVerticalSize(); + } + + /** + * This method returns the maximum size for this {@link JSlider} for this + * look and feel. If it returns null, then it is up to the Layout Manager + * to give the {@link JComponent} a size. + * + * @param c The {@link JComponent} to find a maximum size for. + * + * @return The dimensions of the maximum size. + */ + public Dimension getMaximumSize(JComponent c) + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + return getPreferredHorizontalSize(); + else + return getPreferredVerticalSize(); + } + + /** + * This method calculates all the sizes of the rectangles by delegating + * to the helper methods calculateXXXRect. + */ + protected void calculateGeometry() + { + calculateFocusRect(); + calculateContentRect(); + calculateThumbSize(); + calculateTrackBuffer(); + calculateTrackRect(); + calculateTickRect(); + calculateLabelRect(); + calculateThumbLocation(); + } + + /** + * This method calculates the size and position of the focusRect. This + * method does not need to be called if the orientation changes. + */ + protected void calculateFocusRect() + { + insetCache = slider.getInsets(); + focusRect = SwingUtilities.calculateInnerArea(slider, focusRect); + + if (focusRect.width < 0) + focusRect.width = 0; + if (focusRect.height < 0) + focusRect.height = 0; + } + + /** + * This method calculates the size but not the position of the thumbRect. It + * must take into account the orientation of the slider. + */ + protected void calculateThumbSize() + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + if (thumbWidth > contentRect.width) + thumbRect.width = contentRect.width / 4; + else + thumbRect.width = thumbWidth; + if (thumbHeight > contentRect.height) + thumbRect.height = contentRect.height; + else + thumbRect.height = thumbHeight; + } + else + { + // The thumb gets flipped when inverted, so thumbWidth + // actually is the height and vice versa. + if (thumbWidth > contentRect.height) + thumbRect.height = contentRect.height / 4; + else + thumbRect.height = thumbWidth; + if (thumbHeight > contentRect.width) + thumbRect.width = contentRect.width; + else + thumbRect.width = thumbHeight; + } + } + + /** + * This method calculates the size and position of the contentRect. This + * method does not need to be called if the orientation changes. + */ + protected void calculateContentRect() + { + contentRect.x = focusRect.x + focusInsets.left; + contentRect.y = focusRect.y + focusInsets.top; + contentRect.width = focusRect.width - focusInsets.left - focusInsets.right; + contentRect.height = focusRect.height - focusInsets.top + - focusInsets.bottom; + + if (contentRect.width < 0) + contentRect.width = 0; + if (contentRect.height < 0) + contentRect.height = 0; + } + + /** + * Calculates the position of the thumbRect based on the current value of + * the slider. It must take into account the orientation of the slider. + */ + protected void calculateThumbLocation() + { + int value = slider.getValue(); + + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + thumbRect.x = xPositionForValue(value) - thumbRect.width / 2; + thumbRect.y = contentRect.y; + } + else + { + thumbRect.x = contentRect.x; + thumbRect.y = yPositionForValue(value) - thumbRect.height / 2; + } + } + + /** + * Calculates the gap size between the left edge of the contentRect and the + * left edge of the trackRect. + */ + protected void calculateTrackBuffer() + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + trackBuffer = thumbRect.width; + else + trackBuffer = thumbRect.height; + } + + /** + * This method returns the size of the thumbRect. + * + * @return The dimensions of the thumb. + */ + protected Dimension getThumbSize() + { + // This is really just the bounds box for the thumb. + // The thumb will actually be pointed (like a rectangle + triangle at bottom) + return thumbRect.getSize(); + } + + /** + * Calculates the size and position of the trackRect. It must take into + * account the orientation of the slider. + */ + protected void calculateTrackRect() + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + trackRect.x = contentRect.x + trackBuffer; + trackRect.y = contentRect.y; + trackRect.width = contentRect.width - 2 * trackBuffer; + trackRect.height = thumbRect.height; + } + else + { + trackRect.x = contentRect.x; + trackRect.y = contentRect.y + trackBuffer; + trackRect.width = thumbRect.width; + trackRect.height = contentRect.height - 2 * trackBuffer; + } + } + + /** + * This method returns the height of the tick area box if the slider is + * horizontal and the width of the tick area box is the slider is vertical. + * It not necessarily how long the ticks will be. If a gap between the edge + * of tick box and the actual tick is desired, then that will need to be + * handled in the tick painting methods. + * + * @return The height (or width if the slider is vertical) of the tick + * rectangle. + */ + protected int getTickLength() + { + return tickHeight; + } + + /** + * This method calculates the size and position of the tickRect. It must + * take into account the orientation of the slider. + */ + protected void calculateTickRect() + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + tickRect.x = trackRect.x; + tickRect.y = trackRect.y + trackRect.height; + tickRect.width = trackRect.width; + tickRect.height = getTickLength(); + + if (tickRect.y + tickRect.height > contentRect.y + contentRect.height) + tickRect.height = contentRect.y + contentRect.height - tickRect.y; + } + else + { + tickRect.x = trackRect.x + trackRect.width; + tickRect.y = trackRect.y; + tickRect.width = getTickLength(); + tickRect.height = trackRect.height; + + if (tickRect.x + tickRect.width > contentRect.x + contentRect.width) + tickRect.width = contentRect.x + contentRect.width - tickRect.x; + } + } + + /** + * This method calculates the size and position of the labelRect. It must + * take into account the orientation of the slider. + */ + protected void calculateLabelRect() + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + labelRect.x = contentRect.x; + labelRect.y = tickRect.y + tickRect.height; + labelRect.width = contentRect.width; + labelRect.height = contentRect.height - labelRect.y; + } + else + { + labelRect.x = tickRect.x + tickRect.width; + labelRect.y = contentRect.y; + labelRect.width = contentRect.width - labelRect.x; + labelRect.height = contentRect.height; + } + } + + /** + * This method returns the width of the widest label in the slider's label + * table. + * + * @return The width of the widest label or 0 if no label table exists. + */ + protected int getWidthOfWidestLabel() + { + int widest = 0; + Component label; + + if (slider.getLabelTable() == null) + return 0; + + for (Enumeration list = slider.getLabelTable().elements(); + list.hasMoreElements();) + { + Object comp = list.nextElement(); + if (! (comp instanceof Component)) + continue; + label = (Component) comp; + if (label.getWidth() > widest) + widest = label.getWidth(); + } + return widest; + } + + /** + * This method returns the height of the tallest label in the slider's label + * table. + * + * @return The height of the tallest label or 0 if no label table exists. + */ + protected int getHeightOfTallestLabel() + { + int tallest = 0; + Component label; + + if (slider.getLabelTable() == null) + return 0; + + for (Enumeration list = slider.getLabelTable().elements(); + list.hasMoreElements();) + { + Object comp = list.nextElement(); + if (! (comp instanceof Component)) + continue; + label = (Component) comp; + if (label.getHeight() > tallest) + tallest = label.getHeight(); + } + return tallest; + } + + /** + * This method returns the width of the label whose key has the highest + * value. + * + * @return The width of the high value label or 0 if no label table exists. + */ + protected int getWidthOfHighValueLabel() + { + Component highValueLabel = getHighestValueLabel(); + if (highValueLabel != null) + return highValueLabel.getWidth(); + else + return 0; + } + + /** + * This method returns the width of the label whose key has the lowest + * value. + * + * @return The width of the low value label or 0 if no label table exists. + */ + protected int getWidthOfLowValueLabel() + { + Component lowValueLabel = getLowestValueLabel(); + if (lowValueLabel != null) + return lowValueLabel.getWidth(); + else + return 0; + } + + /** + * This method returns the height of the label whose key has the highest + * value. + * + * @return The height of the high value label or 0 if no label table exists. + */ + protected int getHeightOfHighValueLabel() + { + Component highValueLabel = getHighestValueLabel(); + if (highValueLabel != null) + return highValueLabel.getHeight(); + else + return 0; + } + + /** + * This method returns the height of the label whose key has the lowest + * value. + * + * @return The height of the low value label or 0 if no label table exists. + */ + protected int getHeightOfLowValueLabel() + { + Component lowValueLabel = getLowestValueLabel(); + if (lowValueLabel != null) + return lowValueLabel.getHeight(); + else + return 0; + } + + /** + * This method returns whether the slider is to be drawn inverted. + * + * @return True is the slider is to be drawn inverted. + */ + protected boolean drawInverted() + { + return ! (slider.getInverted() ^ leftToRightCache); + } + + /** + * This method returns the label whose key has the lowest value. + * + * @return The low value label or null if no label table exists. + */ + protected Component getLowestValueLabel() + { + Integer key = new Integer(Integer.MAX_VALUE); + Integer tmpKey; + Dictionary labelTable = slider.getLabelTable(); + + if (labelTable == null) + return null; + + for (Enumeration list = labelTable.keys(); list.hasMoreElements();) + { + Object value = list.nextElement(); + if (! (value instanceof Integer)) + continue; + tmpKey = (Integer) value; + if (tmpKey.intValue() < key.intValue()) + key = tmpKey; + } + Object comp = labelTable.get(key); + if (! (comp instanceof Component)) + return null; + return (Component) comp; + } + + /** + * This method returns the label whose key has the highest value. + * + * @return The high value label or null if no label table exists. + */ + protected Component getHighestValueLabel() + { + Integer key = new Integer(Integer.MIN_VALUE); + Integer tmpKey; + Dictionary labelTable = slider.getLabelTable(); + + if (labelTable == null) + return null; + + for (Enumeration list = labelTable.keys(); list.hasMoreElements();) + { + Object value = list.nextElement(); + if (! (value instanceof Integer)) + continue; + tmpKey = (Integer) value; + if (tmpKey.intValue() > key.intValue()) + key = tmpKey; + } + Object comp = labelTable.get(key); + if (! (comp instanceof Component)) + return null; + return (Component) comp; + } + + /** + * This method is used to paint the {@link JSlider}. It delegates all its + * duties to the various paint methods like paintTicks(), paintTrack(), + * paintThumb(), etc. + * + * @param g The {@link Graphics} object to paint with. + * @param c The {@link JComponent} that is being painted. + */ + public void paint(Graphics g, JComponent c) + { + // FIXME: Move this to propertyChangeEvent handler, when we get those. + leftToRightCache = slider.getComponentOrientation() != ComponentOrientation.RIGHT_TO_LEFT; + // FIXME: This next line is only here because the above line is here. + calculateThumbLocation(); + + if (slider.getPaintTrack()) + paintTrack(g); + if (slider.getPaintTicks()) + paintTicks(g); + if (slider.getPaintLabels()) + paintLabels(g); + + //FIXME: Paint focus. + paintThumb(g); + } + + /** + * This method recalculates any rectangles that need to be recalculated + * after the insets of the component have changed. + */ + protected void recalculateIfInsetsChanged() + { + // Examining a test program shows that either Sun calls private + // methods that we don't know about, or these don't do anything. + calculateFocusRect(); + + calculateContentRect(); + calculateThumbSize(); + calculateTrackBuffer(); + calculateTrackRect(); + calculateThumbLocation(); + + calculateTickRect(); + calculateLabelRect(); + } + + /** + * This method recalculates any rectangles that need to be recalculated + * after the orientation of the slider changes. + */ + protected void recalculateIfOrientationChanged() + { + // Examining a test program shows that either Sun calls private + // methods that we don't know about, or these don't do anything. + calculateThumbSize(); + calculateTrackBuffer(); + calculateTrackRect(); + calculateThumbLocation(); + + calculateTickRect(); + calculateLabelRect(); + } + + /** + * This method is called during a repaint if the slider has focus. It draws + * an outline of the focusRect using the color returned by + * getFocusColor(). + * + * @param g The {@link Graphics} object to draw with. + */ + public void paintFocus(Graphics g) + { + Color saved_color = g.getColor(); + + g.setColor(getFocusColor()); + + g.drawRect(focusRect.x, focusRect.y, focusRect.width, focusRect.height); + + g.setColor(saved_color); + } + + /** + * <p> + * This method is called during a repaint if the track is to be drawn. It + * draws a 3D rectangle to represent the track. The track is not the size + * of the trackRect. The top and left edges of the track should be outlined + * with the shadow color. The bottom and right edges should be outlined + * with the highlight color. + * </p> + * <pre> + * a---d + * | | + * | | a------------------------d + * | | | | + * | | b------------------------c + * | | + * | | + * b---c + * </pre> + * + * <p> + * The b-a-d path needs to be drawn with the shadow color and the b-c-d path + * needs to be drawn with the highlight color. + * </p> + * + * @param g The {@link Graphics} object to draw with. + */ + public void paintTrack(Graphics g) + { + Color saved_color = g.getColor(); + int width; + int height; + + Point a = new Point(trackRect.x, trackRect.y); + Point b = new Point(a); + Point c = new Point(a); + Point d = new Point(a); + + Polygon high; + Polygon shadow; + + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + width = trackRect.width; + height = (thumbRect.height / 4 == 0) ? 1 : thumbRect.height / 4; + + a.translate(0, (trackRect.height / 2) - (height / 2)); + b.translate(0, (trackRect.height / 2) + (height / 2)); + c.translate(trackRect.width, (trackRect.height / 2) + (height / 2)); + d.translate(trackRect.width, (trackRect.height / 2) - (height / 2)); + } + else + { + width = (thumbRect.width / 4 == 0) ? 1 : thumbRect.width / 4; + height = trackRect.height; + + a.translate((trackRect.width / 2) - (width / 2), 0); + b.translate((trackRect.width / 2) - (width / 2), trackRect.height); + c.translate((trackRect.width / 2) + (width / 2), trackRect.height); + d.translate((trackRect.width / 2) + (width / 2), 0); + } + high = new Polygon(new int[] { b.x, c.x, d.x }, + new int[] { b.y, c.y, d.y }, 3); + shadow = new Polygon(new int[] { b.x, a.x, d.x }, + new int[] { b.y, a.y, d.y }, 3); + + g.setColor(getHighlightColor()); + g.drawPolygon(high); + g.setColor(getShadowColor()); + g.drawPolygon(shadow); + + g.setColor(Color.GRAY); + g.fillRect(a.x + 1, a.y + 1, width - 2, height - 2); + g.setColor(saved_color); + } + + /** + * This method is called during a repaint if the ticks are to be drawn. This + * method must still verify that the majorTickSpacing and minorTickSpacing + * are greater than zero before drawing the ticks. + * + * @param g The {@link Graphics} object to draw with. + */ + public void paintTicks(Graphics g) + { + int max = slider.getMaximum(); + int min = slider.getMinimum(); + int majorSpace = slider.getMajorTickSpacing(); + int minorSpace = slider.getMinorTickSpacing(); + + if (majorSpace > 0) + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + double loc = tickRect.x; + double increment = (max == min) ? 0 + : majorSpace * (double) tickRect.width / (max + - min); + if (drawInverted()) + { + loc += tickRect.width; + increment *= -1; + } + for (int i = min; i <= max; i += majorSpace) + { + paintMajorTickForHorizSlider(g, tickRect, (int) loc); + loc += increment; + } + } + else + { + double loc = tickRect.height + tickRect.y; + double increment = (max == min) ? 0 + : -majorSpace * (double) tickRect.height / (max + - min); + if (drawInverted()) + { + loc = tickRect.y; + increment *= -1; + } + for (int i = min; i <= max; i += majorSpace) + { + paintMajorTickForVertSlider(g, tickRect, (int) loc); + loc += increment; + } + } + } + if (minorSpace > 0) + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + double loc = tickRect.x; + double increment = (max == min) ? 0 + : minorSpace * (double) tickRect.width / (max + - min); + if (drawInverted()) + { + loc += tickRect.width; + increment *= -1; + } + for (int i = min; i <= max; i += minorSpace) + { + paintMinorTickForHorizSlider(g, tickRect, (int) loc); + loc += increment; + } + } + else + { + double loc = tickRect.height + tickRect.y; + double increment = (max == min) ? 0 + : -minorSpace * (double) tickRect.height / (max + - min); + if (drawInverted()) + { + loc = tickRect.y; + increment *= -1; + } + for (int i = min; i <= max; i += minorSpace) + { + paintMinorTickForVertSlider(g, tickRect, (int) loc); + loc += increment; + } + } + } + } + + /* Minor ticks start at 1/4 of the height (or width) of the tickRect and extend + to 1/2 of the tickRect. + + Major ticks start at 1/4 of the height and extend to 3/4. + */ + + /** + * This method paints a minor tick for a horizontal slider at the given x + * value. x represents the x coordinate to paint at. + * + * @param g The {@link Graphics} object to draw with. + * @param tickBounds The tickRect rectangle. + * @param x The x coordinate to draw the tick at. + */ + protected void paintMinorTickForHorizSlider(Graphics g, + Rectangle tickBounds, int x) + { + int y = tickRect.y + tickRect.height / 4; + + g.drawLine(x, y, x, y + tickRect.height / 4); + } + + /** + * This method paints a major tick for a horizontal slider at the given x + * value. x represents the x coordinate to paint at. + * + * @param g The {@link Graphics} object to draw with. + * @param tickBounds The tickRect rectangle. + * @param x The x coordinate to draw the tick at. + */ + protected void paintMajorTickForHorizSlider(Graphics g, + Rectangle tickBounds, int x) + { + int y = tickRect.y + tickRect.height / 4; + + g.drawLine(x, y, x, y + tickRect.height / 2); + } + + /** + * This method paints a minor tick for a vertical slider at the given y + * value. y represents the y coordinate to paint at. + * + * @param g The {@link Graphics} object to draw with. + * @param tickBounds The tickRect rectangle. + * @param y The y coordinate to draw the tick at. + */ + protected void paintMinorTickForVertSlider(Graphics g, Rectangle tickBounds, + int y) + { + int x = tickRect.x + tickRect.width / 4; + + g.drawLine(x, y, x + tickRect.width / 4, y); + } + + /** + * This method paints a major tick for a vertical slider at the given y + * value. y represents the y coordinate to paint at. + * + * @param g The {@link Graphics} object to draw with. + * @param tickBounds The tickRect rectangle. + * @param y The y coordinate to draw the tick at. + */ + protected void paintMajorTickForVertSlider(Graphics g, Rectangle tickBounds, + int y) + { + int x = tickRect.x + tickRect.width / 4; + + g.drawLine(x, y, x + tickRect.width / 2, y); + } + + /** + * This method paints all the labels from the slider's label table. This + * method must make sure that the label table is not null before painting + * the labels. Each entry in the label table is a (integer, component) + * pair. Every label is painted at the value of the integer. + * + * @param g The {@link Graphics} object to draw with. + */ + public void paintLabels(Graphics g) + { + if (slider.getLabelTable() != null) + { + Dictionary table = slider.getLabelTable(); + Integer tmpKey; + Object key; + Object element; + Component label; + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + for (Enumeration list = table.keys(); list.hasMoreElements();) + { + key = list.nextElement(); + if (! (key instanceof Integer)) + continue; + tmpKey = (Integer) key; + element = table.get(tmpKey); + // We won't paint them if they're not + // JLabels so continue anyway + if (! (element instanceof JLabel)) + continue; + label = (Component) element; + paintHorizontalLabel(g, tmpKey.intValue(), label); + } + } + else + { + for (Enumeration list = table.keys(); list.hasMoreElements();) + { + key = list.nextElement(); + if (! (key instanceof Integer)) + continue; + tmpKey = (Integer) key; + element = table.get(tmpKey); + // We won't paint them if they're not + // JLabels so continue anyway + if (! (element instanceof JLabel)) + continue; + label = (Component) element; + paintVerticalLabel(g, tmpKey.intValue(), label); + } + } + } + } + + /** + * This method paints the label on the horizontal slider at the value + * specified. The value is not a coordinate. It is a value within the range + * of the slider. If the value is not within the range of the slider, this + * method will do nothing. This method should not paint outside the + * boundaries of the labelRect. + * + * @param g The {@link Graphics} object to draw with. + * @param value The value to paint at. + * @param label The label to paint. + */ + protected void paintHorizontalLabel(Graphics g, int value, Component label) + { + // This relies on clipping working properly or we'll end up + // painting all over the place. If our preferred size is ignored, then + // the labels may not fit inside the slider's bounds. Rather than mucking + // with font sizes and possible icon sizes, we'll set the bounds for + // the label and let it get clipped. + + Dimension dim = label.getPreferredSize(); + int w = (int) dim.getWidth(); + int h = (int) dim.getHeight(); + + int max = slider.getMaximum(); + int min = slider.getMinimum(); + + if (value > max || value < min) + return; + + // value + // | + // ------------ + // | | + // | | + // | | + // The label must move w/2 to the right to fit directly under the value. + + + int xpos = xPositionForValue(value) - w / 2; + int ypos = labelRect.y; + + // We want to center the label around the xPositionForValue + // So we use xpos - w / 2. However, if value is min and the label + // is large, we run the risk of going out of bounds. So we bring it back + // to 0 if it becomes negative. + if (xpos < 0) + xpos = 0; + + // If the label + starting x position is greater than + // the x space in the label rectangle, we reset it to the largest + // amount possible in the rectangle. This means ugliness. + if (xpos + w > labelRect.x + labelRect.width) + w = labelRect.x + labelRect.width - xpos; + + // If the label is too tall. We reset it to the height of the label + // rectangle. + if (h > labelRect.height) + h = labelRect.height; + + label.setBounds(xpos, ypos, w, h); + javax.swing.SwingUtilities.paintComponent(g, label, null, label.getBounds()); + } + + /** + * This method paints the label on the vertical slider at the value + * specified. The value is not a coordinate. It is a value within the range + * of the slider. If the value is not within the range of the slider, this + * method will do nothing. This method should not paint outside the + * boundaries of the labelRect. + * + * @param g The {@link Graphics} object to draw with. + * @param value The value to paint at. + * @param label The label to paint. + */ + protected void paintVerticalLabel(Graphics g, int value, Component label) + { + Dimension dim = label.getPreferredSize(); + int w = (int) dim.getWidth(); + int h = (int) dim.getHeight(); + + int max = slider.getMaximum(); + int min = slider.getMinimum(); + + if (value > max || value < min) + return; + + int xpos = labelRect.x; + int ypos = yPositionForValue(value) - h / 2; + + if (ypos < 0) + ypos = 0; + + if (ypos + h > labelRect.y + labelRect.height) + h = labelRect.y + labelRect.height - ypos; + + if (w > labelRect.width) + w = labelRect.width; + + label.setBounds(xpos, ypos, w, h); + javax.swing.SwingUtilities.paintComponent(g, label, null, label.getBounds()); + } + + /** + * <p> + * This method paints a thumb. There are two types of thumb: + * </p> + * <pre> + * Vertical Horizontal + * a---b a-----b + * | | | \ + * e c | c + * \ / | / + * d e-----d + * </pre> + * + * <p> + * In the case of vertical thumbs, we highlight the path b-a-e-d and shadow + * the path b-c-d. In the case of horizontal thumbs, we highlight the path + * c-b-a-e and shadow the path c-d-e. In both cases we fill the path + * a-b-c-d-e before shadows and highlights are drawn. + * </p> + * + * @param g The graphics object to paint with + */ + public void paintThumb(Graphics g) + { + Color saved_color = g.getColor(); + + Polygon thumb = new Polygon(); + + Point a = new Point(thumbRect.x, thumbRect.y); + Point b = new Point(a); + Point c = new Point(a); + Point d = new Point(a); + Point e = new Point(a); + + Polygon bright; + Polygon dark; + Polygon all; + + // This will be in X-dimension if the slider is inverted and y if it isn't. + int turnPoint; + + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + turnPoint = thumbRect.height * 3 / 4; + + b.translate(thumbRect.width, 0); + c.translate(thumbRect.width, turnPoint); + d.translate(thumbRect.width / 2, thumbRect.height); + e.translate(0, turnPoint); + + bright = new Polygon(new int[] { b.x, a.x, e.x, d.x }, + new int[] { b.y, a.y, e.y, d.y }, 4); + + dark = new Polygon(new int[] { b.x, c.x, d.x }, + new int[] { b.y, c.y, d.y }, 3); + all = new Polygon(new int[] { a.x + 1, b.x, c.x, d.x, e.x + 1 }, + new int[] { a.y + 1, b.y + 1, c.y, d.y + 1, e.y }, 5); + } + else + { + turnPoint = thumbRect.width * 3 / 4; + + b.translate(turnPoint, 0); + c.translate(thumbRect.width, thumbRect.height / 2); + d.translate(turnPoint, thumbRect.height); + e.translate(0, thumbRect.height); + + bright = new Polygon(new int[] { c.x, b.x, a.x, e.x }, + new int[] { c.y, b.y, a.y, e.y }, 4); + + dark = new Polygon(new int[] { c.x, d.x, e.x + 1 }, + new int[] { c.y, d.y, e.y }, 3); + + all = new Polygon(new int[] { a.x + 1, b.x, c.x - 1, d.x, e.x + 1 }, + new int[] { a.y + 1, b.y + 1, c.y, d.y, e.y }, 5); + } + + g.setColor(Color.WHITE); + g.drawPolygon(bright); + + g.setColor(Color.BLACK); + g.drawPolygon(dark); + + g.setColor(Color.GRAY); + g.fillPolygon(all); + + g.setColor(saved_color); + } + + /** + * This method sets the position of the thumbRect. + * + * @param x The new x position. + * @param y The new y position. + */ + public void setThumbLocation(int x, int y) + { + thumbRect.x = x; + thumbRect.y = y; + } + + /** + * This method is used to move the thumb one block in the direction + * specified. If the slider snaps to ticks, this method is responsible for + * snapping it to a tick after the thumb has been moved. + * + * @param direction The direction to move in. + */ + public void scrollByBlock(int direction) + { + // The direction is -1 for backwards and 1 for forwards. + int unit = direction * (slider.getMaximum() - slider.getMinimum()) / 10; + + int moveTo = slider.getValue() + unit; + + if (slider.getSnapToTicks()) + moveTo = findClosestTick(moveTo); + + slider.setValue(moveTo); + } + + /** + * This method is used to move the thumb one unit in the direction + * specified. If the slider snaps to ticks, this method is responsible for + * snapping it to a tick after the thumb has been moved. + * + * @param direction The direction to move in. + */ + public void scrollByUnit(int direction) + { + // The direction is -1 for backwards and 1 for forwards. + int moveTo = slider.getValue() + direction; + + if (slider.getSnapToTicks()) + moveTo = findClosestTick(moveTo); + + slider.setValue(moveTo); + } + + /** + * This method is called when there has been a click in the track and the + * thumb needs to be scrolled on regular intervals. This method is only + * responsible for starting the timer and not for stopping it. + * + * @param dir The direction to move in. + */ + protected void scrollDueToClickInTrack(int dir) + { + scrollTimer.stop(); + + scrollListener.setDirection(dir); + scrollListener.setScrollByBlock(true); + + scrollTimer.start(); + } + + /** + * This method returns the X coordinate for the value passed in. + * + * @param value The value to calculate an x coordinate for. + * + * @return The x coordinate for the value. + */ + protected int xPositionForValue(int value) + { + int min = slider.getMinimum(); + int max = slider.getMaximum(); + int extent = slider.getExtent(); + int len = trackRect.width; + + int xPos = (max == min) ? 0 : (value - min) * len / (max - min); + + if (! drawInverted()) + xPos += trackRect.x; + else + { + xPos = trackRect.width - xPos; + xPos += trackRect.x; + } + return xPos; + } + + /** + * This method returns the y coordinate for the value passed in. + * + * @param value The value to calculate a y coordinate for. + * + * @return The y coordinate for the value. + */ + protected int yPositionForValue(int value) + { + int min = slider.getMinimum(); + int max = slider.getMaximum(); + int extent = slider.getExtent(); + int len = trackRect.height; + + int yPos = (max == min) ? 0 : (value - min) * len / (max - min); + + if (! drawInverted()) + { + yPos = trackRect.height - yPos; + yPos += trackRect.y; + } + else + yPos += trackRect.y; + return yPos; + } + + /** + * This method returns the value in the slider's range given the y + * coordinate. If the value is out of range, it will return the closest + * legal value. + * + * @param yPos The y coordinate to calculate a value for. + * + * @return The value for the y coordinate. + */ + public int valueForYPosition(int yPos) + { + int min = slider.getMinimum(); + int max = slider.getMaximum(); + int len = trackRect.height; + + int value; + + // If the length is 0, you shouldn't be able to even see where the slider is. + // This really shouldn't ever happen, but just in case, we'll return the middle. + if (len == 0) + return ((max - min) / 2); + + if (! drawInverted()) + value = ((len - (yPos - trackRect.y)) * (max - min) / len + min); + else + value = ((yPos - trackRect.y) * (max - min) / len + min); + + // If this isn't a legal value, then we'll have to move to one now. + if (value > max) + value = max; + else if (value < min) + value = min; + return value; + } + + /** + * This method returns the value in the slider's range given the x + * coordinate. If the value is out of range, it will return the closest + * legal value. + * + * @param xPos The x coordinate to calculate a value for. + * + * @return The value for the x coordinate. + */ + public int valueForXPosition(int xPos) + { + int min = slider.getMinimum(); + int max = slider.getMaximum(); + int len = trackRect.width; + + int value; + + // If the length is 0, you shouldn't be able to even see where the slider is. + // This really shouldn't ever happen, but just in case, we'll return the middle. + if (len == 0) + return ((max - min) / 2); + + if (! drawInverted()) + value = ((xPos - trackRect.x) * (max - min) / len + min); + else + value = ((len - (xPos - trackRect.x)) * (max - min) / len + min); + + // If this isn't a legal value, then we'll have to move to one now. + if (value > max) + value = max; + else if (value < min) + value = min; + return value; + } + + /** + * This method finds the closest value that has a tick associated with it. + * + * @param value The value to search from. + * + * @return The closest value that has a tick associated with it. + */ + private int findClosestTick(int value) + { + int min = slider.getMinimum(); + int max = slider.getMaximum(); + int majorSpace = slider.getMajorTickSpacing(); + int minorSpace = slider.getMinorTickSpacing(); + + // The default value to return is value + minor or + // value + major. + // Initializing at min - value leaves us with a default + // return value of min, which always has tick marks + // (if ticks are painted). + int minor = min - value; + int major = min - value; + + // If there are no major tick marks or minor tick marks + // e.g. snap is set to true but no ticks are set, then + // we can just return the value. + if (majorSpace <= 0 && minorSpace <= 0) + return value; + + // First check the major ticks. + if (majorSpace > 0) + { + int lowerBound = (value - min) / majorSpace; + int majLower = majorSpace * lowerBound + min; + int majHigher = majorSpace * (lowerBound + 1) + min; + + if (majHigher <= max && majHigher - value <= value - majLower) + major = majHigher - value; + else + major = majLower - value; + } + + if (minorSpace > 0) + { + int lowerBound = value / minorSpace; + int minLower = minorSpace * lowerBound; + int minHigher = minorSpace * (lowerBound + 1); + + if (minHigher <= max && minHigher - value <= value - minLower) + minor = minHigher - value; + else + minor = minLower - value; + } + + // Give preference to minor ticks + if (Math.abs(minor) > Math.abs(major)) + return value + major; + else + return value + minor; + } +} diff --git a/libstdc++-v3/config/allocator/bitmap_allocator_base.h b/libstdc++-v3/config/allocator/bitmap_allocator_base.h new file mode 100644 index 00000000000..bf84ae06d7f --- /dev/null +++ b/libstdc++-v3/config/allocator/bitmap_allocator_base.h @@ -0,0 +1,37 @@ +// Base to std::allocator -*- C++ -*- + +// Copyright (C) 2004 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. + +// As a special exception, you may use this file as part of a free software +// library without restriction. Specifically, if other files instantiate +// templates or use macros or inline functions from this file, or you compile +// this file and link it with other files to produce an executable, this +// file does not by itself cause the resulting executable to be covered by +// the GNU General Public License. This exception does not however +// invalidate any other reasons why the executable file might be covered by +// the GNU General Public License. + +#ifndef _CXX_ALLOCATOR_H +#define _CXX_ALLOCATOR_H 1 + +// Define bitmap_allocator as the base class to std::allocator. +#include <ext/bitmap_allocator.h> +#define ___glibcxx_base_allocator __gnu_cxx::bitmap_allocator + +#endif diff --git a/libstdc++-v3/config/allocator/malloc_allocator_base.h b/libstdc++-v3/config/allocator/malloc_allocator_base.h new file mode 100644 index 00000000000..4a82ec362c5 --- /dev/null +++ b/libstdc++-v3/config/allocator/malloc_allocator_base.h @@ -0,0 +1,37 @@ +// Base to std::allocator -*- C++ -*- + +// Copyright (C) 2004 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. + +// As a special exception, you may use this file as part of a free software +// library without restriction. Specifically, if other files instantiate +// templates or use macros or inline functions from this file, or you compile +// this file and link it with other files to produce an executable, this +// file does not by itself cause the resulting executable to be covered by +// the GNU General Public License. This exception does not however +// invalidate any other reasons why the executable file might be covered by +// the GNU General Public License. + +#ifndef _CXX_ALLOCATOR_H +#define _CXX_ALLOCATOR_H 1 + +// Define new_allocator as the base class to std::allocator. +#include <ext/malloc_allocator.h> +#define ___glibcxx_base_allocator __gnu_cxx::malloc_allocator + +#endif diff --git a/libstdc++-v3/config/allocator/mt_allocator_base.h b/libstdc++-v3/config/allocator/mt_allocator_base.h new file mode 100644 index 00000000000..52b4421a439 --- /dev/null +++ b/libstdc++-v3/config/allocator/mt_allocator_base.h @@ -0,0 +1,37 @@ +// Base to std::allocator -*- C++ -*- + +// Copyright (C) 2004 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. + +// As a special exception, you may use this file as part of a free software +// library without restriction. Specifically, if other files instantiate +// templates or use macros or inline functions from this file, or you compile +// this file and link it with other files to produce an executable, this +// file does not by itself cause the resulting executable to be covered by +// the GNU General Public License. This exception does not however +// invalidate any other reasons why the executable file might be covered by +// the GNU General Public License. + +#ifndef _CXX_ALLOCATOR_H +#define _CXX_ALLOCATOR_H 1 + +// Define mt_allocator as the base class to std::allocator. +#include <ext/mt_allocator.h> +#define ___glibcxx_base_allocator __gnu_cxx::__mt_alloc + +#endif diff --git a/libstdc++-v3/config/allocator/new_allocator_base.h b/libstdc++-v3/config/allocator/new_allocator_base.h new file mode 100644 index 00000000000..442f89cc535 --- /dev/null +++ b/libstdc++-v3/config/allocator/new_allocator_base.h @@ -0,0 +1,37 @@ +// Base to std::allocator -*- C++ -*- + +// Copyright (C) 2004 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. + +// As a special exception, you may use this file as part of a free software +// library without restriction. Specifically, if other files instantiate +// templates or use macros or inline functions from this file, or you compile +// this file and link it with other files to produce an executable, this +// file does not by itself cause the resulting executable to be covered by +// the GNU General Public License. This exception does not however +// invalidate any other reasons why the executable file might be covered by +// the GNU General Public License. + +#ifndef _CXX_ALLOCATOR_H +#define _CXX_ALLOCATOR_H 1 + +// Define new_allocator as the base class to std::allocator. +#include <ext/new_allocator.h> +#define ___glibcxx_base_allocator __gnu_cxx::new_allocator + +#endif diff --git a/libstdc++-v3/docs/html/ext/ballocator_doc.txt b/libstdc++-v3/docs/html/ext/ballocator_doc.txt new file mode 100644 index 00000000000..2173b618f4f --- /dev/null +++ b/libstdc++-v3/docs/html/ext/ballocator_doc.txt @@ -0,0 +1,374 @@ + BITMAPPED ALLOCATOR + =================== + +2004-03-11 Dhruv Matani <dhruvbird@HotPOP.com> + +--------------------------------------------------------------------- + +As this name suggests, this allocator uses a bit-map to keep track of +the used and unused memory locations for it's book-keeping purposes. + +This allocator will make use of 1 single bit to keep track of whether +it has been allocated or not. A bit 1 indicates free, while 0 +indicates allocated. This has been done so that you can easily check a +collection of bits for a free block. This kind of Bitmapped strategy +works best for single object allocations, and with the STL type +parameterized allocators, we do not need to choose any size for the +block which will be represented by a single bit. This will be the size +of the parameter around which the allocator has been +parameterized. Thus, close to optimal performance will result. Hence, +this should be used for node based containers which call the allocate +function with an argument of 1. + +The bitmapped allocator's internal pool is exponentially +growing. Meaning that internally, the blocks acquired from the Free +List Store will double every time the bitmapped allocator runs out of +memory. + +-------------------------------------------------------------------- + +The macro __GTHREADS decides whether to use Mutex Protection around +every allocation/deallocation. The state of the macro is picked up +automatically from the gthr abstration layer. + +---------------------------------------------------------------------- + +What is the Free List Store? +---------------------------- + +The Free List Store (referred to as FLS for the remaining part of this +document) is the Global memory pool that is shared by all instances of +the bitmapped allocator instantiated for any type. This maintains a +sorted order of all free memory blocks given back to it by the +bitmapped allocator, and is also responsible for giving memory to the +bitmapped allocator when it asks for more. + +Internally, there is a Free List threshold which indicates the Maximum +number of free lists that the FLS can hold internally +(cache). Currently, this value is set at 64. So, if there are more +than 64 free lists coming in, then some of them will be given back to +the OS using operator delete so that at any given time the Free List's +size does not exceed 64 entries. This is done because a Binary Search +is used to locate an entry in a free list when a request for memory +comes along. Thus, the run-time complexity of the search would go up +given an increasing size, for 64 entries however, lg(64) == 6 +comparisons are enough to locate the correct free list if it exists. + +Suppose the free list size has reached it's threshold, then the +largest block from among those in the list and the new block will be +selected and given back to the OS. This is done because it reduces +external fragmentation, and allows the OS to use the larger blocks +later in an orderly fashion, possibly merging them later. Also, on +some systems, large blocks are obtained via calls to mmap, so giving +them back to free system resources becomes most important. + +The function _S_should_i_give decides the policy that determines +whether the current block of memory should be given to the allocator +for the request that it has made. That's because we may not always +have exact fits for the memory size that the allocator requests. We do +this mainly to prevent external fragmentation at the cost of a little +internal fragmentation. Now, the value of this internal fragmentation +has to be decided by this function. I can see 3 possibilities right +now. Please add more as and when you find better strategies. + +1. Equal size check. Return true only when the 2 blocks are of equal + size. + +2. Difference Threshold: Return true only when the _block_size is + greater than or equal to the _required_size, and if the _BS is > + _RS by a difference of less than some THRESHOLD value, then return + true, else return false. + +3. Percentage Threshold. Return true only when the _block_size is + greater than or equal to the _required_size, and if the _BS is > + _RS by a percentage of less than some THRESHOLD value, then return + true, else return false. + +Currently, (3) is being used with a value of 36% Maximum wastage per +Super Block. + +-------------------------------------------------------------------- + +1) What is a super block? Why is it needed? + + A super block is the block of memory acquired from the FLS from + which the bitmap allocator carves out memory for single objects and + satisfies the user's requests. These super blocks come in sizes that + are powers of 2 and multiples of 32 (_Bits_Per_Block). Yes both at + the same time! That's because the next super block acquired will be + 2 times the previous one, and also all super blocks have to be + multiples of the _Bits_Per_Block value. + +2) How does it interact with the free list store? + + The super block is contained in the FLS, and the FLS is responsible + for getting / returning Super Bocks to and from the OS using + operator new as defined by the C++ standard. + +--------------------------------------------------------------------- + +How does the allocate function Work? +------------------------------------ + +The allocate function is specialized for single object allocation +ONLY. Thus, ONLY if n == 1, will the bitmap_allocator's specialized +algorithm be used. Otherwise, the request is satisfied directly by +calling operator new. + +Suppose n == 1, then the allocator does the following: + +1. Checks to see whether the a free block exists somewhere in a region + of memory close to the last satisfied request. If so, then that + block is marked as allocated in the bit map and given to the + user. If not, then (2) is executed. + +2. Is there a free block anywhere after the current block right upto + the end of the memory that we have? If so, that block is found, and + the same procedure is applied as above, and returned to the + user. If not, then (3) is executed. + +3. Is there any block in whatever region of memory that we own free? + This is done by checking (a) The use count for each super block, + and if that fails then (b) The individual bit-maps for each super + block. Note: Here we are never touching any of the memory that the + user will be given, and we are confining all memory accesses to a + small region of memory! This helps reduce cache misses. If this + succeeds then we apply the same procedure on that bit-map as (1), + and return that block of memory to the user. However, if this + process fails, then we resort to (4). + +4. This process involves Refilling the internal exponentially growing + memory pool. The said effect is achieved by calling _S_refill_pool + which does the following: + (a). Gets more memory from the Global Free List of the + Required size. + (b). Adjusts the size for the next call to itself. + (c). Writes the appropriate headers in the bit-maps. + (d). Sets the use count for that super-block just allocated + to 0 (zero). + (e). All of the above accounts to maintaining the basic + invariant for the allocator. If the invariant is + maintained, we are sure that all is well. + Now, the same process is applied on the newly acquired free blocks, + which are dispatched accordingly. + +Thus, you can clearly see that the allocate function is nothing but a +combination of the next-fit and first-fit algorithm optimized ONLY for +single object allocations. + + +------------------------------------------------------------------------- + +How does the deallocate function work? +-------------------------------------- + +The deallocate function again is specialized for single objects ONLY. +For all n belonging to > 1, the operator delete is called without +further ado, and the deallocate function returns. + +However for n == 1, a series of steps are performed: + +1. We first need to locate that super-block which holds the memory + location given to us by the user. For that purpose, we maintain a + static variable _S_last_dealloc_index, which holds the index into + the vector of block pairs which indicates the index of the last + super-block from which memory was freed. We use this strategy in + the hope that the user will deallocate memory in a region close to + what he/she deallocated the last time around. If the check for + belongs_to succeeds, then we determine the bit-map for the given + pointer, and locate the index into that bit-map, and mark that bit + as free by setting it. + +2. If the _S_last_dealloc_index does not point to the memory block + that we're looking for, then we do a linear search on the block + stored in the vector of Block Pairs. This vector in code is called + _S_mem_blocks. When the corresponding super-block is found, we + apply the same procedure as we did for (1) to mark the block as + free in the bit-map. + +Now, whenever a block is freed, the use count of that particular super +block goes down by 1. When this use count hits 0, we remove that super +block from the list of all valid super blocks stored in the +vector. While doing this, we also make sure that the basic invariant +is maintained by making sure that _S_last_request and +_S_last_dealloc_index point to valid locations within the vector. + +-------------------------------------------------------------------- + + +Data Layout for a Super Block: +============================== + +Each Super Block will be of some size that is a multiple of the number +of Bits Per Block. Typically, this value is chosen as Bits_Per_Byte X +sizeof(unsigned int). On an X86 system, this gives the figure +8 X 4 = 32. Thus, each Super Block will be of size 32 X Some_Value. +This Some_Value is sizeof(value_type). For now, let it be called 'K'. +Thus, finally, Super Block size is 32 X K bytes. + +This value of 32 has been chosen because each unsigned int has 32-bits +and Maximum use of these can be made with such a figure. + +Consider a block of size 32 ints. +In memory, it would look like this: + +--------------------------------------------------------------------- +| 136 | 0 | 4294967295 | Data-> Space for 32-ints | +--------------------------------------------------------------------- + +The first Columns represents the size of the Block in bytes as seen by +the Bitmap Allocator. Internally, a global free list is used to keep +track of the free blocks used and given back by the bitmap +allocator. It is this Free List Store that is responsible for writing +and managing this information. Actually the number of bytes allocated +in this case would be: 4 + 4 + 4 + 32*4 = 140 bytes, but the first 4 +bytes are an addition by the Free List Store, so the Bitmap Allocator +sees only 136 bytes. These first 4 bytes about which the bitmapped +allocator is not aware hold the value 136. + +What do the remaining values represent? +--------------------------------------- + +The 2nd 4 in the expression is the sizeof(unsigned int) because the +Bitmapped Allocator maintains a used count for each Super Block, which +is initially set to 0 (as indicated in the diagram). This is +incremented every time a block is removed from this super block +(allocated), and decremented whenever it is given back. So, when the +used count falls to 0, the whole super block will be given back to the +Free List Store. + +The value 4294967295 represents the integer corresponding to the +bit representation of all bits set: 11111111111111111111111111111111. + +The 3rd 4 is size of the bitmap itself, which is the size of 32-bits, +which is 4-bytes, or 1 X sizeof(unsigned int). + + +-------------------------------------------------------------------- + +Another issue would be whether to keep the all bitmaps in a separate +area in memory, or to keep them near the actual blocks that will be +given out or allocated for the client. After some testing, I've +decided to keep these bitmaps close to the actual blocks. this will +help in 2 ways. + +1. Constant time access for the bitmap themselves, since no kind of + look up will be needed to find the correct bitmap list or it's + equivalent. + +2. And also this would preserve the cache as far as possible. + +So in effect, this kind of an allocator might prove beneficial from a +purely cache point of view. But this allocator has been made to try +and roll out the defects of the node_allocator, wherein the nodes get +skewed about in memory, if they are not returned in the exact reverse +order or in the same order in which they were allocated. Also, the +new_allocator's book keeping overhead is too much for small objects +and single object allocations, though it preserves the locality of +blocks very well when they are returned back to the allocator. + +------------------------------------------------------------------- + +Expected overhead per block would be 1 bit in memory. Also, once +the address of the free list has been found, the cost for +allocation/deallocation would be negligible, and is supposed to be +constant time. For these very reasons, it is very important to +minimize the linear time costs, which include finding a free list +with a free block while allocating, and finding the corresponding +free list for a block while deallocating. Therefore, I have decided +that the growth of the internal pool for this allocator will be +exponential as compared to linear for node_allocator. There, linear +time works well, because we are mainly concerned with speed of +allocation/deallocation and memory consumption, whereas here, the +allocation/deallocation part does have some linear/logarithmic +complexity components in it. Thus, to try and minimize them would +be a good thing to do at the cost of a little bit of memory. + +Another thing to be noted is the the pool size will double every time +the internal pool gets exhausted, and all the free blocks have been +given away. The initial size of the pool would be sizeof(unsigned +int)*8 which is the number of bits in an integer, which can fit +exactly in a CPU register. Hence, the term given is exponential growth +of the internal pool. + +--------------------------------------------------------------------- + +After reading all this, you may still have a few questions about the +internal working of this allocator, like my friend had! + +Well here are the exact questions that he posed: + +1) The "Data Layout" section is cryptic. I have no idea of what you + are trying to say. Layout of what? The free-list? Each bitmap? The + Super Block? + + The layout of a Super Block of a given size. In the example, a super + block of size 32 X 1 is taken. The general formula for calculating + the size of a super block is 32*sizeof(value_type)*2^n, where n + ranges from 0 to 32 for 32-bit systems. + +2) And since I just mentioned the term `each bitmap', what in the + world is meant by it? What does each bitmap manage? How does it + relate to the super block? Is the Super Block a bitmap as well? + + Good question! Each bitmap is part of a Super Block which is made up + of 3 parts as I have mentioned earlier. Re-iterating, 1. The use + count, 2. The bit-map for that Super Block. 3. The actual memory + that will be eventually given to the user. Each bitmap is a multiple + of 32 in size. If there are 32*(2^3) blocks of single objects to be + given, there will be '32*(2^3)' bits present. Each 32 bits managing + the allocated / free status for 32 blocks. Since each unsigned int + contains 32-bits, one unsigned int can manage upto 32 blocks' + status. Each bit-map is made up of a number of unsigned ints, whose + exact number for a super-block of a given size I have just + mentioned. + +3) How do the allocate and deallocate functions work in regard to + bitmaps? + + The allocate and deallocate functions manipulate the bitmaps and have + nothing to do with the memory that is given to the user. As I have + earlier mentioned, a 1 in the bitmap's bit field indicates free, + while a 0 indicates allocated. This lets us check 32 bits at a time + to check whether there is at lease one free block in those 32 blocks + by testing for equality with (0). Now, the allocate function will + given a memory block find the corresponding bit in the bitmap, and + will reset it (ie. make it re-set (0)). And when the deallocate + function is called, it will again set that bit after locating it to + indicate that that particular block corresponding to this bit in the + bit-map is not being used by anyone, and may be used to satisfy + future requests. + +---------------------------------------------------------------------- + +(Tech-Stuff, Please stay out if you are not interested in the +selection of certain constants. This has nothing to do with the +algorithm per-se, only with some vales that must be chosen correctly +to ensure that the allocator performs well in a real word scenario, +and maintains a good balance between the memory consumption and the +allocation/deallocation speed). + +The formula for calculating the maximum wastage as a percentage: + +(32 X k + 1) / (2 X (32 X k + 1 + 32 X c)) X 100. + +Where, + k => The constant overhead per node. eg. for list, it is 8 + bytes, and for map it is 12 bytes. + c => The size of the base type on which the map/list is + instantiated. Thus, suppose the the type1 is int and type2 is + double, they are related by the relation sizeof(double) == + 2*sizeof(int). Thus, all types must have this double size + relation for this formula to work properly. + +Plugging-in: For List: k = 8 and c = 4 (int and double), we get: +33.376% + +For map/multimap: k = 12, and c = 4 (int and double), we get: +37.524% + +Thus, knowing these values, and based on the sizeof(value_type), we +may create a function that returns the Max_Wastage_Percentage for us +to use. + + diff --git a/libstdc++-v3/testsuite/20_util/allocator/14176.cc b/libstdc++-v3/testsuite/20_util/allocator/14176.cc new file mode 100644 index 00000000000..cb8a2f5c4bf --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/allocator/14176.cc @@ -0,0 +1,42 @@ +// Copyright (C) 2004 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. + +// 20.4.1.1 allocator members + +#include <memory> +#include <testsuite_hooks.h> + +// libstdc++/14176 +void test02() +{ + unsigned int len = 0; + std::allocator<int> a; + int* p = a.allocate(len); + a.deallocate(p, len); +} + +#if !__GXX_WEAK__ && _MT_ALLOCATOR_H +// Explicitly instantiate for systems with no COMDAT or weak support. +template class __gnu_cxx::__mt_alloc<int>; +#endif + +int main() +{ + test02(); + return 0; +} diff --git a/libstdc++-v3/testsuite/22_locale/locale/cons/12658_thread.cc b/libstdc++-v3/testsuite/22_locale/locale/cons/12658_thread.cc new file mode 100644 index 00000000000..3a89d371f62 --- /dev/null +++ b/libstdc++-v3/testsuite/22_locale/locale/cons/12658_thread.cc @@ -0,0 +1,67 @@ +// { dg-do run { target *-*-freebsd* *-*-netbsd* *-*-linux* *-*-solaris* *-*-cygwin *-*-darwin* alpha*-*-osf* } } +// { dg-options "-pthread" { target *-*-freebsd* *-*-netbsd* *-*-linux* alpha*-*-osf* } } +// { dg-options "-pthreads" { target *-*-solaris* } } + +// Copyright (C) 2004 Free Software Foundation +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. + +// 22.1.1.2 locale constructors and destructors [lib.locale.cons] + +#include <locale> +#include <pthread.h> + +const int max_thread_count = 20; +//const int max_loop_count = 1000000; // orig value +const int max_loop_count = 100000; +const int max_locales = 10; + +void* thread_main(void*) +{ + try + { + std::locale loc_c = std::locale::classic(); + std::locale loc[max_locales]; + for (int j = 0; j < max_locales; ++j) + loc[j] = std::locale(j % 2 ? "en_US" : "fr_FR"); + + for (int i = 0; i < max_loop_count; ++i) + { + int k = i % max_locales; + loc[k] = std::locale::global(loc[k]); + + if (i % 37 == 0) + loc[k] = loc[k].combine<std::ctype<char> >(loc_c); + } + } + catch (...) { } + return 0; +} + +int +main() +{ + pthread_t tid[max_thread_count]; + + for (int i = 0; i < max_thread_count; i++) + pthread_create (&tid[i], NULL, thread_main, 0); + + for (int i = 0; i < max_thread_count; i++) + pthread_join (tid[i], NULL); + + return 0; +} diff --git a/libstdc++-v3/testsuite/22_locale/money_get/get/char/18.cc b/libstdc++-v3/testsuite/22_locale/money_get/get/char/18.cc new file mode 100644 index 00000000000..3da65de43d1 --- /dev/null +++ b/libstdc++-v3/testsuite/22_locale/money_get/get/char/18.cc @@ -0,0 +1,69 @@ +// 2004-03-15 Paolo Carlini <pcarlini@suse.de> + +// Copyright (C) 2004 Free Software Foundation +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. + +// 22.2.6.1.1 money_get members + +#include <locale> +#include <sstream> +#include <testsuite_hooks.h> + +// If (str.flags() & str.showbase) is false, the currency symbol is optional, +// but, if found, must be consumed entirely. +void test01() +{ + using namespace std; + typedef istreambuf_iterator<char> iterator_type; + + bool test __attribute__((unused)) = true; + + // basic construction + locale loc_c = locale::classic(); + locale loc_hk = __gnu_test::try_named_locale("en_HK"); + VERIFY( loc_c != loc_hk ); + + iterator_type end, end01, end02; + istringstream iss; + iss.imbue(loc_hk); + // cache the money_get facet + const money_get<char>& mon_get = + use_facet<money_get<char> >(iss.getloc()); + + iss.str("HK7,200,000,000.00"); + iterator_type is_it01(iss); + string result01; + ios_base::iostate err01 = ios_base::goodbit; + end01 = mon_get.get(is_it01, end, false, iss, err01, result01); + VERIFY( err01 == ios_base::failbit ); + VERIFY( *end01 == '7' ); + + iss.str("(HK100,000,000,000.00)"); + iterator_type is_it02(iss); + string result02; + ios_base::iostate err02 = ios_base::goodbit; + end02 = mon_get.get(is_it02, end, true, iss, err02, result02); + VERIFY( err02 == ios_base::failbit ); + VERIFY( *end02 == '1' ); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/22_locale/money_get/get/char/19.cc b/libstdc++-v3/testsuite/22_locale/money_get/get/char/19.cc new file mode 100644 index 00000000000..5d9dea2be1e --- /dev/null +++ b/libstdc++-v3/testsuite/22_locale/money_get/get/char/19.cc @@ -0,0 +1,125 @@ +// 2004-03-15 Paolo Carlini <pcarlini@suse.de> + +// Copyright (C) 2004 Free Software Foundation +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. + +// 22.2.6.1.1 money_get members + +#include <locale> +#include <sstream> +#include <testsuite_hooks.h> + +struct My_money_io_01 : public std::moneypunct<char, false> +{ + std::string do_curr_symbol() const { return "$"; } + std::string do_positive_sign() const { return ""; } + std::string do_negative_sign() const { return ""; } + + pattern do_neg_format() const + { + pattern pat = { { value, symbol, none, sign } }; + return pat; + } +}; + +struct My_money_io_02 : public std::moneypunct<char, false> +{ + std::string do_curr_symbol() const { return "%"; } + std::string do_positive_sign() const { return ""; } + std::string do_negative_sign() const { return "-"; } + + pattern do_neg_format() const + { + pattern pat = { { value, symbol, sign, none } }; + return pat; + } +}; + +struct My_money_io_03 : public std::moneypunct<char, false> +{ + std::string do_curr_symbol() const { return "&"; } + std::string do_positive_sign() const { return ""; } + std::string do_negative_sign() const { return ""; } + + pattern do_neg_format() const + { + pattern pat = { { value, space, symbol, sign } }; + return pat; + } +}; + +// When both do_positive_sign and do_negative_sign return an empty +// string, patterns of the forms { value, symbol, none, sign }, +// { value, symbol, sign, none } and { X, Y, symbol, sign } imply +// that the symbol is not consumed since no other characters are +// needed to complete the format. +void test01() +{ + using namespace std; + typedef istreambuf_iterator<char> iterator_type; + + bool test __attribute__((unused)) = true; + + // basic construction + locale loc_01(locale::classic(), new My_money_io_01); + locale loc_02(locale::classic(), new My_money_io_02); + locale loc_03(locale::classic(), new My_money_io_03); + + iterator_type end, end01, end02, end03; + istringstream iss_01, iss_02, iss_03; + iss_01.imbue(loc_01); + iss_02.imbue(loc_02); + iss_03.imbue(loc_03); + // cache the money_get facet + const money_get<char>& mon_get_01 = + use_facet<money_get<char> >(iss_01.getloc()); + const money_get<char>& mon_get_02 = + use_facet<money_get<char> >(iss_02.getloc()); + const money_get<char>& mon_get_03 = + use_facet<money_get<char> >(iss_03.getloc()); + + iss_01.str("10$"); + iterator_type is_it01(iss_01); + string result01; + ios_base::iostate err01 = ios_base::goodbit; + end01 = mon_get_01.get(is_it01, end, false, iss_01, err01, result01); + VERIFY( err01 == ios_base::goodbit ); + VERIFY( *end01 == '$' ); + + iss_02.str("50%"); + iterator_type is_it02(iss_02); + string result02; + ios_base::iostate err02 = ios_base::goodbit; + end02 = mon_get_02.get(is_it02, end, false, iss_02, err02, result02); + VERIFY( err02 == ios_base::goodbit ); + VERIFY( *end02 == '%' ); + + iss_03.str("7 &"); + iterator_type is_it03(iss_03); + string result03; + ios_base::iostate err03 = ios_base::goodbit; + end03 = mon_get_03.get(is_it03, end, false, iss_03, err03, result03); + VERIFY( err03 == ios_base::goodbit ); + VERIFY( *end03 == '&' ); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/22_locale/money_get/get/wchar_t/18.cc b/libstdc++-v3/testsuite/22_locale/money_get/get/wchar_t/18.cc new file mode 100644 index 00000000000..285de236276 --- /dev/null +++ b/libstdc++-v3/testsuite/22_locale/money_get/get/wchar_t/18.cc @@ -0,0 +1,69 @@ +// 2004-03-15 Paolo Carlini <pcarlini@suse.de> + +// Copyright (C) 2004 Free Software Foundation +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. + +// 22.2.6.1.1 money_get members + +#include <locale> +#include <sstream> +#include <testsuite_hooks.h> + +// If (str.flags() & str.showbase) is false, the currency symbol is optional, +// but, if found, must be consumed entirely. +void test01() +{ + using namespace std; + typedef istreambuf_iterator<wchar_t> iterator_type; + + bool test __attribute__((unused)) = true; + + // basic construction + locale loc_c = locale::classic(); + locale loc_hk = __gnu_test::try_named_locale("en_HK"); + VERIFY( loc_c != loc_hk ); + + iterator_type end, end01, end02; + wistringstream iss; + iss.imbue(loc_hk); + // cache the money_get facet + const money_get<wchar_t>& mon_get = + use_facet<money_get<wchar_t> >(iss.getloc()); + + iss.str(L"HK7,200,000,000.00"); + iterator_type is_it01(iss); + wstring result01; + ios_base::iostate err01 = ios_base::goodbit; + end01 = mon_get.get(is_it01, end, false, iss, err01, result01); + VERIFY( err01 == ios_base::failbit ); + VERIFY( *end01 == L'7' ); + + iss.str(L"(HK100,000,000,000.00)"); + iterator_type is_it02(iss); + wstring result02; + ios_base::iostate err02 = ios_base::goodbit; + end02 = mon_get.get(is_it02, end, true, iss, err02, result02); + VERIFY( err02 == ios_base::failbit ); + VERIFY( *end02 == L'1' ); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/22_locale/money_get/get/wchar_t/19.cc b/libstdc++-v3/testsuite/22_locale/money_get/get/wchar_t/19.cc new file mode 100644 index 00000000000..93c63e6ea29 --- /dev/null +++ b/libstdc++-v3/testsuite/22_locale/money_get/get/wchar_t/19.cc @@ -0,0 +1,125 @@ +// 2004-03-15 Paolo Carlini <pcarlini@suse.de> + +// Copyright (C) 2004 Free Software Foundation +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. + +// 22.2.6.1.1 money_get members + +#include <locale> +#include <sstream> +#include <testsuite_hooks.h> + +struct My_money_io_01 : public std::moneypunct<wchar_t, false> +{ + std::wstring do_curr_symbol() const { return L"$"; } + std::wstring do_positive_sign() const { return L""; } + std::wstring do_negative_sign() const { return L""; } + + pattern do_neg_format() const + { + pattern pat = { { value, symbol, none, sign } }; + return pat; + } +}; + +struct My_money_io_02 : public std::moneypunct<wchar_t, false> +{ + std::wstring do_curr_symbol() const { return L"%"; } + std::wstring do_positive_sign() const { return L""; } + std::wstring do_negative_sign() const { return L"-"; } + + pattern do_neg_format() const + { + pattern pat = { { value, symbol, sign, none } }; + return pat; + } +}; + +struct My_money_io_03 : public std::moneypunct<wchar_t, false> +{ + std::wstring do_curr_symbol() const { return L"&"; } + std::wstring do_positive_sign() const { return L""; } + std::wstring do_negative_sign() const { return L""; } + + pattern do_neg_format() const + { + pattern pat = { { value, space, symbol, sign } }; + return pat; + } +}; + +// When both do_positive_sign and do_negative_sign return an empty +// string, patterns of the forms { value, symbol, none, sign }, +// { value, symbol, sign, none } and { X, Y, symbol, sign } imply +// that the symbol is not consumed since no other characters are +// needed to complete the format. +void test01() +{ + using namespace std; + typedef istreambuf_iterator<wchar_t> iterator_type; + + bool test __attribute__((unused)) = true; + + // basic construction + locale loc_01(locale::classic(), new My_money_io_01); + locale loc_02(locale::classic(), new My_money_io_02); + locale loc_03(locale::classic(), new My_money_io_03); + + iterator_type end, end01, end02, end03; + wistringstream iss_01, iss_02, iss_03; + iss_01.imbue(loc_01); + iss_02.imbue(loc_02); + iss_03.imbue(loc_03); + // cache the money_get facet + const money_get<wchar_t>& mon_get_01 = + use_facet<money_get<wchar_t> >(iss_01.getloc()); + const money_get<wchar_t>& mon_get_02 = + use_facet<money_get<wchar_t> >(iss_02.getloc()); + const money_get<wchar_t>& mon_get_03 = + use_facet<money_get<wchar_t> >(iss_03.getloc()); + + iss_01.str(L"10$"); + iterator_type is_it01(iss_01); + wstring result01; + ios_base::iostate err01 = ios_base::goodbit; + end01 = mon_get_01.get(is_it01, end, false, iss_01, err01, result01); + VERIFY( err01 == ios_base::goodbit ); + VERIFY( *end01 == L'$' ); + + iss_02.str(L"50%"); + iterator_type is_it02(iss_02); + wstring result02; + ios_base::iostate err02 = ios_base::goodbit; + end02 = mon_get_02.get(is_it02, end, false, iss_02, err02, result02); + VERIFY( err02 == ios_base::goodbit ); + VERIFY( *end02 == L'%' ); + + iss_03.str(L"7 &"); + iterator_type is_it03(iss_03); + wstring result03; + ios_base::iostate err03 = ios_base::goodbit; + end03 = mon_get_03.get(is_it03, end, false, iss_03, err03, result03); + VERIFY( err03 == ios_base::goodbit ); + VERIFY( *end03 == L'&' ); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/deque/modifiers/swap.cc b/libstdc++-v3/testsuite/23_containers/deque/modifiers/swap.cc new file mode 100644 index 00000000000..43dc6867d3d --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/deque/modifiers/swap.cc @@ -0,0 +1,68 @@ +// Copyright (C) 2004 Free Software Foundation +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. + +#include <deque> +#include <testsuite_hooks.h> + +struct T { int i; }; + +int swap_calls; + +namespace std +{ + template<> + void + deque<T, allocator<T> >::swap(deque<T, allocator<T> >&) + { ++swap_calls; } +} + +// Should use deque specialization for swap. +void test01() +{ + bool test __attribute__((unused)) = true; + std::deque<T> A; + std::deque<T> B; + swap_calls = 0; + std::swap(A, B); + VERIFY(1 == swap_calls); +} + +// Should use deque specialization for swap. +void test02() +{ + bool test __attribute__((unused)) = true; + using namespace std; + deque<T> A; + deque<T> B; + swap_calls = 0; + swap(A, B); + VERIFY(1 == swap_calls); +} + +#if !__GXX_WEAK__ && _MT_ALLOCATOR_H +template class __gnu_cxx::__mt_alloc<T>; +template class __gnu_cxx::__mt_alloc<T*>; +#endif + +// See c++/13658 for background info. +int main() +{ + test01(); + test02(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/list/modifiers/swap.cc b/libstdc++-v3/testsuite/23_containers/list/modifiers/swap.cc new file mode 100644 index 00000000000..a51d1263fb4 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/list/modifiers/swap.cc @@ -0,0 +1,67 @@ +// Copyright (C) 2004 Free Software Foundation +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. + +#include <list> +#include <testsuite_hooks.h> + +struct T { int i; }; + +int swap_calls; + +namespace std +{ + template<> + void + list<T, allocator<T> >::swap(list<T, allocator<T> >&) + { ++swap_calls; } +} + +// Should use list specialization for swap. +void test01() +{ + bool test __attribute__((unused)) = true; + std::list<T> A; + std::list<T> B; + swap_calls = 0; + std::swap(A, B); + VERIFY(1 == swap_calls); +} + +// Should use list specialization for swap. +void test02() +{ + bool test __attribute__((unused)) = true; + using namespace std; + list<T> A; + list<T> B; + swap_calls = 0; + swap(A, B); + VERIFY(1 == swap_calls); +} + +#if !__GXX_WEAK__ && _MT_ALLOCATOR_H +template class __gnu_cxx::__mt_alloc<std::_List_node<T> >; +#endif + +// See c++/13658 for background info. +int main() +{ + test01(); + test02(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/map/modifiers/swap.cc b/libstdc++-v3/testsuite/23_containers/map/modifiers/swap.cc new file mode 100644 index 00000000000..1afde71dd8a --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/map/modifiers/swap.cc @@ -0,0 +1,67 @@ +// Copyright (C) 2004 Free Software Foundation +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. + +#include <map> +#include <testsuite_hooks.h> + +struct T { int i; }; + +int swap_calls; + +namespace std +{ + template<> + void + map<T, int>::swap(map<T, int>&) + { ++swap_calls; } +} + +// Should use map specialization for swap. +void test01() +{ + bool test __attribute__((unused)) = true; + std::map<T, int> A; + std::map<T, int> B; + swap_calls = 0; + std::swap(A, B); + VERIFY(1 == swap_calls); +} + +// Should use map specialization for swap. +void test02() +{ + bool test __attribute__((unused)) = true; + using namespace std; + map<T, int> A; + map<T, int> B; + swap_calls = 0; + swap(A, B); + VERIFY(1 == swap_calls); +} + +#if !__GXX_WEAK__ && _MT_ALLOCATOR_H +template class __gnu_cxx::__mt_alloc<std::_Rb_tree_node<std::pair<T const, int> > >; +#endif + +// See c++/13658 for background info. +int main() +{ + test01(); + test02(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/multimap/modifiers/swap.cc b/libstdc++-v3/testsuite/23_containers/multimap/modifiers/swap.cc new file mode 100644 index 00000000000..2e87dff1632 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/multimap/modifiers/swap.cc @@ -0,0 +1,67 @@ +// Copyright (C) 2004 Free Software Foundation +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. + +#include <map> +#include <testsuite_hooks.h> + +struct T { int i; }; + +int swap_calls; + +namespace std +{ + template<> + void + multimap<T, int>::swap(multimap<T, int>&) + { ++swap_calls; } +} + +// Should use multimap specialization for swap. +void test01() +{ + bool test __attribute__((unused)) = true; + std::multimap<T, int> A; + std::multimap<T, int> B; + swap_calls = 0; + std::swap(A, B); + VERIFY(1 == swap_calls); +} + +// Should use multimap specialization for swap. +void test02() +{ + bool test __attribute__((unused)) = true; + using namespace std; + multimap<T, int> A; + multimap<T, int> B; + swap_calls = 0; + swap(A, B); + VERIFY(1 == swap_calls); +} + +#if !__GXX_WEAK__ && _MT_ALLOCATOR_H +template class __gnu_cxx::__mt_alloc<std::_Rb_tree_node<std::pair<T const, int> > >; +#endif + +// See c++/13658 for background info. +int main() +{ + test01(); + test02(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/multiset/modifiers/swap.cc b/libstdc++-v3/testsuite/23_containers/multiset/modifiers/swap.cc new file mode 100644 index 00000000000..b9632cb88ae --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/multiset/modifiers/swap.cc @@ -0,0 +1,67 @@ +// Copyright (C) 2004 Free Software Foundation +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. + +#include <set> +#include <testsuite_hooks.h> + +struct T { int i; }; + +int swap_calls; + +namespace std +{ + template<> + void + multiset<T>::swap(multiset<T>&) + { ++swap_calls; } +} + +// Should use multiset specialization for swap. +void test01() +{ + bool test __attribute__((unused)) = true; + std::multiset<T> A; + std::multiset<T> B; + swap_calls = 0; + std::swap(A, B); + VERIFY(1 == swap_calls); +} + +// Should use multiset specialization for swap. +void test02() +{ + bool test __attribute__((unused)) = true; + using namespace std; + multiset<T> A; + multiset<T> B; + swap_calls = 0; + swap(A, B); + VERIFY(1 == swap_calls); +} + +#if !__GXX_WEAK__ && _MT_ALLOCATOR_H +template class __gnu_cxx::__mt_alloc<std::_Rb_tree_node<T> >; +#endif + +// See c++/13658 for background info. +int main() +{ + test01(); + test02(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/set/modifiers/swap.cc b/libstdc++-v3/testsuite/23_containers/set/modifiers/swap.cc new file mode 100644 index 00000000000..dcc69c99b3a --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/set/modifiers/swap.cc @@ -0,0 +1,67 @@ +// Copyright (C) 2004 Free Software Foundation +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. + +#include <set> +#include <testsuite_hooks.h> + +struct T { int i; }; + +int swap_calls; + +namespace std +{ + template<> + void + set<T>::swap(set<T>&) + { ++swap_calls; } +} + +// Should use set specialization for swap. +void test01() +{ + bool test __attribute__((unused)) = true; + std::set<T> A; + std::set<T> B; + swap_calls = 0; + std::swap(A, B); + VERIFY(1 == swap_calls); +} + +// Should use set specialization for swap. +void test02() +{ + bool test __attribute__((unused)) = true; + using namespace std; + set<T> A; + set<T> B; + swap_calls = 0; + swap(A, B); + VERIFY(1 == swap_calls); +} + +#if !__GXX_WEAK__ && _MT_ALLOCATOR_H +template class __gnu_cxx::__mt_alloc<std::_Rb_tree_node<T> >; +#endif + +// See c++/13658 for background info. +int main() +{ + test01(); + test02(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/vector/modifiers/swap.cc b/libstdc++-v3/testsuite/23_containers/vector/modifiers/swap.cc new file mode 100644 index 00000000000..4e49635bc22 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/modifiers/swap.cc @@ -0,0 +1,67 @@ +// Copyright (C) 2004 Free Software Foundation +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. + +#include <vector> +#include <testsuite_hooks.h> + +struct T { int i; }; + +int swap_calls; + +namespace std +{ + template<> + void + vector<T, allocator<T> >::swap(vector<T, allocator<T> >&) + { ++swap_calls; } +} + +// Should use vector specialization for swap. +void test01() +{ + bool test __attribute__((unused)) = true; + std::vector<T> A; + std::vector<T> B; + swap_calls = 0; + std::swap(A, B); + VERIFY(1 == swap_calls); +} + +// Should use vector specialization for swap. +void test02() +{ + bool test __attribute__((unused)) = true; + using namespace std; + vector<T> A; + vector<T> B; + swap_calls = 0; + swap(A, B); + VERIFY(1 == swap_calls); +} + +#if !__GXX_WEAK__ && _MT_ALLOCATOR_H +template class __gnu_cxx::__mt_alloc<T>; +#endif + +// See c++/13658 for background info. +int main() +{ + test01(); + test02(); + return 0; +} diff --git a/libstdc++-v3/testsuite/26_numerics/cmath/overloads.cc b/libstdc++-v3/testsuite/26_numerics/cmath/overloads.cc new file mode 100644 index 00000000000..4d41a9640b4 --- /dev/null +++ b/libstdc++-v3/testsuite/26_numerics/cmath/overloads.cc @@ -0,0 +1,27 @@ +// PR 3181 +// Origin: pete@toyon.com + +#include <cmath> + +int main() +{ + int i = -1; + int j = 9; + double ans; + ans = std::acos(i); + ans = std::asin(i); + ans = std::atan(i); + ans = std::atan2(i, j); + ans = std::cos(i); + ans = std::cosh(i); + ans = std::exp(i); + ans = std::fabs(i); + ans = std::floor(i); + ans = std::log(i); + ans = std::log10(i); + ans = std::sqrt(i); + ans = std::sin(i); + ans = std::sinh(j); + ans = std::tan(i); + ans = std::tanh(i); +} diff --git a/libstdc++-v3/testsuite/26_numerics/complex/13450.cc b/libstdc++-v3/testsuite/26_numerics/complex/13450.cc new file mode 100644 index 00000000000..50f4bad3b93 --- /dev/null +++ b/libstdc++-v3/testsuite/26_numerics/complex/13450.cc @@ -0,0 +1,75 @@ +// Copyright (C) 2004 Free Software Foundation +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. + +// 26.2.8 complex transcendentals + +#include <complex> +#include <limits> +#include <testsuite_hooks.h> + +template<typename T> + void test01_do(T a, T b) + { + using namespace std; + bool test __attribute__((unused)) = true; + typedef complex<T> cplx; + + T eps = numeric_limits<T>::epsilon() * 100; + + cplx ref = pow(cplx(a, T()), cplx(b, T())); + cplx res1 = pow(a, cplx(b, T())); + cplx res2 = pow(cplx(a, T()), b); + + VERIFY( abs(ref - res1) < eps ); + VERIFY( abs(ref - res2) < eps ); + VERIFY( abs(res1 - res2) < eps ); + } + +// libstdc++/13450 +void test01() +{ + float f1 = -1.0f; + float f2 = 0.5f; + test01_do(f1, f2); + + f1 = -3.2f; + f2 = 1.4f; + test01_do(f1, f2); + + double d1 = -1.0; + double d2 = 0.5; + test01_do(d1, d2); + + d1 = -3.2; + d2 = 1.4; + test01_do(d1, d2); + + long double ld1 = -1.0l; + long double ld2 = 0.5l; + test01_do(ld1, ld2); + + ld1 = -3.2l; + ld2 = 1.4l; + test01_do(ld1, ld2); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/26_numerics/complex/pow.cc b/libstdc++-v3/testsuite/26_numerics/complex/pow.cc new file mode 100644 index 00000000000..58d0fc5909b --- /dev/null +++ b/libstdc++-v3/testsuite/26_numerics/complex/pow.cc @@ -0,0 +1,14 @@ +// PR libbstdc++/10689 +// Origin: Daniel.Levine@jhuaph.edu + +#include <complex> +#include <testsuite_hooks.h> + +int main() +{ + std::complex<double> z; + + VERIFY( pow(z, 1.0/3.0) == 0.0 ); + + return 0; +} diff --git a/libstdc++-v3/testsuite/26_numerics/valarray_subset_assignment.cc b/libstdc++-v3/testsuite/26_numerics/valarray_subset_assignment.cc new file mode 100644 index 00000000000..9298bfb046f --- /dev/null +++ b/libstdc++-v3/testsuite/26_numerics/valarray_subset_assignment.cc @@ -0,0 +1,88 @@ +// 2004-01-03 Jerry Quinn <jlquinn@optonline.net> + +// Copyright (C) 2004 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. + +// As a special exception, you may use this file as part of a free software +// library without restriction. Specifically, if other files instantiate +// templates or use macros or inline functions from this file, or you compile +// this file and link it with other files to produce an executable, this +// file does not by itself cause the resulting executable to be covered by +// the GNU General Public License. This exception does not however +// invalidate any other reasons why the executable file might be covered by +// the GNU General Public License. + +// PR 3247 + +// This is DR-253. Test for accessible assignment-operators. +#include <valarray> +#include <testsuite_hooks.h> + +bool check_array(std::valarray<double>& a, double b[]) +{ + for (int i=0; i < a.size(); i++) + if (a[i] != b[i]) return false; + return true; +} + +int main() +{ + double dvar = 1.0; + std::valarray<double> val_d(10); // 0 1 2 3 4 5 6 7 8 9 + std::valarray<double> val_d1(10); // 10 9 8 7 6 5 4 3 2 1 + + for (int i=0; i< 10; i++) { val_d[i] = 10; val_d1[i] = i; } + std::valarray<double> val_c(val_d); + std::valarray<double> val_f(val_d); + std::valarray<double> val_g(val_d); + + std::slice slc(1, 3, 3); // 1 4 7 + val_d[slc] = val_d1[slc]; + + double ans1[10] = {10, 1, 10, 10, 4, 10, 10, 7, 10, 10}; + VERIFY(check_array(val_d, ans1)); + + std::valarray<std::size_t> val_size(2); + std::valarray<std::size_t> val_stride(2); + val_size[0] = 2; val_size[1] = 3; + val_stride[0] = 4; val_stride[1] = 1; + + std::gslice gslc(1, val_size, val_stride); + val_c[gslc] = val_d1[gslc]; + + double ans2[10] = {10, 1, 2, 3, 10, 5, 6, 7, 10, 10}; + VERIFY(check_array(val_c, ans2)); + + std::valarray<bool> val_b(false, 10); + val_b[2] = val_b[6] = val_b[9] = true; + val_f[val_b] = val_d1[val_b]; + + double ans3[10] = {10, 10, 2, 10, 10, 10, 6, 10, 10, 9}; + VERIFY(check_array(val_f, ans3)); + + size_t addr[] = {1, 2, 3, 4, 5}; + size_t addr1[] = {2, 7, 1, 9, 4}; + std::valarray<std::size_t> val_indirect(addr, 5); + std::valarray<std::size_t> val_indirect1(addr1, 5); + val_g[val_indirect] = val_d1[val_indirect1]; + + double ans4[10] = {10, 2, 7, 1, 9, 4, 10, 10, 10, 10}; + VERIFY(check_array(val_g, ans4)); + + return 0; +}; |