diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/abaco |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/abaco')
-rwxr-xr-x | sys/src/cmd/abaco/NOTES | 14 | ||||
-rwxr-xr-x | sys/src/cmd/abaco/abaco.fonts | 20 | ||||
-rwxr-xr-x | sys/src/cmd/abaco/charsets.awk | 36 | ||||
-rwxr-xr-x | sys/src/cmd/abaco/charsets.txt | 1868 | ||||
-rwxr-xr-x | sys/src/cmd/abaco/cols.c | 549 | ||||
-rwxr-xr-x | sys/src/cmd/abaco/dat.h | 355 | ||||
-rwxr-xr-x | sys/src/cmd/abaco/exec.c | 531 | ||||
-rwxr-xr-x | sys/src/cmd/abaco/fns.h | 85 | ||||
-rwxr-xr-x | sys/src/cmd/abaco/fonts.h | 20 | ||||
-rwxr-xr-x | sys/src/cmd/abaco/html.c | 1072 | ||||
-rwxr-xr-x | sys/src/cmd/abaco/main.c | 433 | ||||
-rwxr-xr-x | sys/src/cmd/abaco/mkfile | 52 | ||||
-rwxr-xr-x | sys/src/cmd/abaco/page.c | 839 | ||||
-rwxr-xr-x | sys/src/cmd/abaco/plumbing | 10 | ||||
-rwxr-xr-x | sys/src/cmd/abaco/rows.c | 252 | ||||
-rwxr-xr-x | sys/src/cmd/abaco/scrl.c | 317 | ||||
-rwxr-xr-x | sys/src/cmd/abaco/tabs.c | 332 | ||||
-rwxr-xr-x | sys/src/cmd/abaco/tcs.h | 167 | ||||
-rwxr-xr-x | sys/src/cmd/abaco/tcs.txt | 58 | ||||
-rwxr-xr-x | sys/src/cmd/abaco/text.c | 880 | ||||
-rwxr-xr-x | sys/src/cmd/abaco/time.c | 119 | ||||
-rwxr-xr-x | sys/src/cmd/abaco/urls.c | 230 | ||||
-rwxr-xr-x | sys/src/cmd/abaco/util.c | 1293 | ||||
-rwxr-xr-x | sys/src/cmd/abaco/wind.c | 383 |
24 files changed, 9915 insertions, 0 deletions
diff --git a/sys/src/cmd/abaco/NOTES b/sys/src/cmd/abaco/NOTES new file mode 100755 index 000000000..bc852c14d --- /dev/null +++ b/sys/src/cmd/abaco/NOTES @@ -0,0 +1,14 @@ +Bugs: + * fix text selection and double clicking; + +Not Bugs: + * complaints like "gif: decode <stdin> failed: ReadGIF: can't recognize format ��" + are caused by sites that return a jpeg and send Content-Type: image/gif. + +Not implented: + * frame's borders and scroll are ignored + * Image: maps + * table atributes + * css + * Js + diff --git a/sys/src/cmd/abaco/abaco.fonts b/sys/src/cmd/abaco/abaco.fonts new file mode 100755 index 000000000..5c467449c --- /dev/null +++ b/sys/src/cmd/abaco/abaco.fonts @@ -0,0 +1,20 @@ +/lib/font/bit/freefont/sans/sans.12.font +/lib/font/bit/freefont/sans/sans.13.font +/lib/font/bit/freefont/sans/sans.15.font +/lib/font/bit/freefont/sans/sans.18.font +/lib/font/bit/freefont/sans/sans.20.font +/lib/font/bit/freefont/sansi/sansi.12.font +/lib/font/bit/freefont/sansi/sansi.13.font +/lib/font/bit/freefont/sansi/sansi.15.font +/lib/font/bit/freefont/sansi/sansi.18.font +/lib/font/bit/freefont/sansi/sansi.20.font +/lib/font/bit/freefont/sansbd/sansbd.12.font +/lib/font/bit/freefont/sansbd/sansbd.13.font +/lib/font/bit/freefont/sansbd/sansbd.15.font +/lib/font/bit/freefont/sansbd/sansbd.18.font +/lib/font/bit/freefont/sansbd/sansbd.20.font +/lib/font/bit/freefont/mono/mono.12.font +/lib/font/bit/freefont/mono/mono.13.font +/lib/font/bit/freefont/mono/mono.15.font +/lib/font/bit/freefont/mono/mono.18.font +/lib/font/bit/freefont/mono/mono.20.font diff --git a/sys/src/cmd/abaco/charsets.awk b/sys/src/cmd/abaco/charsets.awk new file mode 100755 index 000000000..e822f80e8 --- /dev/null +++ b/sys/src/cmd/abaco/charsets.awk @@ -0,0 +1,36 @@ +#!/bin/awk -f +# makes a table of character sets from http://www.iana.org/assignments/character-sets +# and tcs.txt + +BEGIN{ + if(ARGC != 3){ + print "Usage: " ARGV[0] " charsets.txt tcs.txt" + exit 1 + } + while(getline<ARGV[1]){ + if(/^Name:/){ + i = 0 + name=tolower($2) + names[name] = name + alias[name i] = name + nalias[name] = ++i + + } + if(/^Alias:/){ + a = tolower($2) + if(a != "none"){ + names[a] = name + alias[name i ] = a + nalias[name] = ++i + } + } + } +} +{ + tcs = $1 + if(tcs in names){ + name = names[tcs] + for(i=0; i<nalias[name]; i++) + print "\"" alias[name i] "\", \"" $2 "\"," + } +} diff --git a/sys/src/cmd/abaco/charsets.txt b/sys/src/cmd/abaco/charsets.txt new file mode 100755 index 000000000..350858a82 --- /dev/null +++ b/sys/src/cmd/abaco/charsets.txt @@ -0,0 +1,1868 @@ + +=================================================================== +CHARACTER SETS + +(last updated 28 January 2005) + +These are the official names for character sets that may be used in +the Internet and may be referred to in Internet documentation. These +names are expressed in ANSI_X3.4-1968 which is commonly called +US-ASCII or simply ASCII. The character set most commonly use in the +Internet and used especially in protocol standards is US-ASCII, this +is strongly encouraged. The use of the name US-ASCII is also +encouraged. + +The character set names may be up to 40 characters taken from the +printable characters of US-ASCII. However, no distinction is made +between use of upper and lower case letters. + +The MIBenum value is a unique value for use in MIBs to identify coded +character sets. + +The value space for MIBenum values has been divided into three +regions. The first region (3-999) consists of coded character sets +that have been standardized by some standard setting organization. +This region is intended for standards that do not have subset +implementations. The second region (1000-1999) is for the Unicode and +ISO/IEC 10646 coded character sets together with a specification of a +(set of) sub-repertoires that may occur. The third region (>1999) is +intended for vendor specific coded character sets. + + Assigned MIB enum Numbers + ------------------------- + 0-2 Reserved + 3-999 Set By Standards Organizations + 1000-1999 Unicode / 10646 + 2000-2999 Vendor + +The aliases that start with "cs" have been added for use with the +IANA-CHARSET-MIB as originally defined in RFC3808, and as currently +maintained by IANA at http://www.iana.org/assignments/ianacharset-mib. +Note that the ianacharset-mib needs to be kept in sync with this +registry. These aliases that start with "cs" contain the standard +numbers along with suggestive names in order to facilitate applications +that want to display the names in user interfaces. The "cs" stands +for character set and is provided for applications that need a lower +case first letter but want to use mixed case thereafter that cannot +contain any special characters, such as underbar ("_") and dash ("-"). + +If the character set is from an ISO standard, its cs alias is the ISO +standard number or name. If the character set is not from an ISO +standard, but is registered with ISO (IPSJ/ITSCJ is the current ISO +Registration Authority), the ISO Registry number is specified as +ISOnnn followed by letters suggestive of the name or standards number +of the code set. When a national or international standard is +revised, the year of revision is added to the cs alias of the new +character set entry in the IANA Registry in order to distinguish the +revised character set from the original character set. + + +Character Set Reference +------------- --------- + +Name: ANSI_X3.4-1968 [RFC1345,KXS2] +MIBenum: 3 +Source: ECMA registry +Alias: iso-ir-6 +Alias: ANSI_X3.4-1986 +Alias: ISO_646.irv:1991 +Alias: ASCII +Alias: ISO646-US +Alias: US-ASCII (preferred MIME name) +Alias: us +Alias: IBM367 +Alias: cp367 +Alias: csASCII + +Name: ISO-10646-UTF-1 +MIBenum: 27 +Source: Universal Transfer Format (1), this is the multibyte + encoding, that subsets ASCII-7. It does not have byte + ordering issues. +Alias: csISO10646UTF1 + +Name: ISO_646.basic:1983 [RFC1345,KXS2] +MIBenum: 28 +Source: ECMA registry +Alias: ref +Alias: csISO646basic1983 + +Name: INVARIANT [RFC1345,KXS2] +MIBenum: 29 +Alias: csINVARIANT + +Name: ISO_646.irv:1983 [RFC1345,KXS2] +MIBenum: 30 +Source: ECMA registry +Alias: iso-ir-2 +Alias: irv +Alias: csISO2IntlRefVersion + +Name: BS_4730 [RFC1345,KXS2] +MIBenum: 20 +Source: ECMA registry +Alias: iso-ir-4 +Alias: ISO646-GB +Alias: gb +Alias: uk +Alias: csISO4UnitedKingdom + +Name: NATS-SEFI [RFC1345,KXS2] +MIBenum: 31 +Source: ECMA registry +Alias: iso-ir-8-1 +Alias: csNATSSEFI + +Name: NATS-SEFI-ADD [RFC1345,KXS2] +MIBenum: 32 +Source: ECMA registry +Alias: iso-ir-8-2 +Alias: csNATSSEFIADD + +Name: NATS-DANO [RFC1345,KXS2] +MIBenum: 33 +Source: ECMA registry +Alias: iso-ir-9-1 +Alias: csNATSDANO + +Name: NATS-DANO-ADD [RFC1345,KXS2] +MIBenum: 34 +Source: ECMA registry +Alias: iso-ir-9-2 +Alias: csNATSDANOADD + +Name: SEN_850200_B [RFC1345,KXS2] +MIBenum: 35 +Source: ECMA registry +Alias: iso-ir-10 +Alias: FI +Alias: ISO646-FI +Alias: ISO646-SE +Alias: se +Alias: csISO10Swedish + +Name: SEN_850200_C [RFC1345,KXS2] +MIBenum: 21 +Source: ECMA registry +Alias: iso-ir-11 +Alias: ISO646-SE2 +Alias: se2 +Alias: csISO11SwedishForNames + +Name: KS_C_5601-1987 [RFC1345,KXS2] +MIBenum: 36 +Source: ECMA registry +Alias: iso-ir-149 +Alias: KS_C_5601-1989 +Alias: KSC_5601 +Alias: korean +Alias: csKSC56011987 + +Name: ISO-2022-KR (preferred MIME name) [RFC1557,Choi] +MIBenum: 37 +Source: RFC-1557 (see also KS_C_5601-1987) +Alias: csISO2022KR + +Name: EUC-KR (preferred MIME name) [RFC1557,Choi] +MIBenum: 38 +Source: RFC-1557 (see also KS_C_5861-1992) +Alias: csEUCKR + +Name: ISO-2022-JP (preferred MIME name) [RFC1468,Murai] +MIBenum: 39 +Source: RFC-1468 (see also RFC-2237) +Alias: csISO2022JP + +Name: ISO-2022-JP-2 (preferred MIME name) [RFC1554,Ohta] +MIBenum: 40 +Source: RFC-1554 +Alias: csISO2022JP2 + +Name: ISO-2022-CN [RFC1922] +MIBenum: 104 +Source: RFC-1922 + +Name: ISO-2022-CN-EXT [RFC1922] +MIBenum: 105 +Source: RFC-1922 + +Name: JIS_C6220-1969-jp [RFC1345,KXS2] +MIBenum: 41 +Source: ECMA registry +Alias: JIS_C6220-1969 +Alias: iso-ir-13 +Alias: katakana +Alias: x0201-7 +Alias: csISO13JISC6220jp + +Name: JIS_C6220-1969-ro [RFC1345,KXS2] +MIBenum: 42 +Source: ECMA registry +Alias: iso-ir-14 +Alias: jp +Alias: ISO646-JP +Alias: csISO14JISC6220ro + +Name: IT [RFC1345,KXS2] +MIBenum: 22 +Source: ECMA registry +Alias: iso-ir-15 +Alias: ISO646-IT +Alias: csISO15Italian + +Name: PT [RFC1345,KXS2] +MIBenum: 43 +Source: ECMA registry +Alias: iso-ir-16 +Alias: ISO646-PT +Alias: csISO16Portuguese + +Name: ES [RFC1345,KXS2] +MIBenum: 23 +Source: ECMA registry +Alias: iso-ir-17 +Alias: ISO646-ES +Alias: csISO17Spanish + +Name: greek7-old [RFC1345,KXS2] +MIBenum: 44 +Source: ECMA registry +Alias: iso-ir-18 +Alias: csISO18Greek7Old + +Name: latin-greek [RFC1345,KXS2] +MIBenum: 45 +Source: ECMA registry +Alias: iso-ir-19 +Alias: csISO19LatinGreek + +Name: DIN_66003 [RFC1345,KXS2] +MIBenum: 24 +Source: ECMA registry +Alias: iso-ir-21 +Alias: de +Alias: ISO646-DE +Alias: csISO21German + +Name: NF_Z_62-010_(1973) [RFC1345,KXS2] +MIBenum: 46 +Source: ECMA registry +Alias: iso-ir-25 +Alias: ISO646-FR1 +Alias: csISO25French + +Name: Latin-greek-1 [RFC1345,KXS2] +MIBenum: 47 +Source: ECMA registry +Alias: iso-ir-27 +Alias: csISO27LatinGreek1 + +Name: ISO_5427 [RFC1345,KXS2] +MIBenum: 48 +Source: ECMA registry +Alias: iso-ir-37 +Alias: csISO5427Cyrillic + +Name: JIS_C6226-1978 [RFC1345,KXS2] +MIBenum: 49 +Source: ECMA registry +Alias: iso-ir-42 +Alias: csISO42JISC62261978 + +Name: BS_viewdata [RFC1345,KXS2] +MIBenum: 50 +Source: ECMA registry +Alias: iso-ir-47 +Alias: csISO47BSViewdata + +Name: INIS [RFC1345,KXS2] +MIBenum: 51 +Source: ECMA registry +Alias: iso-ir-49 +Alias: csISO49INIS + +Name: INIS-8 [RFC1345,KXS2] +MIBenum: 52 +Source: ECMA registry +Alias: iso-ir-50 +Alias: csISO50INIS8 + +Name: INIS-cyrillic [RFC1345,KXS2] +MIBenum: 53 +Source: ECMA registry +Alias: iso-ir-51 +Alias: csISO51INISCyrillic + +Name: ISO_5427:1981 [RFC1345,KXS2] +MIBenum: 54 +Source: ECMA registry +Alias: iso-ir-54 +Alias: ISO5427Cyrillic1981 + +Name: ISO_5428:1980 [RFC1345,KXS2] +MIBenum: 55 +Source: ECMA registry +Alias: iso-ir-55 +Alias: csISO5428Greek + +Name: GB_1988-80 [RFC1345,KXS2] +MIBenum: 56 +Source: ECMA registry +Alias: iso-ir-57 +Alias: cn +Alias: ISO646-CN +Alias: csISO57GB1988 + +Name: GB_2312-80 [RFC1345,KXS2] +MIBenum: 57 +Source: ECMA registry +Alias: iso-ir-58 +Alias: chinese +Alias: csISO58GB231280 + +Name: NS_4551-1 [RFC1345,KXS2] +MIBenum: 25 +Source: ECMA registry +Alias: iso-ir-60 +Alias: ISO646-NO +Alias: no +Alias: csISO60DanishNorwegian +Alias: csISO60Norwegian1 + +Name: NS_4551-2 [RFC1345,KXS2] +MIBenum: 58 +Source: ECMA registry +Alias: ISO646-NO2 +Alias: iso-ir-61 +Alias: no2 +Alias: csISO61Norwegian2 + +Name: NF_Z_62-010 [RFC1345,KXS2] +MIBenum: 26 +Source: ECMA registry +Alias: iso-ir-69 +Alias: ISO646-FR +Alias: fr +Alias: csISO69French + +Name: videotex-suppl [RFC1345,KXS2] +MIBenum: 59 +Source: ECMA registry +Alias: iso-ir-70 +Alias: csISO70VideotexSupp1 + +Name: PT2 [RFC1345,KXS2] +MIBenum: 60 +Source: ECMA registry +Alias: iso-ir-84 +Alias: ISO646-PT2 +Alias: csISO84Portuguese2 + +Name: ES2 [RFC1345,KXS2] +MIBenum: 61 +Source: ECMA registry +Alias: iso-ir-85 +Alias: ISO646-ES2 +Alias: csISO85Spanish2 + +Name: MSZ_7795.3 [RFC1345,KXS2] +MIBenum: 62 +Source: ECMA registry +Alias: iso-ir-86 +Alias: ISO646-HU +Alias: hu +Alias: csISO86Hungarian + +Name: JIS_C6226-1983 [RFC1345,KXS2] +MIBenum: 63 +Source: ECMA registry +Alias: iso-ir-87 +Alias: x0208 +Alias: JIS_X0208-1983 +Alias: csISO87JISX0208 + +Name: greek7 [RFC1345,KXS2] +MIBenum: 64 +Source: ECMA registry +Alias: iso-ir-88 +Alias: csISO88Greek7 + +Name: ASMO_449 [RFC1345,KXS2] +MIBenum: 65 +Source: ECMA registry +Alias: ISO_9036 +Alias: arabic7 +Alias: iso-ir-89 +Alias: csISO89ASMO449 + +Name: iso-ir-90 [RFC1345,KXS2] +MIBenum: 66 +Source: ECMA registry +Alias: csISO90 + +Name: JIS_C6229-1984-a [RFC1345,KXS2] +MIBenum: 67 +Source: ECMA registry +Alias: iso-ir-91 +Alias: jp-ocr-a +Alias: csISO91JISC62291984a + +Name: JIS_C6229-1984-b [RFC1345,KXS2] +MIBenum: 68 +Source: ECMA registry +Alias: iso-ir-92 +Alias: ISO646-JP-OCR-B +Alias: jp-ocr-b +Alias: csISO92JISC62991984b + +Name: JIS_C6229-1984-b-add [RFC1345,KXS2] +MIBenum: 69 +Source: ECMA registry +Alias: iso-ir-93 +Alias: jp-ocr-b-add +Alias: csISO93JIS62291984badd + +Name: JIS_C6229-1984-hand [RFC1345,KXS2] +MIBenum: 70 +Source: ECMA registry +Alias: iso-ir-94 +Alias: jp-ocr-hand +Alias: csISO94JIS62291984hand + +Name: JIS_C6229-1984-hand-add [RFC1345,KXS2] +MIBenum: 71 +Source: ECMA registry +Alias: iso-ir-95 +Alias: jp-ocr-hand-add +Alias: csISO95JIS62291984handadd + +Name: JIS_C6229-1984-kana [RFC1345,KXS2] +MIBenum: 72 +Source: ECMA registry +Alias: iso-ir-96 +Alias: csISO96JISC62291984kana + +Name: ISO_2033-1983 [RFC1345,KXS2] +MIBenum: 73 +Source: ECMA registry +Alias: iso-ir-98 +Alias: e13b +Alias: csISO2033 + +Name: ANSI_X3.110-1983 [RFC1345,KXS2] +MIBenum: 74 +Source: ECMA registry +Alias: iso-ir-99 +Alias: CSA_T500-1983 +Alias: NAPLPS +Alias: csISO99NAPLPS + +Name: ISO_8859-1:1987 [RFC1345,KXS2] +MIBenum: 4 +Source: ECMA registry +Alias: iso-ir-100 +Alias: ISO_8859-1 +Alias: ISO-8859-1 (preferred MIME name) +Alias: latin1 +Alias: l1 +Alias: IBM819 +Alias: CP819 +Alias: csISOLatin1 + +Name: ISO_8859-2:1987 [RFC1345,KXS2] +MIBenum: 5 +Source: ECMA registry +Alias: iso-ir-101 +Alias: ISO_8859-2 +Alias: ISO-8859-2 (preferred MIME name) +Alias: latin2 +Alias: l2 +Alias: csISOLatin2 + +Name: T.61-7bit [RFC1345,KXS2] +MIBenum: 75 +Source: ECMA registry +Alias: iso-ir-102 +Alias: csISO102T617bit + +Name: T.61-8bit [RFC1345,KXS2] +MIBenum: 76 +Alias: T.61 +Source: ECMA registry +Alias: iso-ir-103 +Alias: csISO103T618bit + +Name: ISO_8859-3:1988 [RFC1345,KXS2] +MIBenum: 6 +Source: ECMA registry +Alias: iso-ir-109 +Alias: ISO_8859-3 +Alias: ISO-8859-3 (preferred MIME name) +Alias: latin3 +Alias: l3 +Alias: csISOLatin3 + +Name: ISO_8859-4:1988 [RFC1345,KXS2] +MIBenum: 7 +Source: ECMA registry +Alias: iso-ir-110 +Alias: ISO_8859-4 +Alias: ISO-8859-4 (preferred MIME name) +Alias: latin4 +Alias: l4 +Alias: csISOLatin4 + +Name: ECMA-cyrillic +MIBenum: 77 +Source: ISO registry (formerly ECMA registry) + http://www.itscj.ipsj.jp/ISO-IR/111.pdf +Alias: iso-ir-111 +Alias: KOI8-E +Alias: csISO111ECMACyrillic + +Name: CSA_Z243.4-1985-1 [RFC1345,KXS2] +MIBenum: 78 +Source: ECMA registry +Alias: iso-ir-121 +Alias: ISO646-CA +Alias: csa7-1 +Alias: ca +Alias: csISO121Canadian1 + +Name: CSA_Z243.4-1985-2 [RFC1345,KXS2] +MIBenum: 79 +Source: ECMA registry +Alias: iso-ir-122 +Alias: ISO646-CA2 +Alias: csa7-2 +Alias: csISO122Canadian2 + +Name: CSA_Z243.4-1985-gr [RFC1345,KXS2] +MIBenum: 80 +Source: ECMA registry +Alias: iso-ir-123 +Alias: csISO123CSAZ24341985gr + +Name: ISO_8859-6:1987 [RFC1345,KXS2] +MIBenum: 9 +Source: ECMA registry +Alias: iso-ir-127 +Alias: ISO_8859-6 +Alias: ISO-8859-6 (preferred MIME name) +Alias: ECMA-114 +Alias: ASMO-708 +Alias: arabic +Alias: csISOLatinArabic + +Name: ISO_8859-6-E [RFC1556,IANA] +MIBenum: 81 +Source: RFC1556 +Alias: csISO88596E +Alias: ISO-8859-6-E (preferred MIME name) + +Name: ISO_8859-6-I [RFC1556,IANA] +MIBenum: 82 +Source: RFC1556 +Alias: csISO88596I +Alias: ISO-8859-6-I (preferred MIME name) + +Name: ISO_8859-7:1987 [RFC1947,RFC1345,KXS2] +MIBenum: 10 +Source: ECMA registry +Alias: iso-ir-126 +Alias: ISO_8859-7 +Alias: ISO-8859-7 (preferred MIME name) +Alias: ELOT_928 +Alias: ECMA-118 +Alias: greek +Alias: greek8 +Alias: csISOLatinGreek + +Name: T.101-G2 [RFC1345,KXS2] +MIBenum: 83 +Source: ECMA registry +Alias: iso-ir-128 +Alias: csISO128T101G2 + +Name: ISO_8859-8:1988 [RFC1345,KXS2] +MIBenum: 11 +Source: ECMA registry +Alias: iso-ir-138 +Alias: ISO_8859-8 +Alias: ISO-8859-8 (preferred MIME name) +Alias: hebrew +Alias: csISOLatinHebrew + +Name: ISO_8859-8-E [RFC1556,Nussbacher] +MIBenum: 84 +Source: RFC1556 +Alias: csISO88598E +Alias: ISO-8859-8-E (preferred MIME name) + +Name: ISO_8859-8-I [RFC1556,Nussbacher] +MIBenum: 85 +Source: RFC1556 +Alias: csISO88598I +Alias: ISO-8859-8-I (preferred MIME name) + +Name: CSN_369103 [RFC1345,KXS2] +MIBenum: 86 +Source: ECMA registry +Alias: iso-ir-139 +Alias: csISO139CSN369103 + +Name: JUS_I.B1.002 [RFC1345,KXS2] +MIBenum: 87 +Source: ECMA registry +Alias: iso-ir-141 +Alias: ISO646-YU +Alias: js +Alias: yu +Alias: csISO141JUSIB1002 + +Name: ISO_6937-2-add [RFC1345,KXS2] +MIBenum: 14 +Source: ECMA registry and ISO 6937-2:1983 +Alias: iso-ir-142 +Alias: csISOTextComm + +Name: IEC_P27-1 [RFC1345,KXS2] +MIBenum: 88 +Source: ECMA registry +Alias: iso-ir-143 +Alias: csISO143IECP271 + +Name: ISO_8859-5:1988 [RFC1345,KXS2] +MIBenum: 8 +Source: ECMA registry +Alias: iso-ir-144 +Alias: ISO_8859-5 +Alias: ISO-8859-5 (preferred MIME name) +Alias: cyrillic +Alias: csISOLatinCyrillic + +Name: JUS_I.B1.003-serb [RFC1345,KXS2] +MIBenum: 89 +Source: ECMA registry +Alias: iso-ir-146 +Alias: serbian +Alias: csISO146Serbian + +Name: JUS_I.B1.003-mac [RFC1345,KXS2] +MIBenum: 90 +Source: ECMA registry +Alias: macedonian +Alias: iso-ir-147 +Alias: csISO147Macedonian + +Name: ISO_8859-9:1989 [RFC1345,KXS2] +MIBenum: 12 +Source: ECMA registry +Alias: iso-ir-148 +Alias: ISO_8859-9 +Alias: ISO-8859-9 (preferred MIME name) +Alias: latin5 +Alias: l5 +Alias: csISOLatin5 + +Name: greek-ccitt [RFC1345,KXS2] +MIBenum: 91 +Source: ECMA registry +Alias: iso-ir-150 +Alias: csISO150 +Alias: csISO150GreekCCITT + +Name: NC_NC00-10:81 [RFC1345,KXS2] +MIBenum: 92 +Source: ECMA registry +Alias: cuba +Alias: iso-ir-151 +Alias: ISO646-CU +Alias: csISO151Cuba + +Name: ISO_6937-2-25 [RFC1345,KXS2] +MIBenum: 93 +Source: ECMA registry +Alias: iso-ir-152 +Alias: csISO6937Add + +Name: GOST_19768-74 [RFC1345,KXS2] +MIBenum: 94 +Source: ECMA registry +Alias: ST_SEV_358-88 +Alias: iso-ir-153 +Alias: csISO153GOST1976874 + +Name: ISO_8859-supp [RFC1345,KXS2] +MIBenum: 95 +Source: ECMA registry +Alias: iso-ir-154 +Alias: latin1-2-5 +Alias: csISO8859Supp + +Name: ISO_10367-box [RFC1345,KXS2] +MIBenum: 96 +Source: ECMA registry +Alias: iso-ir-155 +Alias: csISO10367Box + +Name: ISO-8859-10 (preferred MIME name) [RFC1345,KXS2] +MIBenum: 13 +Source: ECMA registry +Alias: iso-ir-157 +Alias: l6 +Alias: ISO_8859-10:1992 +Alias: csISOLatin6 +Alias: latin6 + +Name: latin-lap [RFC1345,KXS2] +MIBenum: 97 +Source: ECMA registry +Alias: lap +Alias: iso-ir-158 +Alias: csISO158Lap + +Name: JIS_X0212-1990 [RFC1345,KXS2] +MIBenum: 98 +Source: ECMA registry +Alias: x0212 +Alias: iso-ir-159 +Alias: csISO159JISX02121990 + +Name: DS_2089 [RFC1345,KXS2] +MIBenum: 99 +Source: Danish Standard, DS 2089, February 1974 +Alias: DS2089 +Alias: ISO646-DK +Alias: dk +Alias: csISO646Danish + +Name: us-dk [RFC1345,KXS2] +MIBenum: 100 +Alias: csUSDK + +Name: dk-us [RFC1345,KXS2] +MIBenum: 101 +Alias: csDKUS + +Name: JIS_X0201 [RFC1345,KXS2] +MIBenum: 15 +Source: JIS X 0201-1976. One byte only, this is equivalent to + JIS/Roman (similar to ASCII) plus eight-bit half-width + Katakana +Alias: X0201 +Alias: csHalfWidthKatakana + +Name: KSC5636 [RFC1345,KXS2] +MIBenum: 102 +Alias: ISO646-KR +Alias: csKSC5636 + +Name: ISO-10646-UCS-2 +MIBenum: 1000 +Source: the 2-octet Basic Multilingual Plane, aka Unicode + this needs to specify network byte order: the standard + does not specify (it is a 16-bit integer space) +Alias: csUnicode + +Name: ISO-10646-UCS-4 +MIBenum: 1001 +Source: the full code space. (same comment about byte order, + these are 31-bit numbers. +Alias: csUCS4 + +Name: DEC-MCS [RFC1345,KXS2] +MIBenum: 2008 +Source: VAX/VMS User's Manual, + Order Number: AI-Y517A-TE, April 1986. +Alias: dec +Alias: csDECMCS + +Name: hp-roman8 [HP-PCL5,RFC1345,KXS2] +MIBenum: 2004 +Source: LaserJet IIP Printer User's Manual, + HP part no 33471-90901, Hewlet-Packard, June 1989. +Alias: roman8 +Alias: r8 +Alias: csHPRoman8 + +Name: macintosh [RFC1345,KXS2] +MIBenum: 2027 +Source: The Unicode Standard ver1.0, ISBN 0-201-56788-1, Oct 1991 +Alias: mac +Alias: csMacintosh + +Name: IBM037 [RFC1345,KXS2] +MIBenum: 2028 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: cp037 +Alias: ebcdic-cp-us +Alias: ebcdic-cp-ca +Alias: ebcdic-cp-wt +Alias: ebcdic-cp-nl +Alias: csIBM037 + +Name: IBM038 [RFC1345,KXS2] +MIBenum: 2029 +Source: IBM 3174 Character Set Ref, GA27-3831-02, March 1990 +Alias: EBCDIC-INT +Alias: cp038 +Alias: csIBM038 + +Name: IBM273 [RFC1345,KXS2] +MIBenum: 2030 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: CP273 +Alias: csIBM273 + +Name: IBM274 [RFC1345,KXS2] +MIBenum: 2031 +Source: IBM 3174 Character Set Ref, GA27-3831-02, March 1990 +Alias: EBCDIC-BE +Alias: CP274 +Alias: csIBM274 + +Name: IBM275 [RFC1345,KXS2] +MIBenum: 2032 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: EBCDIC-BR +Alias: cp275 +Alias: csIBM275 + +Name: IBM277 [RFC1345,KXS2] +MIBenum: 2033 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: EBCDIC-CP-DK +Alias: EBCDIC-CP-NO +Alias: csIBM277 + +Name: IBM278 [RFC1345,KXS2] +MIBenum: 2034 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: CP278 +Alias: ebcdic-cp-fi +Alias: ebcdic-cp-se +Alias: csIBM278 + +Name: IBM280 [RFC1345,KXS2] +MIBenum: 2035 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: CP280 +Alias: ebcdic-cp-it +Alias: csIBM280 + +Name: IBM281 [RFC1345,KXS2] +MIBenum: 2036 +Source: IBM 3174 Character Set Ref, GA27-3831-02, March 1990 +Alias: EBCDIC-JP-E +Alias: cp281 +Alias: csIBM281 + +Name: IBM284 [RFC1345,KXS2] +MIBenum: 2037 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: CP284 +Alias: ebcdic-cp-es +Alias: csIBM284 + +Name: IBM285 [RFC1345,KXS2] +MIBenum: 2038 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: CP285 +Alias: ebcdic-cp-gb +Alias: csIBM285 + +Name: IBM290 [RFC1345,KXS2] +MIBenum: 2039 +Source: IBM 3174 Character Set Ref, GA27-3831-02, March 1990 +Alias: cp290 +Alias: EBCDIC-JP-kana +Alias: csIBM290 + +Name: IBM297 [RFC1345,KXS2] +MIBenum: 2040 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: cp297 +Alias: ebcdic-cp-fr +Alias: csIBM297 + +Name: IBM420 [RFC1345,KXS2] +MIBenum: 2041 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990, + IBM NLS RM p 11-11 +Alias: cp420 +Alias: ebcdic-cp-ar1 +Alias: csIBM420 + +Name: IBM423 [RFC1345,KXS2] +MIBenum: 2042 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: cp423 +Alias: ebcdic-cp-gr +Alias: csIBM423 + +Name: IBM424 [RFC1345,KXS2] +MIBenum: 2043 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: cp424 +Alias: ebcdic-cp-he +Alias: csIBM424 + +Name: IBM437 [RFC1345,KXS2] +MIBenum: 2011 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: cp437 +Alias: 437 +Alias: csPC8CodePage437 + +Name: IBM500 [RFC1345,KXS2] +MIBenum: 2044 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: CP500 +Alias: ebcdic-cp-be +Alias: ebcdic-cp-ch +Alias: csIBM500 + +Name: IBM775 [HP-PCL5] +MIBenum: 2087 +Source: HP PCL 5 Comparison Guide (P/N 5021-0329) pp B-13, 1996 +Alias: cp775 +Alias: csPC775Baltic + +Name: IBM850 [RFC1345,KXS2] +MIBenum: 2009 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: cp850 +Alias: 850 +Alias: csPC850Multilingual + +Name: IBM851 [RFC1345,KXS2] +MIBenum: 2045 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: cp851 +Alias: 851 +Alias: csIBM851 + +Name: IBM852 [RFC1345,KXS2] +MIBenum: 2010 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: cp852 +Alias: 852 +Alias: csPCp852 + +Name: IBM855 [RFC1345,KXS2] +MIBenum: 2046 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: cp855 +Alias: 855 +Alias: csIBM855 + +Name: IBM857 [RFC1345,KXS2] +MIBenum: 2047 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: cp857 +Alias: 857 +Alias: csIBM857 + +Name: IBM860 [RFC1345,KXS2] +MIBenum: 2048 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: cp860 +Alias: 860 +Alias: csIBM860 + +Name: IBM861 [RFC1345,KXS2] +MIBenum: 2049 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: cp861 +Alias: 861 +Alias: cp-is +Alias: csIBM861 + +Name: IBM862 [RFC1345,KXS2] +MIBenum: 2013 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: cp862 +Alias: 862 +Alias: csPC862LatinHebrew + +Name: IBM863 [RFC1345,KXS2] +MIBenum: 2050 +Source: IBM Keyboard layouts and code pages, PN 07G4586 June 1991 +Alias: cp863 +Alias: 863 +Alias: csIBM863 + +Name: IBM864 [RFC1345,KXS2] +MIBenum: 2051 +Source: IBM Keyboard layouts and code pages, PN 07G4586 June 1991 +Alias: cp864 +Alias: csIBM864 + +Name: IBM865 [RFC1345,KXS2] +MIBenum: 2052 +Source: IBM DOS 3.3 Ref (Abridged), 94X9575 (Feb 1987) +Alias: cp865 +Alias: 865 +Alias: csIBM865 + +Name: IBM866 [Pond] +MIBenum: 2086 +Source: IBM NLDG Volume 2 (SE09-8002-03) August 1994 +Alias: cp866 +Alias: 866 +Alias: csIBM866 + +Name: IBM868 [RFC1345,KXS2] +MIBenum: 2053 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: CP868 +Alias: cp-ar +Alias: csIBM868 + +Name: IBM869 [RFC1345,KXS2] +MIBenum: 2054 +Source: IBM Keyboard layouts and code pages, PN 07G4586 June 1991 +Alias: cp869 +Alias: 869 +Alias: cp-gr +Alias: csIBM869 + +Name: IBM870 [RFC1345,KXS2] +MIBenum: 2055 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: CP870 +Alias: ebcdic-cp-roece +Alias: ebcdic-cp-yu +Alias: csIBM870 + +Name: IBM871 [RFC1345,KXS2] +MIBenum: 2056 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: CP871 +Alias: ebcdic-cp-is +Alias: csIBM871 + +Name: IBM880 [RFC1345,KXS2] +MIBenum: 2057 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: cp880 +Alias: EBCDIC-Cyrillic +Alias: csIBM880 + +Name: IBM891 [RFC1345,KXS2] +MIBenum: 2058 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: cp891 +Alias: csIBM891 + +Name: IBM903 [RFC1345,KXS2] +MIBenum: 2059 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: cp903 +Alias: csIBM903 + +Name: IBM904 [RFC1345,KXS2] +MIBenum: 2060 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: cp904 +Alias: 904 +Alias: csIBBM904 + +Name: IBM905 [RFC1345,KXS2] +MIBenum: 2061 +Source: IBM 3174 Character Set Ref, GA27-3831-02, March 1990 +Alias: CP905 +Alias: ebcdic-cp-tr +Alias: csIBM905 + +Name: IBM918 [RFC1345,KXS2] +MIBenum: 2062 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: CP918 +Alias: ebcdic-cp-ar2 +Alias: csIBM918 + +Name: IBM1026 [RFC1345,KXS2] +MIBenum: 2063 +Source: IBM NLS RM Vol2 SE09-8002-01, March 1990 +Alias: CP1026 +Alias: csIBM1026 + +Name: EBCDIC-AT-DE [RFC1345,KXS2] +MIBenum: 2064 +Source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987 +Alias: csIBMEBCDICATDE + +Name: EBCDIC-AT-DE-A [RFC1345,KXS2] +MIBenum: 2065 +Source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987 +Alias: csEBCDICATDEA + +Name: EBCDIC-CA-FR [RFC1345,KXS2] +MIBenum: 2066 +Source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987 +Alias: csEBCDICCAFR + +Name: EBCDIC-DK-NO [RFC1345,KXS2] +MIBenum: 2067 +Source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987 +Alias: csEBCDICDKNO + +Name: EBCDIC-DK-NO-A [RFC1345,KXS2] +MIBenum: 2068 +Source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987 +Alias: csEBCDICDKNOA + +Name: EBCDIC-FI-SE [RFC1345,KXS2] +MIBenum: 2069 +Source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987 +Alias: csEBCDICFISE + +Name: EBCDIC-FI-SE-A [RFC1345,KXS2] +MIBenum: 2070 +Source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987 +Alias: csEBCDICFISEA + +Name: EBCDIC-FR [RFC1345,KXS2] +MIBenum: 2071 +Source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987 +Alias: csEBCDICFR + +Name: EBCDIC-IT [RFC1345,KXS2] +MIBenum: 2072 +Source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987 +Alias: csEBCDICIT + +Name: EBCDIC-PT [RFC1345,KXS2] +MIBenum: 2073 +Source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987 +Alias: csEBCDICPT + +Name: EBCDIC-ES [RFC1345,KXS2] +MIBenum: 2074 +Source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987 +Alias: csEBCDICES + +Name: EBCDIC-ES-A [RFC1345,KXS2] +MIBenum: 2075 +Source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987 +Alias: csEBCDICESA + +Name: EBCDIC-ES-S [RFC1345,KXS2] +MIBenum: 2076 +Source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987 +Alias: csEBCDICESS + +Name: EBCDIC-UK [RFC1345,KXS2] +MIBenum: 2077 +Source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987 +Alias: csEBCDICUK + +Name: EBCDIC-US [RFC1345,KXS2] +MIBenum: 2078 +Source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987 +Alias: csEBCDICUS + +Name: UNKNOWN-8BIT [RFC1428] +MIBenum: 2079 +Alias: csUnknown8BiT + +Name: MNEMONIC [RFC1345,KXS2] +MIBenum: 2080 +Source: RFC 1345, also known as "mnemonic+ascii+38" +Alias: csMnemonic + +Name: MNEM [RFC1345,KXS2] +MIBenum: 2081 +Source: RFC 1345, also known as "mnemonic+ascii+8200" +Alias: csMnem + +Name: VISCII [RFC1456] +MIBenum: 2082 +Source: RFC 1456 +Alias: csVISCII + +Name: VIQR [RFC1456] +MIBenum: 2083 +Source: RFC 1456 +Alias: csVIQR + +Name: KOI8-R (preferred MIME name) [RFC1489] +MIBenum: 2084 +Source: RFC 1489, based on GOST-19768-74, ISO-6937/8, + INIS-Cyrillic, ISO-5427. +Alias: csKOI8R + +Name: KOI8-U [RFC2319] +MIBenum: 2088 +Source: RFC 2319 + +Name: IBM00858 +MIBenum: 2089 +Source: IBM See (http://www.iana.org/assignments/charset-reg/IBM00858) [Mahdi] +Alias: CCSID00858 +Alias: CP00858 +Alias: PC-Multilingual-850+euro + +Name: IBM00924 +MIBenum: 2090 +Source: IBM See (http://www.iana.org/assignments/charset-reg/IBM00924) [Mahdi] +Alias: CCSID00924 +Alias: CP00924 +Alias: ebcdic-Latin9--euro + +Name: IBM01140 +MIBenum: 2091 +Source: IBM See (http://www.iana.org/assignments/charset-reg/IBM01140) [Mahdi] +Alias: CCSID01140 +Alias: CP01140 +Alias: ebcdic-us-37+euro + +Name: IBM01141 +MIBenum: 2092 +Source: IBM See (http://www.iana.org/assignments/charset-reg/IBM01141) [Mahdi] +Alias: CCSID01141 +Alias: CP01141 +Alias: ebcdic-de-273+euro + +Name: IBM01142 +MIBenum: 2093 +Source: IBM See (http://www.iana.org/assignments/charset-reg/IBM01142) [Mahdi] +Alias: CCSID01142 +Alias: CP01142 +Alias: ebcdic-dk-277+euro +Alias: ebcdic-no-277+euro + +Name: IBM01143 +MIBenum: 2094 +Source: IBM See (http://www.iana.org/assignments/charset-reg/IBM01143) [Mahdi] +Alias: CCSID01143 +Alias: CP01143 +Alias: ebcdic-fi-278+euro +Alias: ebcdic-se-278+euro + +Name: IBM01144 +MIBenum: 2095 +Source: IBM See (http://www.iana.org/assignments/charset-reg/IBM01144) [Mahdi] +Alias: CCSID01144 +Alias: CP01144 +Alias: ebcdic-it-280+euro + +Name: IBM01145 +MIBenum: 2096 +Source: IBM See (http://www.iana.org/assignments/charset-reg/IBM01145) [Mahdi] +Alias: CCSID01145 +Alias: CP01145 +Alias: ebcdic-es-284+euro + +Name: IBM01146 +MIBenum: 2097 +Source: IBM See (http://www.iana.org/assignments/charset-reg/IBM01146) [Mahdi] +Alias: CCSID01146 +Alias: CP01146 +Alias: ebcdic-gb-285+euro + +Name: IBM01147 +MIBenum: 2098 +Source: IBM See (http://www.iana.org/assignments/charset-reg/IBM01147) [Mahdi] +Alias: CCSID01147 +Alias: CP01147 +Alias: ebcdic-fr-297+euro + +Name: IBM01148 +MIBenum: 2099 +Source: IBM See (http://www.iana.org/assignments/charset-reg/IBM01148) [Mahdi] +Alias: CCSID01148 +Alias: CP01148 +Alias: ebcdic-international-500+euro + +Name: IBM01149 +MIBenum: 2100 +Source: IBM See (http://www.iana.org/assignments/charset-reg/IBM01149) [Mahdi] +Alias: CCSID01149 +Alias: CP01149 +Alias: ebcdic-is-871+euro + +Name: Big5-HKSCS [Yick] +MIBenum: 2101 +Source: See (http://www.iana.org/assignments/charset-reg/Big5-HKSCS) +Alias: None + +Name: IBM1047 [Robrigado] +MIBenum: 2102 +Source: IBM1047 (EBCDIC Latin 1/Open Systems) +http://www-1.ibm.com/servers/eserver/iseries/software/globalization/pdf/cp01047z.pdf +Alias: IBM-1047 + +Name: PTCP154 [Uskov] +MIBenum: 2103 +Source: See (http://www.iana.org/assignments/charset-reg/PTCP154) +Alias: csPTCP154 +Alias: PT154 +Alias: CP154 +Alias: Cyrillic-Asian + +Name: Amiga-1251 +MIBenum: 2104 +Source: See (http://www.amiga.ultranet.ru/Amiga-1251.html) +Alias: Ami1251 +Alias: Amiga1251 +Alias: Ami-1251 +(Aliases are provided for historical reasons and should not be used) + [Malyshev] + +Name: KOI7-switched +MIBenum: 2105 +Source: See <http://www.iana.org/assignments/charset-reg/KOI7-switched> +Aliases: None + +Name: UNICODE-1-1 [RFC1641] +MIBenum: 1010 +Source: RFC 1641 +Alias: csUnicode11 + +Name: SCSU +MIBenum: 1011 +Source: SCSU See (http://www.iana.org/assignments/charset-reg/SCSU) [Scherer] +Alias: None + +Name: UTF-7 [RFC2152] +MIBenum: 1012 +Source: RFC 2152 +Alias: None + +Name: UTF-16BE [RFC2781] +MIBenum: 1013 +Source: RFC 2781 +Alias: None + +Name: UTF-16LE [RFC2781] +MIBenum: 1014 +Source: RFC 2781 +Alias: None + +Name: UTF-16 [RFC2781] +MIBenum: 1015 +Source: RFC 2781 +Alias: None + +Name: CESU-8 [Phipps] +MIBenum: 1016 +Source: <http://www.unicode.org/unicode/reports/tr26> +Alias: csCESU-8 + +Name: UTF-32 [Davis] +MIBenum: 1017 +Source: <http://www.unicode.org/unicode/reports/tr19/> +Alias: None + +Name: UTF-32BE [Davis] +MIBenum: 1018 +Source: <http://www.unicode.org/unicode/reports/tr19/> +Alias: None + +Name: UTF-32LE [Davis] +MIBenum: 1019 +Source: <http://www.unicode.org/unicode/reports/tr19/> +Alias: None + +Name: BOCU-1 [Scherer] +MIBenum: 1020 +Source: http://www.unicode.org/notes/tn6/ +Alias: csBOCU-1 + +Name: UNICODE-1-1-UTF-7 [RFC1642] +MIBenum: 103 +Source: RFC 1642 +Alias: csUnicode11UTF7 + +Name: UTF-8 [RFC3629] +MIBenum: 106 +Source: RFC 3629 +Alias: None + +Name: ISO-8859-13 +MIBenum: 109 +Source: ISO See (http://www.iana.org/assignments/charset-reg/iso-8859-13)[Tumasonis] +Alias: None + +Name: ISO-8859-14 +MIBenum: 110 +Source: ISO See (http://www.iana.org/assignments/charset-reg/iso-8859-14) [Simonsen] +Alias: iso-ir-199 +Alias: ISO_8859-14:1998 +Alias: ISO_8859-14 +Alias: latin8 +Alias: iso-celtic +Alias: l8 + +Name: ISO-8859-15 +MIBenum: 111 +Source: ISO + Please see: <http://www.iana.org/assignments/charset-reg/ISO-8859-15> +Alias: ISO_8859-15 +Alias: Latin-9 + +Name: ISO-8859-16 +MIBenum: 112 +Source: ISO +Alias: iso-ir-226 +Alias: ISO_8859-16:2001 +Alias: ISO_8859-16 +Alias: latin10 +Alias: l10 + +Name: GBK +MIBenum: 113 +Source: Chinese IT Standardization Technical Committee + Please see: <http://www.iana.org/assignments/charset-reg/GBK> +Alias: CP936 +Alias: MS936 +Alias: windows-936 + +Name: GB18030 +MIBenum: 114 +Source: Chinese IT Standardization Technical Committee + Please see: <http://www.iana.org/assignments/charset-reg/GB18030> +Alias: None + +Name: OSD_EBCDIC_DF04_15 +MIBenum: 115 +Source: Fujitsu-Siemens standard mainframe EBCDIC encoding + Please see: <http://www.iana.org/assignments/charset-reg/OSD-EBCDIC-DF04-15> +Alias: None + +Name: OSD_EBCDIC_DF03_IRV +MIBenum: 116 +Source: Fujitsu-Siemens standard mainframe EBCDIC encoding + Please see: <http://www.iana.org/assignments/charset-reg/OSD-EBCDIC-DF03-IRV> +Alias: None + +Name: OSD_EBCDIC_DF04_1 +MIBenum: 117 +Source: Fujitsu-Siemens standard mainframe EBCDIC encoding + Please see: <http://www.iana.org/assignments/charset-reg/OSD-EBCDIC-DF04-1> +Alias: None + +Name: JIS_Encoding +MIBenum: 16 +Source: JIS X 0202-1991. Uses ISO 2022 escape sequences to + shift code sets as documented in JIS X 0202-1991. +Alias: csJISEncoding + +Name: Shift_JIS (preferred MIME name) +MIBenum: 17 +Source: This charset is an extension of csHalfWidthKatakana by + adding graphic characters in JIS X 0208. The CCS's are + JIS X0201:1997 and JIS X0208:1997. The + complete definition is shown in Appendix 1 of JIS + X0208:1997. + This charset can be used for the top-level media type "text". +Alias: MS_Kanji +Alias: csShiftJIS + +Name: Extended_UNIX_Code_Packed_Format_for_Japanese +MIBenum: 18 +Source: Standardized by OSF, UNIX International, and UNIX Systems + Laboratories Pacific. Uses ISO 2022 rules to select + code set 0: US-ASCII (a single 7-bit byte set) + code set 1: JIS X0208-1990 (a double 8-bit byte set) + restricted to A0-FF in both bytes + code set 2: Half Width Katakana (a single 7-bit byte set) + requiring SS2 as the character prefix + code set 3: JIS X0212-1990 (a double 7-bit byte set) + restricted to A0-FF in both bytes + requiring SS3 as the character prefix +Alias: csEUCPkdFmtJapanese +Alias: EUC-JP (preferred MIME name) + +Name: Extended_UNIX_Code_Fixed_Width_for_Japanese +MIBenum: 19 +Source: Used in Japan. Each character is 2 octets. + code set 0: US-ASCII (a single 7-bit byte set) + 1st byte = 00 + 2nd byte = 20-7E + code set 1: JIS X0208-1990 (a double 7-bit byte set) + restricted to A0-FF in both bytes + code set 2: Half Width Katakana (a single 7-bit byte set) + 1st byte = 00 + 2nd byte = A0-FF + code set 3: JIS X0212-1990 (a double 7-bit byte set) + restricted to A0-FF in + the first byte + and 21-7E in the second byte +Alias: csEUCFixWidJapanese + +Name: ISO-10646-UCS-Basic +MIBenum: 1002 +Source: ASCII subset of Unicode. Basic Latin = collection 1 + See ISO 10646, Appendix A +Alias: csUnicodeASCII + +Name: ISO-10646-Unicode-Latin1 +MIBenum: 1003 +Source: ISO Latin-1 subset of Unicode. Basic Latin and Latin-1 + Supplement = collections 1 and 2. See ISO 10646, + Appendix A. See RFC 1815. +Alias: csUnicodeLatin1 +Alias: ISO-10646 + +Name: ISO-10646-J-1 +Source: ISO 10646 Japanese, see RFC 1815. + +Name: ISO-Unicode-IBM-1261 +MIBenum: 1005 +Source: IBM Latin-2, -3, -5, Extended Presentation Set, GCSGID: 1261 +Alias: csUnicodeIBM1261 + +Name: ISO-Unicode-IBM-1268 +MIBenum: 1006 +Source: IBM Latin-4 Extended Presentation Set, GCSGID: 1268 +Alias: csUnicodeIBM1268 + +Name: ISO-Unicode-IBM-1276 +MIBenum: 1007 +Source: IBM Cyrillic Greek Extended Presentation Set, GCSGID: 1276 +Alias: csUnicodeIBM1276 + +Name: ISO-Unicode-IBM-1264 +MIBenum: 1008 +Source: IBM Arabic Presentation Set, GCSGID: 1264 +Alias: csUnicodeIBM1264 + +Name: ISO-Unicode-IBM-1265 +MIBenum: 1009 +Source: IBM Hebrew Presentation Set, GCSGID: 1265 +Alias: csUnicodeIBM1265 + +Name: ISO-8859-1-Windows-3.0-Latin-1 [HP-PCL5] +MIBenum: 2000 +Source: Extended ISO 8859-1 Latin-1 for Windows 3.0. + PCL Symbol Set id: 9U +Alias: csWindows30Latin1 + +Name: ISO-8859-1-Windows-3.1-Latin-1 [HP-PCL5] +MIBenum: 2001 +Source: Extended ISO 8859-1 Latin-1 for Windows 3.1. + PCL Symbol Set id: 19U +Alias: csWindows31Latin1 + +Name: ISO-8859-2-Windows-Latin-2 [HP-PCL5] +MIBenum: 2002 +Source: Extended ISO 8859-2. Latin-2 for Windows 3.1. + PCL Symbol Set id: 9E +Alias: csWindows31Latin2 + +Name: ISO-8859-9-Windows-Latin-5 [HP-PCL5] +MIBenum: 2003 +Source: Extended ISO 8859-9. Latin-5 for Windows 3.1 + PCL Symbol Set id: 5T +Alias: csWindows31Latin5 + +Name: Adobe-Standard-Encoding [Adobe] +MIBenum: 2005 +Source: PostScript Language Reference Manual + PCL Symbol Set id: 10J +Alias: csAdobeStandardEncoding + +Name: Ventura-US [HP-PCL5] +MIBenum: 2006 +Source: Ventura US. ASCII plus characters typically used in + publishing, like pilcrow, copyright, registered, trade mark, + section, dagger, and double dagger in the range A0 (hex) + to FF (hex). + PCL Symbol Set id: 14J +Alias: csVenturaUS + +Name: Ventura-International [HP-PCL5] +MIBenum: 2007 +Source: Ventura International. ASCII plus coded characters similar + to Roman8. + PCL Symbol Set id: 13J +Alias: csVenturaInternational + +Name: PC8-Danish-Norwegian [HP-PCL5] +MIBenum: 2012 +Source: PC Danish Norwegian + 8-bit PC set for Danish Norwegian + PCL Symbol Set id: 11U +Alias: csPC8DanishNorwegian + +Name: PC8-Turkish [HP-PCL5] +MIBenum: 2014 +Source: PC Latin Turkish. PCL Symbol Set id: 9T +Alias: csPC8Turkish + +Name: IBM-Symbols [IBM-CIDT] +MIBenum: 2015 +Source: Presentation Set, CPGID: 259 +Alias: csIBMSymbols + +Name: IBM-Thai [IBM-CIDT] +MIBenum: 2016 +Source: Presentation Set, CPGID: 838 +Alias: csIBMThai + +Name: HP-Legal [HP-PCL5] +MIBenum: 2017 +Source: PCL 5 Comparison Guide, Hewlett-Packard, + HP part number 5961-0510, October 1992 + PCL Symbol Set id: 1U +Alias: csHPLegal + +Name: HP-Pi-font [HP-PCL5] +MIBenum: 2018 +Source: PCL 5 Comparison Guide, Hewlett-Packard, + HP part number 5961-0510, October 1992 + PCL Symbol Set id: 15U +Alias: csHPPiFont + +Name: HP-Math8 [HP-PCL5] +MIBenum: 2019 +Source: PCL 5 Comparison Guide, Hewlett-Packard, + HP part number 5961-0510, October 1992 + PCL Symbol Set id: 8M +Alias: csHPMath8 + +Name: Adobe-Symbol-Encoding [Adobe] +MIBenum: 2020 +Source: PostScript Language Reference Manual + PCL Symbol Set id: 5M +Alias: csHPPSMath + +Name: HP-DeskTop [HP-PCL5] +MIBenum: 2021 +Source: PCL 5 Comparison Guide, Hewlett-Packard, + HP part number 5961-0510, October 1992 + PCL Symbol Set id: 7J +Alias: csHPDesktop + +Name: Ventura-Math [HP-PCL5] +MIBenum: 2022 +Source: PCL 5 Comparison Guide, Hewlett-Packard, + HP part number 5961-0510, October 1992 + PCL Symbol Set id: 6M +Alias: csVenturaMath + +Name: Microsoft-Publishing [HP-PCL5] +MIBenum: 2023 +Source: PCL 5 Comparison Guide, Hewlett-Packard, + HP part number 5961-0510, October 1992 + PCL Symbol Set id: 6J +Alias: csMicrosoftPublishing + +Name: Windows-31J +MIBenum: 2024 +Source: Windows Japanese. A further extension of Shift_JIS + to include NEC special characters (Row 13), NEC + selection of IBM extensions (Rows 89 to 92), and IBM + extensions (Rows 115 to 119). The CCS's are + JIS X0201:1997, JIS X0208:1997, and these extensions. + This charset can be used for the top-level media type "text", + but it is of limited or specialized use (see RFC2278). + PCL Symbol Set id: 19K +Alias: csWindows31J + +Name: GB2312 (preferred MIME name) +MIBenum: 2025 +Source: Chinese for People's Republic of China (PRC) mixed one byte, + two byte set: + 20-7E = one byte ASCII + A1-FE = two byte PRC Kanji + See GB 2312-80 + PCL Symbol Set Id: 18C +Alias: csGB2312 + +Name: Big5 (preferred MIME name) +MIBenum: 2026 +Source: Chinese for Taiwan Multi-byte set. + PCL Symbol Set Id: 18T +Alias: csBig5 + +Name: windows-1250 +MIBenum: 2250 +Source: Microsoft (http://www.iana.org/assignments/charset-reg/windows-1250) [Lazhintseva] +Alias: None + +Name: windows-1251 +MIBenum: 2251 +Source: Microsoft (http://www.iana.org/assignments/charset-reg/windows-1251) [Lazhintseva] +Alias: None + +Name: windows-1252 +MIBenum: 2252 +Source: Microsoft (http://www.iana.org/assignments/charset-reg/windows-1252) [Wendt] +Alias: None + +Name: windows-1253 +MIBenum: 2253 +Source: Microsoft (http://www.iana.org/assignments/charset-reg/windows-1253) [Lazhintseva] +Alias: None + +Name: windows-1254 +MIBenum: 2254 +Source: Microsoft (http://www.iana.org/assignments/charset-reg/windows-1254) [Lazhintseva] +Alias: None + +Name: windows-1255 +MIBenum: 2255 +Source: Microsoft (http://www.iana.org/assignments/charset-reg/windows-1255) [Lazhintseva] +Alias: None + +Name: windows-1256 +MIBenum: 2256 +Source: Microsoft (http://www.iana.org/assignments/charset-reg/windows-1256) [Lazhintseva] +Alias: None + +Name: windows-1257 +MIBenum: 2257 +Source: Microsoft (http://www.iana.org/assignments/charset-reg/windows-1257) [Lazhintseva] +Alias: None + +Name: windows-1258 +MIBenum: 2258 +Source: Microsoft (http://www.iana.org/assignments/charset-reg/windows-1258) [Lazhintseva] +Alias: None + +Name: TIS-620 +MIBenum: 2259 +Source: Thai Industrial Standards Institute (TISI) [Tantsetthi] + +Name: HZ-GB-2312 +MIBenum: 2085 +Source: RFC 1842, RFC 1843 [RFC1842, RFC1843] + + +REFERENCES +---------- + +[RFC1345] Simonsen, K., "Character Mnemonics & Character Sets", + RFC 1345, Rationel Almen Planlaegning, Rationel Almen + Planlaegning, June 1992. + +[RFC1428] Vaudreuil, G., "Transition of Internet Mail from + Just-Send-8 to 8bit-SMTP/MIME", RFC1428, CNRI, February + 1993. + +[RFC1456] Vietnamese Standardization Working Group, "Conventions for + Encoding the Vietnamese Language VISCII: VIetnamese + Standard Code for Information Interchange VIQR: VIetnamese + Quoted-Readable Specification Revision 1.1", RFC 1456, May + 1993. + +[RFC1468] Murai, J., Crispin, M., and E. van der Poel, "Japanese + Character Encoding for Internet Messages", RFC 1468, + Keio University, Panda Programming, June 1993. + +[RFC1489] Chernov, A., "Registration of a Cyrillic Character Set", + RFC1489, RELCOM Development Team, July 1993. + +[RFC1554] Ohta, M., and K. Handa, "ISO-2022-JP-2: Multilingual + Extension of ISO-2022-JP", RFC1554, Tokyo Institute of + Technology, ETL, December 1993. + +[RFC1556] Nussbacher, H., "Handling of Bi-directional Texts in MIME", + RFC1556, Israeli Inter-University, December 1993. + +[RFC1557] Choi, U., Chon, K., and H. Park, "Korean Character Encoding + for Internet Messages", KAIST, Solvit Chosun Media, + December 1993. + +[RFC1641] Goldsmith, D., and M. Davis, "Using Unicode with MIME", + RFC1641, Taligent, Inc., July 1994. + +[RFC1642] Goldsmith, D., and M. Davis, "UTF-7", RFC1642, Taligent, + Inc., July 1994. + +[RFC1815] Ohta, M., "Character Sets ISO-10646 and ISO-10646-J-1", + RFC 1815, Tokyo Institute of Technology, July 1995. + + +[Adobe] Adobe Systems Incorporated, PostScript Language Reference + Manual, second edition, Addison-Wesley Publishing Company, + Inc., 1990. + +[ECMA Registry] ISO-IR: International Register of Escape Sequences + http://www.itscj.ipsj.or.jp/ISO-IE/ Note: The current + registration authority is IPSJ/ITSCJ, Japan. + +[HP-PCL5] Hewlett-Packard Company, "HP PCL 5 Comparison Guide", + (P/N 5021-0329) pp B-13, 1996. + +[IBM-CIDT] IBM Corporation, "ABOUT TYPE: IBM's Technical Reference + for Core Interchange Digitized Type", Publication number + S544-3708-01 + +[RFC1842] Wei, Y., J. Li, and Y. Jiang, "ASCII Printable + Characters-Based Chinese Character Encoding for Internet + Messages", RFC 1842, Harvard University, Rice University, + University of Maryland, August 1995. + +[RFC1843] Lee, F., "HZ - A Data Format for Exchanging Files of + Arbitrarily Mixed Chinese and ASCII Characters", RFC 1843, + Stanford University, August 1995. + +[RFC2152] Goldsmith, D., M. Davis, "UTF-7: A Mail-Safe Transformation + Format of Unicode", RFC 2152, Apple Computer, Inc., + Taligent Inc., May 1997. + +[RFC2279] Yergeau, F., "UTF-8, A Transformation Format of ISO 10646", + RFC 2279, Alis Technologies, January, 1998. + +[RFC2781] Hoffman, P., Yergeau, F., "UTF-16, an encoding of ISO 10646", + RFC 2781, February 2000. + +[RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO 10646", + RFC3629, November 2003. + +PEOPLE +------ + +[KXS2] Keld Simonsen <Keld.Simonsen@dkuug.dk> + +[Choi] Woohyong Choi <whchoi@cosmos.kaist.ac.kr> + +[Davis] Mark Davis, <mark@unicode.org>, April 2002. + +[Lazhintseva] Katya Lazhintseva, <katyal@MICROSOFT.com>, May 1996. + +[Mahdi] Tamer Mahdi, <tamer@ca.ibm.com>, August 2000. + +[Malyshev] Michael Malyshev, <michael_malyshev@mail.ru>, January 2004 + +[Murai] Jun Murai <jun@wide.ad.jp> + +[Nussbacher] Hank Nussbacher, <hank@vm.tau.ac.il> + +[Ohta] Masataka Ohta, <mohta@cc.titech.ac.jp>, July 1995. + +[Phipps] Toby Phipps, <tphipps@peoplesoft.com>, March 2002. + +[Pond] Rick Pond, <rickpond@vnet.ibm.com>, March 1997. + +[Robrigado] Reuel Robrigado, <reuelr@ca.ibm.com>, September 2002. + +[Scherer] Markus Scherer, <markus.scherer@jtcsv.com>, August 2000, + September 2002. + +[Simonsen] Keld Simonsen, <Keld.Simonsen@rap.dk>, August 2000. + +[Tantsetthi] Trin Tantsetthi, <trin@mozart.inet.co.th>, September 1998. + +[Tumasonis] Vladas Tumasonis, <vladas.tumasonis@maf.vu.lt>, August 2000. + +[Uskov] Alexander Uskov, <auskov@idc.kz>, September 2002. + +[Wendt] Chris Wendt, <christw@microsoft.com>, December 1999. + +[Yick] Nicky Yick, <cliac@itsd.gcn.gov.hk>, October 2000. + +[] + + + + + + + diff --git a/sys/src/cmd/abaco/cols.c b/sys/src/cmd/abaco/cols.c new file mode 100755 index 000000000..5be689490 --- /dev/null +++ b/sys/src/cmd/abaco/cols.c @@ -0,0 +1,549 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <memdraw.h> +#include <thread.h> +#include <cursor.h> +#include <mouse.h> +#include <keyboard.h> +#include <frame.h> +#include <plumb.h> +#include <html.h> +#include "dat.h" +#include "fns.h" + +void +colinit(Column *c, Rectangle r) +{ + Rectangle r1; + Text *t; + + draw(screen, r, display->white, nil, ZP); + c->r = r; + c->w = nil; + c->nw = 0; + t = &c->tag; + t->w = nil; + t->col = c; + r1 = r; + r1.max.y = r1.min.y + font->height; + textinit(t, screen, r1, font, tagcols); + t->what = Columntag; + r1.min.y = r1.max.y; + r1.max.y += Border; + draw(screen, r1, display->black, nil, ZP); + textinsert(t, 0, L"New Cut Paste Snarf Sort Delcol ", 32); + textsetselect(t, t->rs.nr, t->rs.nr); + draw(screen, t->scrollr, colbutton, nil, colbutton->r.min); + c->safe = TRUE; +} + +Window* +coladd(Column *c, Window *w, Window *clone, int y) +{ + Rectangle r, r1; + Window *v; + int i, t; + + v = nil; + r = c->r; + r.min.y = c->tag.r.max.y+Border; + if(y<r.min.y && c->nw>0){ /* steal half of last window by default */ + v = c->w[c->nw-1]; + y = v->page.all.min.y+Dy(v->page.all)/2; + } + /* look for window we'll land on */ + for(i=0; i<c->nw; i++){ + v = c->w[i]; + if(y < v->r.max.y) + break; + } + if(c->nw > 0){ + if(i < c->nw) + i++; /* new window will go after v */ + /* + * if v's too small, grow it first. + */ + if(!c->safe || Dy(v->page.all)<=3 ){ + colgrow(c, v, 1); + y = v->page.all.min.y+Dy(v->page.all)/2; + } + r = v->r; + if(i == c->nw) + t = c->r.max.y; + else + t = c->w[i]->r.min.y-Border; + r.max.y = t; + r1 = r; + y = min(y, t-(Dy(v->r)-Dy(v->page.all))); + r1.max.y = min(y, v->page.all.min.y+Dy(v->page.all)); + r1.min.y = winresize(v, r1, FALSE); + r1.max.y = r1.min.y+Border; + draw(screen, r1, display->black, nil, ZP); + r.min.y = r1.max.y; + } + if(w == nil){ + w = emalloc(sizeof(Window)); + w->col = c; + wininit(w, clone, r); + }else{ + w->col = c; + winresize(w, r, FALSE); + } + w->tag.col = c; + w->tag.row = c->row; + w->url.col = c; + w->url.row = c->row; + w->page.col = c; + w->page.row = c->row; + w->status.col = c; + w->status.row = c->row; + c->w = realloc(c->w, (c->nw+1)*sizeof(Window*)); + memmove(c->w+i+1, c->w+i, (c->nw-i)*sizeof(Window*)); + c->nw++; + c->w[i] = w; + savemouse(w); + /* near but not on the button */ + moveto(mousectl, addpt(w->tag.scrollr.max, Pt(3, 3))); + c->safe = TRUE; + return w; +} + +void +colclose(Column *c, Window *w, int dofree) +{ + Rectangle r; + int i; + + /* w is locked */ + if(!c->safe) + colgrow(c, w, 1); + for(i=0; i<c->nw; i++) + if(c->w[i] == w) + goto Found; + error("can't find window"); + Found: + r = w->r; + w->tag.col = nil; + w->url.col = nil; + w->page.col = nil; + w->col = nil; + restoremouse(w); + if(dofree) + winclose(w); + memmove(c->w+i, c->w+i+1, (c->nw-i)*sizeof(Window*)); + c->nw--; + c->w = realloc(c->w, c->nw*sizeof(Window*)); + if(c->nw == 0){ + draw(screen, r, display->white, nil, ZP); + return; + } + if(i == c->nw){ /* extend last window down */ + w = c->w[i-1]; + r.min.y = w->r.min.y; + r.max.y = c->r.max.y; + }else{ /* extend next window up */ + w = c->w[i]; + r.max.y = w->r.max.y; + } + if(c->safe) + winresize(w, r, FALSE); +} + +void +colcloseall(Column *c) +{ + int i; + Window *w; + + if(c == activecol) + activecol = nil; + if(seltext && c==seltext->col) + seltext = nil; + textclose(&c->tag); + for(i=0; i<c->nw; i++){ + w = c->w[i]; + w->tag.col = nil; + w->url.col = nil; + w->page.col = nil; + w->col = nil; + winclose(w); + } + c->nw = 0; + free(c->w); + free(c); + clearmouse(); +} + +void +colmousebut(Column *c) +{ + moveto(mousectl, divpt(addpt(c->tag.scrollr.min, c->tag.scrollr.max), 2)); +} + +void +colresize(Column *c, Rectangle r) +{ + int i; + Rectangle r1, r2; + Window *w; + + clearmouse(); + r1 = r; + r1.max.y = r1.min.y + c->tag.font->height; + textresize(&c->tag, screen, r1); + draw(screen, c->tag.scrollr, colbutton, nil, colbutton->r.min); + r1.min.y = r1.max.y; + r1.max.y += Border; + draw(screen, r1, display->black, nil, ZP); + r1.max.y = r.max.y; + for(i=0; i<c->nw; i++){ + w = c->w[i]; + if(i == c->nw-1) + r1.max.y = r.max.y; + else + r1.max.y = r1.min.y+(Dy(w->r)+Border)*Dy(r)/Dy(c->r); + r2 = r1; + r2.max.y = r2.min.y+Border; + draw(screen, r2, display->black, nil, ZP); + r1.min.y = r2.max.y; + r1.min.y = winresize(w, r1, FALSE); + } + c->r = r; +} + +static +int +colcmp(void *a, void *b) +{ + Rune *r1, *r2; + int i, nr1, nr2; + + r1 = (*(Window**)a)->page.title.r; + nr1 = (*(Window**)a)->page.title.nr; + r2 = (*(Window**)b)->page.title.r; + nr2 = (*(Window**)b)->page.title.nr; + for(i=0; i<nr1 && i<nr2; i++){ + if(*r1 != *r2) + return *r1-*r2; + r1++; + r2++; + } + return nr1-nr2; +} + +void +colsort(Column *c) +{ + int i, y; + Rectangle r, r1, *rp; + Window **wp, *w; + + if(c->nw == 0) + return; + clearmouse(); + rp = emalloc(c->nw*sizeof(Rectangle)); + wp = emalloc(c->nw*sizeof(Window*)); + memmove(wp, c->w, c->nw*sizeof(Window*)); + qsort(wp, c->nw, sizeof(Window*), colcmp); + for(i=0; i<c->nw; i++) + rp[i] = wp[i]->r; + r = c->r; + y = c->tag.r.max.y; + for(i=0; i<c->nw; i++){ + w = wp[i]; + r.min.y = y; + if(i == c->nw-1) + r.max.y = c->r.max.y; + else + r.max.y = r.min.y+Dy(w->r)+Border; + r1 = r; + r1.max.y = r1.min.y+Border; + draw(screen, r1, display->black, nil, ZP); + r.min.y = r1.max.y; + y = winresize(w, r, FALSE); + } + free(rp); + free(c->w); + c->w = wp; +} + +void +colgrow(Column *c, Window *w, int but) +{ + Rectangle r, cr; + int i, j, k, l, y1, y2, *nl, *ny, tot, nnl, onl, dnl, h, wnl; + Window *v; + + for(i=0; i<c->nw; i++) + if(c->w[i] == w) + goto Found; + error("can't find window"); + + Found: + cr = c->r; + if(but < 0){ /* make sure window fills its own space properly */ + r = w->r; + if(i==c->nw-1 || c->safe==FALSE) + r.max.y = cr.max.y; + else + r.max.y = c->w[i+1]->r.min.y; + winresize(w, r, FALSE); + return; + } + cr.min.y = c->w[0]->r.min.y; + if(but == 3){ /* full size */ + if(i != 0){ + v = c->w[0]; + c->w[0] = w; + c->w[i] = v; + } + for(j=1; j<c->nw; j++) + c->w[j]->page.all = ZR; + winresize(w, cr, FALSE); + c->safe = FALSE; + return; + } + /* store old #lines for each window */ + wnl = Dy(w->page.all); + onl = wnl; + nl = emalloc(c->nw * sizeof(int)); + ny = emalloc(c->nw * sizeof(int)); + tot = 0; + for(j=0; j<c->nw; j++){ + l = Dy(c->w[j]->page.all); + nl[j] = l; + tot += l; + } + /* approximate new #lines for this window */ + if(but == 2){ /* as big as can be */ + memset(nl, 0, c->nw * sizeof(int)); + goto Pack; + } + nnl = min(onl + max(min(5, wnl), onl/2), tot); + if(nnl < wnl) + nnl = (wnl+nnl)/2; + if(nnl == 0) + nnl = 2; + dnl = nnl - onl; + /* compute new #lines for each window */ + for(k=1; k<c->nw; k++){ + /* prune from later window */ + j = i+k; + if(j<c->nw && nl[j]){ + l = min(dnl, max(1, nl[j]/2)); + nl[j] -= l; + nl[i] += l; + dnl -= l; + } + /* prune from earlier window */ + j = i-k; + if(j>=0 && nl[j]){ + l = min(dnl, max(1, nl[j]/2)); + nl[j] -= l; + nl[i] += l; + dnl -= l; + } + } + Pack: + /* pack everyone above */ + y1 = cr.min.y; + for(j=0; j<i; j++){ + v = c->w[j]; + r = v->r; + r.min.y = y1; + r.max.y = y1+Dy(v->tag.all)+Border+Dy(v->url.all); + if(nl[j]) + r.max.y += 1 + nl[j]; + if(!c->safe || !eqrect(v->r, r)) + winresize(v, r, c->safe); + + r.min.y = v->r.max.y; + r.max.y += Border; + draw(screen, r, display->black, nil, ZP); + y1 = r.max.y; + } + /* scan to see new size of everyone below */ + y2 = c->r.max.y; + for(j=c->nw-1; j>i; j--){ + v = c->w[j]; + r = v->r; + r.min.y = y2-Dy(v->tag.all)-Border-Dy(v->url.all); + if(nl[j]) + r.min.y -= 1 + nl[j]; + r.min.y -= Border; + ny[j] = r.min.y; + y2 = r.min.y; + } + /* compute new size of window */ + r = w->r; + r.min.y = y1; + if(i == c->nw-1) + r.max.y = c->r.max.y; + else{ + r.max.y = r.min.y+Dy(w->tag.all)+Border+Dy(w->url.all); + h = font->height; + if(y2-r.max.y >= 2*(1+h+Border)){ + r.max.y += 1; + r.max.y += h*((y2-r.max.y)/h); + } + } + /* draw window */ + if(!c->safe || !eqrect(w->r, r)) + winresize(w, r, c->safe); + + if(i < c->nw-1){ + r.min.y = r.max.y; + r.max.y += Border; + draw(screen, r, display->black, nil, ZP); + for(j=i+1; j<c->nw; j++) + ny[j] -= (y2-r.max.y); + } + /* pack everyone below */ + y1 = r.max.y; + for(j=i+1; j<c->nw; j++){ + v = c->w[j]; + r = v->r; + r.min.y = y1; + if(j == c->nw-1) + r.max.y = c->r.max.y; + else{ + r.max.y = y1+Dy(v->tag.all)+Border+Dy(v->url.all); + if(nl[j]) + r.max.y += 1 + nl[j]; + } + if(!c->safe || !eqrect(v->r, r)) + winresize(v, r, c->safe); + if(j < c->nw-1){ /* no border on last window */ + r.min.y = v->r.max.y; + r.max.y += Border; + draw(screen, r, display->black, nil, ZP); + } + y1 = r.max.y; + } + free(nl); + free(ny); + c->safe = TRUE; + winmousebut(w); +} + +void +coldragwin(Column *c, Window *w, int but) +{ + Rectangle r; + int i, b; + Point p, op; + Window *v; + Column *nc; + + clearmouse(); + setcursor(mousectl, &boxcursor); + b = mouse->buttons; + op = mouse->xy; + while(mouse->buttons == b) + readmouse(mousectl); + setcursor(mousectl, nil); + if(mouse->buttons){ + while(mouse->buttons) + readmouse(mousectl); + return; + } + + for(i=0; i<c->nw; i++) + if(c->w[i] == w) + goto Found; + error("can't find window"); + + Found: + p = mouse->xy; + if(abs(p.x-op.x)<5 && abs(p.y-op.y)<5){ + colgrow(c, w, but); + winmousebut(w); + return; + } + /* is it a flick to the right? */ + if(abs(p.y-op.y)<10 && p.x>op.x+30 && rowwhichcol(c->row, p)==c) + p.x = op.x+Dx(w->r); /* yes: toss to next column */ + nc = rowwhichcol(c->row, p); + if(nc!=nil && nc!=c){ + colclose(c, w, FALSE); + coladd(nc, w, nil, p.y); + winmousebut(w); + return; + } + if(i==0 && c->nw==1) + return; /* can't do it */ + if((i>0 && p.y<c->w[i-1]->r.min.y) || (i<c->nw-1 && p.y>w->r.max.y) + || (i==0 && p.y>w->r.max.y)){ + /* shuffle */ + colclose(c, w, FALSE); + coladd(c, w, nil, p.y); + winmousebut(w); + return; + } + if(i == 0) + return; + v = c->w[i-1]; + if(p.y < v->url.all.max.y) + p.y = v->url.all.max.y; + if(p.y > w->r.max.y-Dy(w->tag.all)-Border-Dy(w->url.all)) + p.y = w->r.max.y-Dy(w->tag.all)-Border-Dy(w->url.all); + r = v->r; + r.max.y = p.y; + if(r.max.y > v->page.all.min.y){ + r.max.y -= (r.max.y-v->page.all.min.y)%font->height; + if(v->page.all.min.y == v->page.all.max.y) + r.max.y++; + } + if(!eqrect(v->r, r)) + winresize(v, r, c->safe); + r.min.y = v->r.max.y; + r.max.y = r.min.y+Border; + draw(screen, r, display->black, nil, ZP); + r.min.y = r.max.y; + if(i == c->nw-1) + r.max.y = c->r.max.y; + else + r.max.y = c->w[i+1]->r.min.y-Border; + if(!eqrect(w->r, r)) + winresize(w, r, c->safe); + c->safe = TRUE; + winmousebut(w); +} + +Text* +colwhich(Column *c, Point p, Rune r, int key) +{ + Window *w; + Text *t; + int i; + + if(!ptinrect(p, c->r)) + return nil; + if(ptinrect(p, c->tag.all)) + return &c->tag; + for(i=0; i<c->nw; i++){ + w = c->w[i]; + if(ptinrect(p, w->r)){ + winlock(w, key ? 'K' : 'M'); + if(key) + t = wintype(w, p, r); + else + t = winmouse(w, p, r); + winunlock(w); + return t; + } + } + return nil; +} + +int +colclean(Column *c) +{ + int i, clean; + + clean = TRUE; + for(i=0; i<c->nw; i++) + clean &= winclean(c->w[i], TRUE); + return clean; +} diff --git a/sys/src/cmd/abaco/dat.h b/sys/src/cmd/abaco/dat.h new file mode 100755 index 000000000..afe553f5b --- /dev/null +++ b/sys/src/cmd/abaco/dat.h @@ -0,0 +1,355 @@ +typedef struct Box Box; +typedef struct Cimage Cimage; +typedef struct Column Column; +typedef struct Exec Exec; +typedef struct Line Line; +typedef struct Page Page; +typedef struct Row Row; +typedef struct Runestr Runestr; +typedef struct Text Text; +typedef struct Timer Timer; +typedef struct Url Url; +typedef struct Window Window; + +struct Runestr +{ + Rune *r; + int nr; +}; + +enum +{ + Rowtag, + Columntag, + Tag, + Urltag, + Statustag, + Entry, + Textarea, +}; + +struct Text +{ + Frame; + uint org; + uint q0; + uint q1; + int what; + Window *w; + Rectangle scrollr; + Rectangle lastsr; + Rectangle all; + Row *row; + Column *col; + Runestr rs; +}; + +uint textbacknl(Text*, uint, uint); +int textbswidth(Text*, Rune); +int textclickmatch(Text*, int, int, int, uint*); +void textclose(Text*); +void textdelete(Text*, uint, uint); +void textdoubleclick(Text*, uint*, uint*); +void textfill(Text*); +void textframescroll(Text*, int); +void textinit(Text *, Image *, Rectangle, Font *, Image **); +void textinsert(Text*, uint, Rune*, uint); +void textredraw(Text *, Rectangle, Font *, Image *); +int textresize(Text *, Image *, Rectangle); +void textscrdraw(Text*); +void textscroll(Text*, int); +void textselect(Text*); +int textselect2(Text *, uint *, uint *, Text **); +int textselect3(Text *, uint *, uint *); +void textset(Text *, Rune *, int); +void textsetorigin(Text*, uint, int); +void textsetselect(Text*, uint, uint); +void textshow(Text*, uint, uint, int); +void texttype(Text*, Rune); +void textmouse(Text *, Point, int); + +struct Line +{ + Rectangle r; + int state; + int hastext; + int hastable; + Box *boxes; + Box *lastbox; + Line *prev; + Line *next; +}; + +struct Box +{ + Item *i; + Rectangle r; + + void (*draw)(Box *, Page *, Image *); + void (*mouse)(Box *, Page *, int); + void (*key)(Box *, Page *, Rune); + Box *prev; + Box *next; +}; + +Box* boxalloc(Line *, Item *, Rectangle); +void boxinit(Box *); + +struct Lay +{ + Rectangle r; + int width; + int xwall; + Line *lines; + Line *lastline; + Font *font; + Ifloat *floats; + int laying; +}; + +void laypage(Page *p); +Lay* layitems(Item *, Rectangle, int); +void laydraw(Page *, Image *, Lay *); +void layfree(Lay *); + +struct Cimage +{ + Ref; + Image *i; + Memimage *mi; + Url *url; + Cimage *next; +}; + +struct Url +{ + Ref; /* urls in window.url[] are not freed */ + int id; + int method; /* HGet or HPost */ + Runestr src; /* requested url */ + Runestr act; /* actual url (redirection) */ + Runestr post; /* only set if method==HPost */ + Runestr ctype; /* content type */ +}; + +Url* urlalloc(Runestr *, Runestr *, int); +void urlfree(Url *); +Url* urldup(Url *); +int urlopen(Url *); + +struct Page +{ + Url *url; + Runestr title; + Window *w; + Image *b; + + Rectangle r; + Rectangle all; + Rectangle vscrollr; + Rectangle hscrollr; + Row *row; + Column *col; + + Docinfo *doc; + Kidinfo *kidinfo; + Item *items; + Lay *lay; + Point pos; + + int selecting; + Point top, bot; + Box *topbx, *botbx; + + int aborting; + int changed; + int loading; + + Rune *status; + + Page *parent; + Page *child; + Page *next; + + Cimage **cimage; + int ncimage; + + struct{ + long t; + Runestr rs; + }refresh; +}; + +void pageget(Page *, Runestr *, Runestr *, int, int); +void pageload(Page *, Url *, int); +void pageclose(Page *); +void pageredraw(Page *); +void pagerender(Page *); +void pagemouse(Page *, Point, int); +void pagetype(Page *, Rune, Point); +void pagescrldraw(Page *); +void pagescroll(Page *, int, int); +int pagescrollxy(Page *, int, int); +int pageabort(Page *); +void pagesnarf(Page *); +void pagesetrefresh(Page *); +int pagerefresh(Page *); + +struct Window +{ + Ref; + QLock; + Text tag; + Text url; + Page page; + Text status; + int owner; + int inpage; + Rectangle r; + Column *col; + struct{ + Url **url; + int nurl; + int cid; + }history; +}; + +void wininit(Window *, Window *, Rectangle); +int winclean(Window *, int); +void winclose(Window *); +int winresize(Window *, Rectangle, int); +Text* wintext(Window *, Point); +void winlock(Window *, int); +void winunlock(Window *); +void winaddhist(Window *, Url *); +void wingohist(Window *, int); +void winsettag(Window *); +void winseturl(Window *); +void winsetstatus(Window *w, Rune *); +Text* wintype(Window *, Point, Rune); +Text* winmouse(Window *, Point, int); +void winmousebut(Window *); +void windebug(Window *); + +struct Column +{ + Rectangle r; + Text tag; + Row *row; + Window **w; + int nw; + int safe; +}; + +void colinit(Column*, Rectangle); +Window* coladd(Column*, Window*, Window*, int); +void colclose(Column*, Window*, int); +void colcloseall(Column*); +void colresize(Column*, Rectangle); +Text* colwhich(Column*, Point, Rune, int); +void coldragwin(Column*, Window*, int); +void colgrow(Column*, Window*, int); +int colclean(Column*); +void colsort(Column*); +void colmousebut(Column*); + +struct Row +{ + QLock; + Rectangle r; + Text tag; + Column **col; + int ncol; + +}; + +void rowinit(Row*, Rectangle); +Column* rowadd(Row*, Column *c, int); +void rowclose(Row*, Column*, int); +Text* rowwhich(Row*, Point, Rune, int); +Column* rowwhichcol(Row*, Point); +void rowresize(Row*, Rectangle); +void rowdragcol(Row*, Column*, int but); + +struct Exec +{ + char *cmd; + int p[2]; /* p[1] is write to program; p[0] set to prog fd 0*/ + int q[2]; /* q[0] is read from program; q[1] set to prog fd 1 */ + Channel *sync; /* chan(ulong) */ +}; + +struct Timer +{ + int dt; + int cancel; + Channel *c; /* chan(int) */ + Timer *next; +}; + +enum +{ + Scrollsize = 12, + Scrollgap = 4, + Margin = 4, + Border = 2, + Space = 2, + Tabspace = 30, + Boxsize = 12, + WFont = FntR*NumSize+Tiny, + + Panspeed = 4, + Maxtab = 8, + + BUFSIZE = 1024*8, + RBUFSIZE = BUFSIZE/sizeof(Rune), + STACK = 64*1024, +}; + +enum +{ + FALSE, + TRUE, + XXX, +}; + +enum +{ + Light = 0xEEEEEE, + Dark = 0x666666, + Red = 0xBB0000, + Back = 0xCCCCCC, +}; + +Mouse *mouse; +Mousectl *mousectl; +Keyboardctl *keyboardctl; +Image *tagcols[NCOL]; +Image *textcols[NCOL]; +Image *but2col; +Image *but3col; +Image *button; +Image *colbutton; +Font *passfont; +Cursor boxcursor; +Row row; +Text *argtext; +Text *seltext; +Text *typetext; +Page *selpage; +Column *activecol; +char *webmountpt; +int plumbsendfd; +int webctlfd; +char *charset; +int procstderr; + +enum +{ + Kscrolloneup = KF|0x20, + Kscrollonedown = KF|0x21, +}; + +Channel *cplumb; /* chan(Plumbmsg*) */ +Channel *cexit; /* chan(int) */ +Channel *crefresh; /* chan(page *) */ diff --git a/sys/src/cmd/abaco/exec.c b/sys/src/cmd/abaco/exec.c new file mode 100755 index 000000000..59c8f03d2 --- /dev/null +++ b/sys/src/cmd/abaco/exec.c @@ -0,0 +1,531 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <memdraw.h> +#include <thread.h> +#include <cursor.h> +#include <mouse.h> +#include <keyboard.h> +#include <frame.h> +#include <plumb.h> +#include <html.h> +#include "dat.h" +#include "fns.h" + +void del(Text *, Text *, int, int, Rune *, int); +void delcol(Text *, Text *, int, int, Rune *, int); +void cut(Text *, Text *, int, int, Rune *, int); +void exit(Text *, Text *, int, int, Rune *, int); +void get(Text *, Text *, int, int, Rune *, int); +void go(Text *,Text *, int, int, Rune *, int); +void google(Text *,Text *, int, int, Rune *, int); +void new(Text*, Text *, int, int, Rune *, int); +void newcol(Text*, Text *, int, int, Rune *, int); +void paste(Text *, Text *, int, int, Rune *, int); +void sort(Text *, Text *, int, int, Rune *, int); +void stop(Text *, Text *, int, int, Rune *, int); +void debug(Text *, Text *, int, int, Rune *, int); + +typedef struct Exectab Exectab; +struct Exectab +{ + Rune *name; + void (*fn)(Text *, Text *, int, int, Rune *, int); + int flag1; + int flag2; +}; + +Exectab exectab[] = { + { L"Back", go, FALSE, XXX }, + { L"Cut", cut, TRUE, TRUE }, + { L"Debug", debug, XXX, XXX }, + { L"Del", del, XXX, XXX }, + { L"Delcol", delcol, FALSE, TRUE }, + { L"Exit", exit, XXX, XXX }, + { L"Get", get, XXX, XXX }, + { L"Google", google, XXX, XXX }, + { L"New", new, XXX, XXX }, + { L"Newcol", newcol, XXX, XXX }, + { L"Next", go, TRUE, XXX }, + { L"Paste", paste, TRUE, XXX }, + { L"Snarf", cut, TRUE, FALSE }, + { L"Stop", stop, XXX, XXX }, + { L"Sort", sort, XXX, XXX }, + { nil, nil, 0, 0 }, +}; + +static +Exectab* +lookup(Rune *r, int n) +{ + Exectab *e; + int nr; + + r = skipbl(r, n, &n); + if(n == 0) + return nil; + findbl(r, n, &nr); + nr = n-nr; + for(e=exectab; e->name; e++) + if(runeeq(r, nr, e->name, runestrlen(e->name)) == TRUE) + return e; + return nil; +} + +int +isexecc(int c) +{ + if(isalnum(c)) + return 1; + return c=='<' || c=='|' || c=='>'; +} + +void +execute(Text *t, uint aq0, uint aq1, Text *) +{ + uint q0, q1; + Rune *r, *s; + Exectab *e; + int c, n; + + q0 = aq0; + q1 = aq1; + if(q1 == q0){ /* expand to find word (actually file name) */ + /* if in selection, choose selection */ + if(t->q1>t->q0 && t->q0<=q0 && q0<=t->q1){ + q0 = t->q0; + q1 = t->q1; + }else{ + while(q1<t->rs.nr && isexecc(c=t->rs.r[q1]) && c!=':') + q1++; + while(q0>0 && isexecc(c=t->rs.r[q0-1]) && c!=':') + q0--; + if(q1 == q0) + return; + } + } + r = runemalloc(q1-q0); + runemove(r, t->rs.r+q0, q1-q0); + e = lookup(r, q1-q0); + if(e){ + s = skipbl(r, q1-q0, &n); + s = findbl(s, n, &n); + s = skipbl(s, n, &n); + (*e->fn)(t, seltext, e->flag1, e->flag2, s, n); + } + free(r); +} + +void +newcol(Text *et, Text *, int, int, Rune *, int) +{ + Column *c; + + c = rowadd(et->row, nil, -1); + if(c) + winsettag(coladd(c, nil, nil, -1)); +} + +void +delcol(Text *t, Text *, int, int, Rune *, int) +{ + Column *c; + + c = t->col; + if(c==nil || colclean(c)==0) + return; + + rowclose(c->row, c, TRUE); +} + +void +del(Text *et, Text *, int flag1, int, Rune *, int) +{ + if(et->w==nil) + return; + + if(flag1 || winclean(et->w, FALSE)) + colclose(et->col, et->w, TRUE); +} + +void +sort(Text *et, Text *, int, int, Rune *, int) +{ + if(et->col) + colsort(et->col); +} + +void +exit(Text *, Text *, int, int, Rune *, int) +{ + sendul(cexit, 0); + threadexits(nil); +} + +void +debug(Text *, Text *, int, int, Rune *, int) +{ + Column *c; + int i, j; + + for(j=0; j<row.ncol; j++){ + c = row.col[j]; + for(i=0; i<c->nw; i++){ + fprint(2, "Col: %d; Win: %d\n", j, i); + windebug(c->w[i]); + } + } +} + +void +stop(Text *t, Text *, int, int, Rune *, int) +{ + if(t==nil || t->w==nil) + return; + + pageabort(&t->w->page); +} + +void +get(Text *t, Text *, int, int, Rune *, int) +{ + Window *w; + int dohist; + + if(t==nil || t->w==nil) + return; + w = t->w; + if(w->url.rs.nr == 0) + return; + + dohist = FALSE; + if(w->page.url==nil || runestreq(w->page.url->act, w->url.rs)==FALSE) + dohist = TRUE; + + pageget(&w->page, &w->url.rs, nil, HGet, dohist); +} + +void +go(Text *et, Text *t, int isnext, int, Rune *, int) +{ + if(et!=nil && et->w!=nil) + t = et; + if(t==nil || t->w==nil) + return; + + wingohist(t->w, isnext); +} + +void +cut(Text *, Text *t, int dosnarf, int docut, Rune *, int) +{ + Runestr rs; + uint u; + + if(selpage){ + if(dosnarf && !docut && !eqpt(selpage->top, selpage->bot)) + pagesnarf(selpage); + return; + } + if(t==nil){ + /* can only happen if seltext == nil */ + return; + } + if(t->q0 > t->q1){ + u = t->q0; + t->q0 = t->q1; + t->q1 =u; + } + + if(t->q0 == t->q1) + return; + + if(dosnarf){ + rs.nr = t->q1-t->q0; + rs.r = runemalloc(rs.nr); + runemove(rs.r, t->rs.r+t->q0, rs.nr); + putsnarf(&rs); + closerunestr(&rs); + } + if(docut){ + textdelete(t, t->q0, t->q1); + textsetselect(t, t->q0, t->q0); + if(t->w) + textscrdraw(t); + }else if(dosnarf) /* Snarf command */ + argtext = t; +} + +void +paste(Text *, Text *t, int selectall, int, Rune *, int) +{ + Runestr rs; + uint q1; + + if(t == nil) + return; + + getsnarf(&rs); + if(rs.nr == 0) + return; + + cut(t, t, FALSE, TRUE, nil, 0); + textinsert(t, t->q0, rs.r, rs.nr); + q1 = t->q0+rs.nr; + if(selectall) + textsetselect(t, t->q0, q1); + else + textsetselect(t, q1, q1); + if(t->w) + textscrdraw(t); + + closerunestr(&rs); +} + +typedef struct Expand Expand; + +struct Expand +{ + uint q0; + uint q1; + Rune *name; + int nname; + int jump; + union{ + Text *at; + Rune *ar; + }; + int (*agetc)(void*, uint); + int a0; + int a1; +}; + +int +expand(Text *t, uint q0, uint q1, Expand *e) +{ + memset(e, 0, sizeof *e); + + /* if in selection, choose selection */ + e->jump = TRUE; + if(q1==q0 && t->q1>t->q0 && t->q0<=q0 && q0<=t->q1){ + q0 = t->q0; + q1 = t->q1; + if(t->what == Tag) + e->jump = FALSE; + } + if(q0 == q1){ + while(q1<t->rs.nr && isalnum(t->rs.r[q1])) + q1++; + while(q0>0 && isalnum(t->rs.r[q0-1])) + q0--; + } + e->q0 = q0; + e->q1 = q1; + return q1 > q0; +} + +void +look3(Text *t, uint q0, uint q1) +{ + Expand e; + Text *ct; + Runestr rs; + char buf[32]; + Rune *r, c; + uint p; + int n; + + ct = seltext; + if(ct == nil) + ct = seltext = t; + if(expand(t, q0, q1, &e) == FALSE) + return; + if(plumbsendfd >= 0){ + /* send whitespace-delimited word to plumber */ + buf[0] = '\0'; + if(q1 == q0){ + if(t->q1>t->q0 && t->q0<=q0 && q0<=t->q1){ + q0 = t->q0; + q1 = t->q1; + }else{ + p = q0; + while(q0>0 && (c=t->rs.r[q0-1])!=L' ' && c!=L'\t' && c!=L'\n') + q0--; + while(q1<t->rs.nr && (c=t->rs.r[q1])!=L' ' && c!=L'\t' && c!=L'\n') + q1++; + if(q1 == q0) + return; + sprint(buf, "click=%d", p-q0); + } + } + rs.r = runemalloc(q1-q0); + runemove(rs.r, t->rs.r+q0, q1-q0); + rs.nr = q1-q0; + if(plumbrunestr(&rs, buf) >= 0){ + closerunestr(&rs); + return; + } + /* plumber failed to match; fall through */ + } + if(t == ct) + textsetselect(ct, e.q1, e.q1); + n = e.q1 - e.q0; + r = runemalloc(n); + runemove(r, t->rs.r+e.q0, n); + if(search(ct, r, n) && e.jump) + moveto(mousectl, addpt(frptofchar(ct, ct->p0), Pt(4, ct->font->height-4))); + + free(r); +} + +int +search(Text *ct, Rune *r, uint n) +{ + uint q, nb, maxn; + int around; + Rune *s, *b, *c; + + if(n==0 || n>ct->rs.nr || 2*n>RBUFSIZE) + return FALSE; + + maxn = max(n*2, RBUFSIZE); + s = runemalloc(RBUFSIZE); + b = s; + nb = 0; + b[nb] = 0; + around = 0; + q = ct->q1; + for(;;){ + if(q >= ct->rs.nr){ + q = 0; + around = 1; + nb = 0; + b[nb] = 0; + } + if(nb > 0){ + c = runestrchr(b, r[0]); + if(c == nil){ + q += nb; + nb = 0; + b[nb] = 0; + if(around && q>=ct->q1) + break; + continue; + } + q += (c-b); + nb -= (c-b); + b = c; + } + /* reload if buffer covers neither string nor rest of file */ + if(nb<n && nb!=ct->rs.nr-q){ + nb = ct->rs.nr-q; + if(nb >= maxn) + nb = maxn-1; + runemove(s, ct->rs.r+q, nb); + b = s; + b[nb] = '\0'; + } + /* this runeeq is fishy but the null at b[nb] makes it safe */ + if(runeeq(b, n, r, n) == TRUE){ + if(ct->w) + textshow(ct, q, q+n, 1); + else{ + ct->q0 = q; + ct->q1 = q+n; + } + seltext = ct; + free(s); + return TRUE; + } + if(around && q>=ct->q1) + break; + --nb; + b++; + q++; + } + free(s); + return FALSE; +} + +Window* +lookpage(Rune *s, int n) +{ + int i, j; + Window *w; + Column *c; + Page *p; + + /* avoid terminal slash on directories */ + if(n>1 && s[n-1] == '/') + --n; + for(j=0; j<row.ncol; j++){ + c = row.col[j]; + for(i=0; i<c->nw; i++){ + w = c->w[i]; + p = &w->page; + if(p->url && runeeq(p->url->src.r, p->url->src.nr, s, n)) + if(w->col != nil) + return w; + } + } + return nil; +} + +Window * +openpage(Page *p, Runestr *rs) +{ + Window *w; + + if(!validurl(rs->r)) + return nil; + + w = lookpage(rs->r, rs->nr); + if(w){ + p = &w->page; + if(!p->col->safe && Dy(p->r)==0) /* window is obscured by full-column window */ + colgrow(p->col, p->col->w[0], 1); + }else{ + w = makenewwindow(p); + winsettag(w); + pageget(&w->page, rs, nil, HGet, TRUE); + } + return w; +} + +void +plumblook(Plumbmsg *m) +{ + Runestr rs; + + if(m->ndata >= BUFSIZE){ + fprint(2, "insanely long file name (%d bytes) in plumb message (%.32s...)\n", m->ndata, m->data); + return; + } + if(m->data[0] == '\0') + return; + + bytetorunestr(m->data, &rs); + openpage(nil, &rs); + closerunestr(&rs); +} + +void +new(Text *et, Text *, int, int, Rune *, int) +{ + if(et->col != nil) + winsettag(coladd(et->col, nil, nil, -1)); +} + +void +google(Text *, Text *, int, int, Rune *arg, int narg) +{ + Runestr rs; + Rune *s; + + s = ucvt(arg); + rs.r = runesmprint("http://www.google.com/search?hl=en&ie=UTF-8&q=%.*S", narg, s); + rs.nr = runestrlen(rs.r); + openpage(nil, &rs); + free(s); + closerunestr(&rs); +} diff --git a/sys/src/cmd/abaco/fns.h b/sys/src/cmd/abaco/fns.h new file mode 100755 index 000000000..3e739a7e8 --- /dev/null +++ b/sys/src/cmd/abaco/fns.h @@ -0,0 +1,85 @@ +#define runemalloc(a) emalloc((a)*sizeof(Rune)) +#define runerealloc(a, b) erealloc(a, (b)*sizeof(Rune)) +#define runemove(a, b, c) memmove(a, b, (c)*sizeof(Rune)) + +#define hasbrk(x) ((x)&IFbrk || (x)&IFbrksp) +#define istrue(x) ((x) ? "true" : "false") + +void plumblook(Plumbmsg*m); +int plumbrunestr(Runestr *, char *); +void putsnarf(Runestr *); +void getsnarf(Runestr *); + +void tablesize(Table *, int); +void drawtable(Box *, Page *, Image *); +void laytable(Itable *, Rectangle); +void settables(Page *); +void laysnarf(Page *, Lay *, Runestr *); +Timer* timerstart(int); +void timerstop(Timer*); +void timercancel(Timer*); +void timerinit(void); + +void cut(Text *, Text *, int, int, Rune *, int); +void get(Text *, Text *, int, int, Rune *, int); +void paste(Text *, Text *, int, int, Rune *, int); +void execute(Text *, uint, uint, Text *); +void look3(Text *, uint, uint); +int search(Text *, Rune *, uint); + +void scrsleep(uint); +void scrlresize(void); +void tmpresize(void); + +void initfontpaths(void); +void cvttorunes(char*, int, Rune*, int*, int*, int*); +void error(char *); +void closerunestr(Runestr *); +void copyrunestr(Runestr *, Runestr *); +int runestreq(Runestr, Runestr); +int validurl(Rune *); +int runeeq(Rune *, uint, Rune *, uint); +int min(int, int); +int max(int, int); +int isalnum(Rune); +Rune* skipbl(Rune *, int, int *); +Rune* findbl(Rune *r, int, int *); +char* estrdup(char *); +Rune* erunestrdup(Rune *); +Rune* ucvt(Rune *s); +int dimwidth(Dimen , int); +void frdims(Dimen *, int, int, int **); +Image* getbg(Page *); +Rune* getbase(Page *); +Image* eallocimage(Display *, Rectangle, ulong, int, int); +Image* getcolor(int); +void freecolors(void); +Font* getfont(int); +void freefonts(void); +void colarray(Image **, Image *, Image *, Image *, int); +void rect3d(Image *, Rectangle, int, Image **, Point); +void ellipse3d(Image *, Point, int, int, Image **, Point); +void reverseimages(Iimage **); +void setstatus(Window *, char *, ...); +int istextfield(Item *); +int forceitem(Item *); +int xtofchar(Rune *, Font *, long); +int istextsel(Page *, Rectangle, int *, int *, Rune *, Font *); +char* convert(Runestr, char *, long *); +void execproc(void *); +void getimage(Cimage *, Rune *); +Point getpt(Page *p, Point); +Rune *urlcombine(Rune *, Rune *); +void fixtext(Page *); +void addrefresh(Page *, char *, ...); +void flushrefresh(void); +void savemouse(Window *); +void restoremouse(Window *); +void clearmouse(void); +void bytetorunestr(char *, Runestr *); +Window* makenewwindow(Page *); + +Line* linewhich(Lay *, Point); +Box* pttobox(Line *, Point); +Box* boxwhich(Lay *, Point); + diff --git a/sys/src/cmd/abaco/fonts.h b/sys/src/cmd/abaco/fonts.h new file mode 100755 index 000000000..54719852c --- /dev/null +++ b/sys/src/cmd/abaco/fonts.h @@ -0,0 +1,20 @@ + "/lib/font/bit/lucidasans/unicode.6.font", + "/lib/font/bit/lucidasans/unicode.7.font", + "/lib/font/bit/lucidasans/unicode.8.font", + "/lib/font/bit/lucidasans/unicode.10.font", + "/lib/font/bit/lucidasans/unicode.13.font", + "/lib/font/bit/lucidasans/italicunicode.6.font", + "/lib/font/bit/lucidasans/italicunicode.7.font", + "/lib/font/bit/lucidasans/italicunicode.8.font", + "/lib/font/bit/lucidasans/italicunicode.10.font", + "/lib/font/bit/lucidasans/italicunicode.13.font", + "/lib/font/bit/lucidasans/boldunicode.6.font", + "/lib/font/bit/lucidasans/boldunicode.7.font", + "/lib/font/bit/lucidasans/boldunicode.8.font", + "/lib/font/bit/lucidasans/boldunicode.10.font", + "/lib/font/bit/lucidasans/boldunicode.13.font", + "/lib/font/bit/fixed/unicode.6x12.font", + "/lib/font/bit/fixed/unicode.8x13.font", + "/lib/font/bit/fixed/unicode.9x15.font", + "/lib/font/bit/fixed/unicode.9x18.font", + "/lib/font/bit/fixed/unicode.10x20.font", diff --git a/sys/src/cmd/abaco/html.c b/sys/src/cmd/abaco/html.c new file mode 100755 index 000000000..9a53eec53 --- /dev/null +++ b/sys/src/cmd/abaco/html.c @@ -0,0 +1,1072 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <memdraw.h> +#include <thread.h> +#include <cursor.h> +#include <mouse.h> +#include <keyboard.h> +#include <frame.h> +#include <plumb.h> +#include <html.h> +#include "dat.h" +#include "fns.h" + +static void sizeitem(Lay *, Item *); + +static +void +sizetext(Lay *lay, Itext *i) +{ + lay->font = getfont(i->fnt); + i->height = lay->font->height + 2*Space; + i->width = runestringwidth(lay->font, i->s); + i->width += runestringnwidth(lay->font, L" ", 1); +} + +static +void +sizerule(Lay *lay, Irule *i) +{ + i->width = lay->width; + i->height = Space + i->size + Space; +} + +static +void +sizeimage(Lay *, Iimage *i) +{ + Cimage *ci; + + ci = (Cimage *)i->aux; + + if(ci==nil) + return; + + if(ci->i == nil) + getimage(ci, i->altrep); + if(ci->i == nil) + return; + i->width = Dx(ci->i->r) + i->border + i->hspace; + i->height = Dy(ci->i->r) + i->border + i->vspace; +} + +static +void +sizetextfield(Lay *, Iformfield *i) +{ + Formfield *ff; + Font *f; + int w, h; + + ff = i->formfield; + if(ff->ftype == Ftextarea){ + w = ff->cols; + h = ff->rows; + }else{ + w = ff->size; + h = 1; + } + f = getfont(WFont); + i->width = runestringnwidth(f, L"0", 1)*w + 2*(Space+Border+Margin); + i->width += Scrollsize+Scrollgap; + i->height = f->height*h + 2*(Space+Border+Margin); +} + +static +void +sizecheck(Lay *, Iformfield *i) +{ + i->width = Boxsize + Space; + i->height = Boxsize; +} + +static +void +sizebutton(Lay *, Iformfield *i) +{ + Font *f; + int x; + + x = Margin + Border + Space; + f = getfont(WFont); + i->width = runestringwidth(f, i->formfield->value) + 2*x + Space; + i->height = f->height + 2*x; +} + +static +void +sizefimage(Lay *lay, Iformfield *i) +{ + Iimage *ii; + + ii = (Iimage *)i->formfield->image; + sizeimage(lay, ii); + i->width = ii->width; + i->height = ii->height; +} + +static +void +sizeselect(Lay *, Iformfield *i) +{ + Option *o; + Font *f; + int x; + + f = getfont(WFont); + i->width = 0; + for(o=i->formfield->options; o!=nil; o=o->next) + i->width = max(i->width, runestringwidth(f, o->display)); + x = Margin + Border + Space; + i->width += 2*x; + i->height = f->height+2*x; +} + +static +void +sizeformfield(Lay *lay, Iformfield *i) +{ + int type; + + type = i->formfield->ftype; + + if(type==Ftext || type==Ftextarea || type==Fpassword) + sizetextfield(lay, i); + else if(type==Fcheckbox || type==Fradio) + sizecheck(lay, i); + else if(type==Fbutton || type==Freset || type==Fsubmit) + sizebutton(lay, i); + else if(type == Fimage) + sizefimage(lay, i); + else if(type == Fselect) + sizeselect(lay, i); +} + +static +void +sizetable(Lay *lay, Itable *i) +{ + tablesize(i->table, lay->width); + i->width = i->table->totw; + i->height = i->table->toth; +} + +static +void +sizefloat(Lay *lay, Ifloat *i) +{ + sizeitem(lay, i->item); + i->width = i->item->width; + i->height = i->item->height; +} + +static +void +sizespacer(Lay *lay, Ispacer *i) +{ + if(i->spkind != ISPnull){ + if(i->spkind == ISPhspace) + i->width = stringnwidth(lay->font, " ", 1); + i->height = lay->font->height + 2*Space; + } +} + +static +void +sizeitem(Lay *lay, Item *i) +{ + + switch(i->tag){ + case Itexttag: + sizetext(lay, (Itext *)i); + break; + case Iruletag: + sizerule(lay, (Irule *)i); + break; + case Iimagetag: + sizeimage(lay, (Iimage *)i); + break; + case Iformfieldtag: + sizeformfield(lay, (Iformfield *)i); + break; + case Itabletag: + sizetable(lay, (Itable *)i); + break; + case Ifloattag: + sizefloat(lay, (Ifloat *)i); + break; + case Ispacertag: + sizespacer(lay, (Ispacer *)i); + break; + default: + error("can't happen"); + } +} + +static +void +drawtext(Box *b, Page *p, Image *im) +{ + Rectangle r, r1; + Image *c; + Point pt; + Font *f; + Itext *i; + int q0, q1; + + r = rectsubpt(b->r, p->pos); + i = (Itext *)b->i; + f = getfont(i->fnt); + if(istextsel(p, b->r, &q0, &q1, i->s, f)){ + r1 = r; + if(q0 > 0) + r1.min.x += runestringnwidth(f, i->s, q0); + if(q1 > 0) + r1.max.x = r1.min.x + runestringnwidth(f, i->s+q0, q1-q0); + draw(im, r1, textcols[HIGH], nil, ZP); + } + c = getcolor(i->fg); + runestringbg(im, r.min, c, ZP, f, i->s, im, addpt(r.min, im->r.min)); + + if(i->ul == ULnone) + return; + + if(i->ul == ULmid) + r.min.y += f->height/2; + else + r.min.y +=f->height-1; + pt = r.min; + pt.x += runestringwidth(f, i->s); + line(im, r.min, pt, Enddisc, Enddisc, 0, c, ZP); +} + +static +void +drawrule(Box *b, Page *p, Image *im) +{ + Rectangle r; + Irule *i; + + i = ((Irule *)b->i); + r = rectsubpt(b->r, p->pos); + r.min.y += Space; + r.max.y -=Space; + draw(im, r, getcolor(i->color), nil, ZP); +} + +static +void +drawimage(Box *b, Page *p, Image *im) +{ + Rectangle r; + Cimage *ci; + Iimage *i; + Image *c; + + if(b->i->tag==Iimagetag) + i = (Iimage *)b->i; + else + i = (Iimage *)((Iformfield *)b->i)->formfield->image; + + ci = (Cimage *)i->aux; + if(ci==nil || ci->i==nil) + return; + + r = rectsubpt(b->r, p->pos); + r.min.x += i->border + i->hspace; + r.min.y += i->border + i->vspace; + r.max.x -= i->border + i->hspace; + r.max.y -= i->border + i->vspace; + + draw(im, r, ci->i, nil, ci->i->r.min); + + if(i->border){ + if(i->anchorid >= 0) + c = getcolor(p->doc->link); + else + c = display->black; + + border(im, r, i->border, c, ZP); + } +} + +static +void +drawtextfield(Image *im, Rectangle r, Iformfield *i) +{ + Formfield *ff; + Image *c[3]; + Text *t; + Font *f; + + r = insetrect(r, Space); + colarray(c, getcolor(Dark), getcolor(Light), display->white, 1); + rect3d(im, r, Border, c, ZP); + r = insetrect(r, Border+Margin); + + if(i->aux == nil){ + ff = i->formfield; + t = emalloc(sizeof(Text)); + if(ff->ftype == Ftextarea) + t->what = Textarea; + else + t->what = Entry; + if(ff->ftype == Fpassword) + f = passfont; + else + f = getfont(WFont); + textinit(t, im, r, f, textcols); + if(ff->value!=nil){ + textinsert(t, 0, ff->value, runestrlen(ff->value)); + textsetselect(t, t->rs.nr, t->rs.nr); + } + if(t->what == Textarea) + textscrdraw(t); + i->aux = t; + }else + textresize(i->aux, im, r); +} + +void +drawcheck(Image *im, Rectangle r, Formfield *f) +{ + Image *c[3]; + Point pt; + int n; + + if(f->flags & FFchecked) + colarray(c, getcolor(Dark), getcolor(Light), getcolor(Red), TRUE); + else + colarray(c, getcolor(Dark), getcolor(Light), getcolor(Back), FALSE); + + if(f->ftype == Fradio){ + n = Boxsize/2-1; + pt = addpt(r.min, Pt(n,n)); + ellipse3d(im, pt, n, Border, c, ZP); + }else + rect3d(im, r, Border, c, ZP); +} + +void +drawbutton(Image *im, Rectangle r, Formfield *f, int checked) +{ + Image *c[3]; + + r = insetrect(r, Space); + colarray(c, getcolor(Dark), getcolor(Light), getcolor(Back), checked); + rect3d(im, r, Border, c, ZP); + r.min.x += Border + Margin; + r.min.y += Border + Margin; + runestringbg(im, r.min, display->black, ZP, getfont(WFont), f->value, c[2], ZP); +} + +void +drawselect(Image *im, Rectangle r, Iformfield *i) +{ + Formfield *f; + Image *c[3]; + + f = i->formfield; + if(f->options == nil) + return; + r = insetrect(r, Space); + colarray(c, getcolor(Dark), getcolor(Light), display->white, 1); + rect3d(im, r, Border, c, ZP); + r = insetrect(r, Border+Margin); + draw(im, r, textcols[HIGH], nil, ZP); + if(i->aux==nil){ + i->aux = f->options->display; + i->formfield->value = erunestrdup(f->options->value); + } + runestring(im, r.min, display->black, ZP, getfont(WFont), i->aux); +} + +/* Formfields are a special case */ +static +void +drawformfield(Box *b, Page *p, Image *im) +{ + Formfield *f; + int type; + + f = ((Iformfield *)b->i)->formfield; + type =f->ftype; + if(istextfield(b->i)) + drawtextfield(im, rectsubpt(b->r, p->pos), (Iformfield *)b->i); + else if(type==Fcheckbox || type==Fradio) + drawcheck(im, rectsubpt(b->r, p->pos), f); + else if(type==Fbutton || type==Freset || type==Fsubmit) + drawbutton(im, rectsubpt(b->r, p->pos), f, FALSE); + else if(type == Fimage) + drawimage(b, p, im); + else if(type == Fselect) + drawselect(im, rectsubpt(b->r, p->pos), (Iformfield *)b->i); +} + +static +void +drawnull(Box *, Page *, Image *) +{ +} + +static +Page * +whichtarget1(Page *p, Rune *r) +{ + Kidinfo *k; + Page *c, *ret; + + k = p->kidinfo; + if(k && k->name && runestrcmp(k->name, r)==0) + return p; + for(c=p->child; c; c=c->next){ + ret = whichtarget1(c, r); + if(ret) + return ret; + } + return nil; +} + +static +Page * +whichtarget(Page *p, int t) +{ + Page *r; + + switch(t){ + case FTblank: + case FTtop: + r = &p->w->page; + break; + case FTself: + r = p; + break; + case FTparent: + r = p->parent; + break; + default: + if(targetname(t) == L"?") + error("targetname"); + r = whichtarget1(&p->w->page, targetname(t)); + } + + return r ? r: &p->w->page; +} + +static +void +mouselink(Box *b, Page *p, int but) +{ + Runestr rs; + Anchor *a; + + /* eat mouse */ + while(mousectl->buttons) + readmouse(mousectl); + + if(b->i->anchorid < 0) + return; + + /* binary search would be better */ + for(a=p->doc->anchors; a!=nil; a=a->next) + if(a->index == b->i->anchorid) + break; + + if(a==nil || a->href==nil) + return; + + p = whichtarget(p, a->target); + rs.r = urlcombine(getbase(p), a->href); + if(rs.r == nil) + return; + rs.nr = runestrlen(rs.r); + + if(but == 1) + pageget(p, &rs, nil, HGet, p==&p->w->page); + else if(but == 2) + textset(&p->w->status, rs.r, rs.nr); + else if(but == 3) + plumbrunestr(&rs, nil); + closerunestr(&rs); +} + +static +void +submit(Page *p, Formfield *formfield, int subfl) +{ + Formfield *f; + Form *form; + Runestr src, post; + Rune *x, *sep, *y, *z; + + form = formfield->form; + x = erunestrdup(L""); + sep = L""; + for(f=form->fields; f!=nil; f=f->next){ + if(f->ftype == Freset) + continue; + if((f->ftype==Fradio || f->ftype==Fcheckbox) && !(f->flags&FFchecked)) + continue; + if(f->ftype==Fsubmit && (f!=formfield || !subfl)) + continue; + if(f->value==nil || f->name==nil || runestrcmp(f->name, L"_no_name_submit_")==0) + continue; + + z = ucvt(f->value); + y = runesmprint("%S%S%S=%S", x, sep, f->name, z); + free(z); + sep = L"&"; + free(x); + x = y; + } + p = whichtarget(p, form->target); + y = urlcombine(getbase(p), form->action); + + memset(&src, 0, sizeof(Runestr)); + memset(&post, 0, sizeof(Runestr)); + if(form->method == HGet){ + if(y[runestrlen(y)-1] == L'?') + sep = L""; + else + sep = L"?"; + src.r = runesmprint("%S%S%S",y, sep, x); + free(x); + free(y); + }else{ + src.r = y; + post.r = x; + post.nr = runestrlen(x); + if(post.nr == 0){ + free(post.r); + post.r = nil; + } + } + src.nr = runestrlen(src.r); + pageget(p, &src, &post, form->method, p==&p->w->page); + closerunestr(&src); + closerunestr(&post); +} + +static +void +setradios(Formfield *formfield) +{ + Formfield *f; + + for(f=formfield->form->fields; f!=nil; f=f->next) + if(f->ftype==Fradio && f!=formfield && runestrcmp(f->name, formfield->name)==0) + f->flags &=~FFchecked; +} + +static +void +selectmouse(Box *b, Page *p, int but) +{ + Formfield *f; + Option *o; + Menu m; + char **item; + int i, n; + + f = ((Iformfield *)b->i)->formfield; + n = 0; + item = nil; + for(o=f->options; o!=nil; o=o->next){ + item = erealloc(item, ++n*sizeof(char *)); + if(o->display) + item[n-1] = smprint("%S", o->display); + else + item[n-1] = estrdup("--"); + } + if(item == nil) + return; + + item[n] = 0; + m.item = item; + i = menuhit(but, mousectl, &m, nil); + if(i >= 0){ + for(o=f->options; o!=nil; o=o->next, i--){ + if(i == 0) + break; + } + ((Iformfield *)b->i)->aux = o->display; + drawselect(p->b, rectaddpt(rectsubpt(b->r, p->pos), p->r.min), (Iformfield *)b->i); + if(f->value != nil) + free(f->value); + f->value = erunestrdup(o->value); + } + for(i=0; i< n; i++) + free(item[i]); +// free(item); +} + +static +void +mouseform(Box *b, Page *p, int but) +{ + Rectangle r, cr; + Formfield *f; + Text *t; + + f = ((Iformfield *)b->i)->formfield; + r = rectaddpt(rectsubpt(b->r, p->pos), p->r.min); + if(istextfield(b->i)){ + cr = p->b->clipr; + replclipr(p->b, 0, p->r); + t = ((Iformfield *)b->i)->aux; + if(p->b != t->b) + drawtextfield(p->b, r, (Iformfield *)b->i); + textmouse(t, mouse->xy, but); + if(f->value) + free(f->value); + f->value = runesmprint("%.*S", t->rs.nr, t->rs.r); + replclipr(p->b, 0, cr); + return; + } + + if(but != 1) + return; + + if(f->ftype==Fselect){ + selectmouse(b, p, but); + return; + } + if(f->ftype==Fsubmit || f->ftype==Fimage){ + if(f->ftype == Fsubmit) + drawbutton(p->b, r, f, TRUE); + while(mouse->buttons == but) + readmouse(mousectl); + if(f->ftype == Fsubmit) + drawbutton(p->b, r, f, FALSE); + if(mouse->buttons==0 && ptinrect(mouse->xy, r)) + submit(p, f, TRUE); + return; + } + if(f->ftype==Fradio || f->ftype==Fcheckbox){ + if(f->flags&FFchecked){ + if(f->ftype==Fcheckbox) + f->flags &=~FFchecked; + }else{ + f->flags |= FFchecked; + } + if(f->ftype == Fradio) + setradios(f); + pageredraw(p); + } +} + +static +void +keyform(Box *b, Page *p, Rune r) +{ + Rectangle cr; + Formfield *f; + Text *t; + + f = ((Iformfield *)b->i)->formfield; + if(r==L'\n' && f->ftype==Ftext){ + submit(p, f, FALSE); + return; + } + t = ((Iformfield *)b->i)->aux; + cr = p->b->clipr; + replclipr(p->b, 0, p->r); + if(t->b != p->b) + drawtextfield(p->b, rectaddpt(rectsubpt(b->r, p->pos), p->r.min), (Iformfield *)b->i); + texttype(t, r); + if(f->value) + free(f->value); + f->value = runesmprint("%.*S", t->rs.nr, t->rs.r); + replclipr(p->b, 0, cr); +} + +void +boxinit(Box *b) +{ + if(b->i->anchorid) + b->mouse = mouselink; + /* override mouselink for forms */ + if(b->i->tag == Iformfieldtag){ + b->mouse = mouseform; + if(istextfield(b->i)) + b->key = keyform; + } + switch(b->i->tag){ + case Itexttag: + b->draw = drawtext; + break; + case Iruletag: + b->draw = drawrule; + break; + case Iimagetag: + b->draw = drawimage; + break; + case Iformfieldtag: + b->draw = drawformfield; + break; + case Itabletag: + b->draw = drawtable; + break; + case Ifloattag: + b->draw = drawnull; + break; + case Ispacertag: + b->draw = drawnull; + } +} + +Box * +boxalloc(Line *l, Item *i, Rectangle r) +{ + Box *b; + + b = emalloc(sizeof(Box)); + b->i = i; + b->r = r; + if(l->boxes == nil) + l->boxes = b; + else{ + b->prev = l->lastbox; + l->lastbox->next = b; + } + l->lastbox = b; + + return b; +} + +Box * +pttobox(Line *l, Point xy) +{ + Box *b; + + for(b=l->boxes; b!=nil; b=b->next) + if(ptinrect(xy, b->r)) + return b; + + return nil; +} + +static +Line * +tbtoline(Itable *i, Point xy) +{ + Tablecell *c; + + for(c=i->table->cells; c!=nil; c=c->next) + if(ptinrect(xy, c->lay->r)) + return linewhich(c->lay, xy); + + return nil; +} + +Line * +linewhich(Lay *lay, Point xy) +{ + Line *l, *t; + Box *b; + + t = nil; + for(l=lay->lines; l!=nil; l=l->next) + if(ptinrect(xy, l->r)) + break; + + if(l!=nil && l->hastable){ + b = pttobox(l, xy); + if(b!=nil && b->i->tag==Itabletag) + t = tbtoline((Itable *)b->i, xy); + } + return t? t: l; +} + +Box * +boxwhich(Lay *lay, Point xy) +{ + Line *l; + + l = linewhich(lay, xy); + if(l) + return pttobox(l, xy); + + return nil; +} + +static void justline1(Line *, int); + +static +void +justlay(Lay *lay, int x) +{ + Line *l; + + lay->r.min.x += x; + lay->r.max.x += x; + + for(l=lay->lines; l!=nil; l=l->next) + justline1(l, x); +} + +static +void +justtable(Itable *i, int x) +{ + Tablecell *c; + + for(c=i->table->cells; c!=nil; c=c->next) + justlay(c->lay, x); +} + +static +void +justline1(Line *l, int x) +{ + Box *b; + + l->r.min.x += x; + l->r.max.x += x; + for(b=l->boxes; b!=nil; b=b->next){ + if(b->i->tag == Itabletag) + justtable((Itable *)b->i, x); + b->r.min.x += x; + b->r.max.x += x; + } +} + +static +void +justline(Lay *lay, Line *l) +{ + + int w, x; + + w = Dx(l->r); + if(w>0 && w<lay->width){ + x = 0; + if(l->state & IFrjust) + x = lay->width - w; + else if(l->state & IFcjust) + x = lay->width/2 - w/2; + if(x > 0) + justline1(l, x); + } +} + +static +void +newline(Lay *lay, int state) +{ + Line *l, *last; + int indent, nl; + + last = lay->lastline; + if(lay->laying == TRUE) + justline(lay, last); + + lay->r.max.x = max(lay->r.max.x, last->r.max.x); + lay->r.max.y = last->r.max.y; + + indent = ((state&IFindentmask)>>IFindentshift) * Tabspace; + nl = (state & IFbrksp) ? 1 : 0; + + l = emalloc(sizeof(Line)); + l->state = state; + l->hastext = FALSE; + l->hastable = FALSE; + l->r.min.x = lay->r.min.x + indent; + l->r.min.y = last->r.max.y + font->height*nl; + l->r.max = l->r.min; + l->prev = last; + last->next = l; + lay->lastline = l; +} + + +static +void +layitem(Lay *lay, Item *i) +{ + Rectangle r; + Line *l; + Box *b; + + if(i->state&IFbrk || i->state&IFbrksp) + newline(lay, i->state); + else if(lay->lastline->r.max.x+i->width>lay->xwall && forceitem(i)==FALSE) + newline(lay, i->state); + + l = lay->lastline; + r = Rect(l->r.max.x, l->r.min.y, l->r.max.x+i->width, l->r.min.y+i->height); + l->r.max.x = r.max.x; + if(l->r.max.y < r.max.y) + l->r.max.y = r.max.y; + + if(i->tag == Ifloattag) + i = ((Ifloat *)i)->item; + if(i->tag == Itexttag) + l->hastext = TRUE; + else if(i->tag == Itabletag && lay->laying==TRUE){ + laytable((Itable *)i, r); + l->hastable = TRUE; + } + b = boxalloc(l, i, r); + if(lay->laying) + boxinit(b); +} + +static +void +linefix(Lay *lay) +{ + Line *l; + + for(l=lay->lines; l!=nil; l=l->next){ + l->r.min.x = lay->r.min.x; + l->r.max.x = lay->r.max.x; + } +} + +Lay * +layitems(Item *items, Rectangle r, int laying) +{ + Lay *lay; + Line *l; + Item *i; + + lay = emalloc(sizeof(Lay)); + lay->r.min = r.min; + lay->r.max = r.min; + lay->xwall = r.max.x; + lay->width = Dx(r); + lay->laying = laying; + l = emalloc(sizeof(Line)); + l->r.min = lay->r.min; + l->r.max = lay->r.min; + l->state = IFbrk; + l->boxes = nil; + lay->lines = l; + lay->lastline = l; + lay->font = font; + + for(i=items; i; i=i->next){ + sizeitem(lay, i); + layitem(lay, i); + } + newline(lay, IFbrk); + if(laying) + linefix(lay); + + return lay; +} + +void +laypage(Page *p) +{ + settables(p); + layfree(p->lay); + p->lay = layitems(p->items, Rect(0,0,Dx(p->r),Dy(p->r)), TRUE); + p->lay->r.max.y = max(p->lay->r.max.y, Dy(p->r)); +} + +static +void +drawline(Page *p, Image *im, Line *l) +{ + Box *b; + + for(b=l->boxes; b!=nil; b=b->next) + b->draw(b, p, im); +} + +void +laydraw(Page *p, Image *im, Lay *lay) +{ + Rectangle r; + Line *l; + + r = rectaddpt(p->lay->r, p->pos); + for(l=lay->lines; l!=nil; l=l->next){ + if(rectXrect(r, l->r)) + drawline(p, im, l); + } +} + +static +void +laytablefree(Table *t) +{ + Tablecell *c; + + for(c=t->cells; c!=nil; c=c->next){ + layfree(c->lay); + c->lay = nil; + } +} + +void +layfree(Lay *lay) +{ + Line *l, *nextline; + Box *b, *nextbox; + void **aux; + + if(lay == nil) + return; + + for(l=lay->lines; l!=nil; l=nextline){ + for(b=l->boxes; b!=nil; b=nextbox){ + nextbox = b->next; + if(b->i->tag==Iformfieldtag && istextfield(b->i)){ + aux = &((Iformfield *)b->i)->aux; + if(*aux){ + textclose(*aux); + free(*aux); + } + *aux = nil; + }else if(b->i->tag == Itabletag) + laytablefree(((Itable *)b->i)->table); + + free(b); + } + nextline = l->next; + free(l); + } + free(lay); +} + +void +laysnarf(Page *p, Lay *lay, Runestr *rs) +{ + Tablecell *c; + Itext *i; + Font *f; + Line *l; + Box *b; + int q0, q1, n; + + for(l=lay->lines; l!=nil; l=l->next) for(b=l->boxes; b!=nil; b=b->next){ + if(p->selecting && hasbrk(b->i->state)){ + rs->r = runerealloc(rs->r, rs->nr+2); + rs->r[rs->nr++] = L'\n'; + rs->r[rs->nr] = L'\0'; + } + if(b->i->tag==Itexttag){ + i = (Itext *)b->i; + f = getfont(i->fnt); + if(istextsel(p, b->r, &q0, &q1, i->s, f)){ + if(q1 == 0) + q1 = runestrlen(i->s); + n = q1-q0; + if(n == 0) + n = runestrlen(i->s); + rs->r = runerealloc(rs->r, rs->nr+n+2); + runemove(rs->r+rs->nr, i->s+q0, n); + rs->nr += n; + rs->r[rs->nr++] = L' '; + rs->r[rs->nr] = L'\0'; + } + }else if(b->i->tag == Itabletag) + for(c=((Itable *)b->i)->table->cells; c!=nil; c=c->next) + if(c->lay) + laysnarf(p, c->lay, rs); + } +} diff --git a/sys/src/cmd/abaco/main.c b/sys/src/cmd/abaco/main.c new file mode 100755 index 000000000..b190e9f02 --- /dev/null +++ b/sys/src/cmd/abaco/main.c @@ -0,0 +1,433 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <memdraw.h> +#include <thread.h> +#include <mouse.h> +#include <keyboard.h> +#include <cursor.h> +#include <frame.h> +#include <regexp.h> +#include <plumb.h> +#include <html.h> +#include "dat.h" +#include "fns.h" + +enum { + WPERCOL = 8, +}; +void mousethread(void *); +void keyboardthread(void *); +void iconinit(void); +void plumbproc(void*); + +Channel *cexit; +Channel *cplumb; +Mousectl *mousectl; + +char *fontnames[2] = { + "/lib/font/bit/lucidasans/unicode.8.font", + "/lib/font/bit/lucidasans/passwd.6.font", +}; + +int snarffd = -1; +int mainpid; +int plumbwebfd; +int plumbsendfd ; +char *webmountpt = "/mnt/web"; +char *charset = "iso-8859-1"; +int mainstacksize = STACK; + +void readpage(Column *, char *); +int shutdown(void *, char *); + +void +derror(Display *, char *s) +{ + error(s); +} + +static void +usage(void) +{ + fprint(2, "usage: %s [-c ncol] [-m mtpt] [-t charset] [url...]\n", + argv0); + exits("usage"); +} + +void +threadmain(int argc, char *argv[]) +{ + Column *c; + char buf[256]; + int i, ncol; + + rfork(RFENVG|RFNAMEG); + + ncol = 1; + ARGBEGIN{ + case 'c': + ncol = atoi(EARGF(usage())); + if(ncol <= 0) + usage(); + break; + case 'm': + webmountpt = EARGF(usage()); + break; + case 'p': + procstderr++; + break; + case 't': + charset = EARGF(usage()); + break; + default: + usage(); + break; + }ARGEND + + snprint(buf, sizeof(buf), "%s/ctl", webmountpt); + webctlfd = open(buf, ORDWR); + if(webctlfd < 0) + sysfatal("can't initialize webfs: %r"); + + snarffd = open("/dev/snarf", OREAD|OCEXEC); + + if(initdraw(derror, fontnames[0], "abaco") < 0) + sysfatal("can't open display: %r"); + memimageinit(); + iconinit(); + timerinit(); + initfontpaths(); + + cexit = chancreate(sizeof(int), 0); + crefresh = chancreate(sizeof(Page *), 0); + if(cexit==nil || crefresh==nil) + sysfatal("can't create initial channels: %r"); + + mousectl = initmouse(nil, screen); + if(mousectl == nil) + sysfatal("can't initialize mouse: %r"); + mouse = mousectl; + keyboardctl = initkeyboard(nil); + if(keyboardctl == nil) + sysfatal("can't initialize keyboard: %r"); + mainpid = getpid(); + plumbwebfd = plumbopen("web", OREAD|OCEXEC); + if(plumbwebfd >= 0){ + cplumb = chancreate(sizeof(Plumbmsg*), 0); + proccreate(plumbproc, nil, STACK); + } + plumbsendfd = plumbopen("send", OWRITE|OCEXEC); + + rowinit(&row, screen->clipr); + for(i=0; i<ncol; i++){ + c = rowadd(&row, nil, -1); + if(c==nil && i==0) + error("initializing columns"); + } + c = row.col[row.ncol-1]; + for(i=0; i<argc; i++) + if(i/WPERCOL >= row.ncol) + readpage(c, argv[i]); + else + readpage(row.col[i/WPERCOL], argv[i]); + flushimage(display, 1); + threadcreate(keyboardthread, nil, STACK); + threadcreate(mousethread, nil, STACK); + + threadnotify(shutdown, 1); + recvul(cexit); + threadexitsall(nil); +} + +void +readpage(Column *c, char *s) +{ + Window *w; + Runestr rs; + + w = coladd(c, nil, nil, -1); + bytetorunestr(s, &rs); + pageget(&w->page, &rs, nil, HGet, TRUE); + closerunestr(&rs); +} + +char *oknotes[] = { + "delete", + "hangup", + "kill", + "exit", + nil +}; + +int +shutdown(void*, char *msg) +{ + int i; + + for(i=0; oknotes[i]; i++) + if(strncmp(oknotes[i], msg, strlen(oknotes[i])) == 0) + threadexitsall(msg); + print("abaco: %s\n", msg); +// abort(); + return 0; +} + +void +plumbproc(void *) +{ + Plumbmsg *m; + + threadsetname("plumbproc"); + for(;;){ + m = plumbrecv(plumbwebfd); + if(m == nil) + threadexits(nil); + sendp(cplumb, m); + } +} + +enum { KTimer, KKey, NKALT, }; + +void +keyboardthread(void *) +{ + Timer *timer; + Text *t; + Rune r; + + static Alt alts[NKALT+1]; + + alts[KTimer].c = nil; + alts[KTimer].v = nil; + alts[KTimer].op = CHANNOP; + alts[KKey].c = keyboardctl->c; + alts[KKey].v = &r; + alts[KKey].op = CHANRCV; + alts[NKALT].op = CHANEND; + + timer = nil; + threadsetname("keyboardthread"); + for(;;){ + switch(alt(alts)){ + case KTimer: + timerstop(timer); + alts[KTimer].c = nil; + alts[KTimer].op = CHANNOP; + break; + case KKey: + casekeyboard: + typetext = rowwhich(&row, mouse->xy, r, TRUE); + t = typetext; + if(t!=nil && t->col!=nil && + !(r==Kdown || r==Kleft || r==Kright)) + /* scrolling doesn't change activecol */ + activecol = t->col; + if(timer != nil) + timercancel(timer); + if(t!=nil){ + texttype(t, r); + timer = timerstart(500); + alts[KTimer].c = timer->c; + alts[KTimer].op = CHANRCV; + }else{ + timer = nil; + alts[KTimer].c = nil; + alts[KTimer].op = CHANNOP; + } + if(nbrecv(keyboardctl->c, &r) > 0) + goto casekeyboard; + flushimage(display, 1); + break; + } + } +} + +void +mousethread(void *) +{ + Plumbmsg *pm; + Mouse m; + Text *t; + int but; + enum { MResize, MMouse, MPlumb, MRefresh, NMALT }; + static Alt alts[NMALT+1]; + + threadsetname("mousethread"); + alts[MResize].c = mousectl->resizec; + alts[MResize].v = nil; + alts[MResize].op = CHANRCV; + alts[MMouse].c = mousectl->c; + alts[MMouse].v = &mousectl->Mouse; + alts[MMouse].op = CHANRCV; + alts[MPlumb].c = cplumb; + alts[MPlumb].v = ± + alts[MPlumb].op = CHANRCV; + alts[MRefresh].c = crefresh; + alts[MRefresh].v = nil; + alts[MRefresh].op = CHANRCV; + if(cplumb == nil) + alts[MPlumb].op = CHANNOP; + alts[NMALT].op = CHANEND; + + for(;;){ + qlock(&row); + flushrefresh(); + qunlock(&row); + flushimage(display, 1); + switch(alt(alts)){ + case MResize: + if(getwindow(display, Refnone) < 0) + error("resized"); + scrlresize(); + tmpresize(); + rowresize(&row, screen->clipr); + break; + case MPlumb: + plumblook(pm); + plumbfree(pm); + break; + case MRefresh: + break; + case MMouse: + m = mousectl->Mouse; + if(m.buttons == 0) + continue; + + qlock(&row); + but = 0; + if(m.buttons == 1) + but = 1; + else if(m.buttons == 2) + but = 2; + else if(m.buttons == 4) + but = 3; + + if(m.buttons & (8|16)){ + if(m.buttons & 8) + but = Kscrolloneup; + else + but = Kscrollonedown; + rowwhich(&row, m.xy, but, TRUE); + }else if(but){ + t = rowwhich(&row, m.xy, but, FALSE); + if(t) + textmouse(t, m.xy, but); + } + qunlock(&row); + break; + } + } +} + +Cursor boxcursor = { + {-7, -7}, + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, + 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + {0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, + 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, + 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, + 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x00, 0x00} +}; + +void +iconinit(void) +{ + Rectangle r; + + /* Green */ + tagcols[BACK] = allocimagemix(display, DPalegreen, DWhite); + if(tagcols[BACK] == nil) + error("allocimagemix"); + tagcols[HIGH] = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkgreen); + tagcols[BORD] = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, DMedgreen); + tagcols[TEXT] = display->black; + tagcols[HTEXT] = display->black; + + /* Grey */ + textcols[BACK] = display->white; + textcols[HIGH] = eallocimage(display, Rect(0,0,1,1), CMAP8,1, 0xCCCCCCFF); + textcols[BORD] = display->black; + textcols[TEXT] = display->black; + textcols[HTEXT] = display->black; + + r = Rect(0, 0, Scrollsize+2, font->height+1); + button = eallocimage(display, r, screen->chan, 0, DNofill); + draw(button, r, tagcols[BACK], nil, r.min); + r.max.x -= 2; + border(button, r, 2, tagcols[BORD], ZP); + + r = button->r; + colbutton = eallocimage(display, r, screen->chan, 0, 0x00994CFF); + + but2col = eallocimage(display, Rect(0,0,1,2), screen->chan, 1, 0xAA0000FF); + but3col = eallocimage(display, Rect(0,0,1,2), screen->chan, 1, 0x444488FF); + + passfont = openfont(display, fontnames[1]); + if(passfont == nil) + error("openfont"); +} + +/* + * /dev/snarf updates when the file is closed, so we must open our own + * fd here rather than use snarffd + */ + +/* + * rio truncates large snarf buffers, so this avoids using the + * service if the string is huge + */ + +enum +{ + NSnarf = 1000, + MAXSNARF = 100*1024, +}; + +void +putsnarf(Runestr *rs) +{ + int fd, i, n; + + if(snarffd<0 || rs->nr==0) + return; + if(rs->nr > MAXSNARF) + return; + fd = open("/dev/snarf", OWRITE); + if(fd < 0) + return; + for(i=0; i<rs->nr; i+=n){ + n = rs->nr-i; + if(n > NSnarf) + n =NSnarf; + if(fprint(fd, "%.*S", n, rs->r) < 0) + break; + } + close(fd); +} + +void +getsnarf(Runestr *rs) +{ + int i, n, nb, nulls; + char *sn, buf[BUFSIZE]; + + if(snarffd < 0) + return; + sn = nil; + i = 0; + seek(snarffd, 0, 0); + while((n=read(snarffd, buf, sizeof(buf))) > 0){ + sn = erealloc(sn, i+n+1); + memmove(sn+i, buf, n); + i += n; + sn[i] = 0; + } + if(i > 0){ + rs->r = runemalloc(i+1); + cvttorunes(sn, i, rs->r, &nb, &rs->nr, &nulls); + free(sn); + } +} diff --git a/sys/src/cmd/abaco/mkfile b/sys/src/cmd/abaco/mkfile new file mode 100755 index 000000000..5348a41bb --- /dev/null +++ b/sys/src/cmd/abaco/mkfile @@ -0,0 +1,52 @@ +</$objtype/mkfile + +BIN=/$objtype/bin + +TARG=abaco + +OFILES=\ + cols.$O\ + exec.$O\ + html.$O\ + main.$O\ + page.$O\ + rows.$O\ + scrl.$O\ + tabs.$O\ + text.$O\ + time.$O\ + urls.$O\ + util.$O\ + wind.$O\ + +HFILES=\ + dat.h\ + fns.h\ + tcs.h\ + +UPDATE=\ + mkfile\ + $HFILES\ + ${OFILES:%.$O=%.c}\ + +</sys/src/cmd/mkone + +charsets.txt: + hget http://www.iana.org/assignments/character-sets | sed 's/
//' > charsets.txt + +tcs.h: charsets.awk charsets.txt tcs.txt + charsets.awk charsets.txt tcs.txt > tcs.h + +syms:V: + 8c -a $CFLAGS main.c > syms + 8c -aa ????.c >> syms + +tgz:V: + cd .. + tar c abaco | gzip -9 > $home/src/tar/abaco_^`{date -n}^.tgz + +dist: + 9fs sources + mk clean + cd .. + tar c $TARG | gzip -9 > /n/sources/contrib/fgb/abaco-test.tgz diff --git a/sys/src/cmd/abaco/page.c b/sys/src/cmd/abaco/page.c new file mode 100755 index 000000000..6f75f6afb --- /dev/null +++ b/sys/src/cmd/abaco/page.c @@ -0,0 +1,839 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <memdraw.h> +#include <thread.h> +#include <cursor.h> +#include <mouse.h> +#include <keyboard.h> +#include <frame.h> +#include <plumb.h> +#include <html.h> +#include "dat.h" +#include "fns.h" + +static void pageload1(Page *, Url *, int); + +static +void +addchild(Page *p, Page *c) +{ + Page *t; + + c->parent = p; + c->w = p->w; + c->b = p->b; + c->col = p->col; + c->row = p->row; + if(p->child == nil) + p->child = c; + else{ + for(t=p->child; t->next!=nil; t=t->next) + ; + t->next = c; + } +} + +static +void +loadchilds(Page *p, Kidinfo *k) +{ + Runestr rs; + Kidinfo *t; + Page *c; + + addrefresh(p, "loading frames..."); + p->kidinfo = k; + for(t=k->kidinfos; t!=nil; t=t->next){ + c = emalloc(sizeof(Page)); + addchild(p, c); + if(t->isframeset){ + c->url = urldup(p->url); + loadchilds(c, t); + }else{ + c->kidinfo = t; + /* this check shouldn't be necessary, but... */ + if(t->src){ + rs.r = urlcombine(p->url->act.r, t->src); + rs.nr = runestrlen(rs.r); + pageload1(c, urlalloc(&rs, nil, HGet), FALSE); + closerunestr(&rs); + } + } + } +} + +static struct { + char *mime; + char *filter; +}filtertab[] = { + "image/gif", "gif -t9", + "image/jpeg", "jpg -t9", + "image/jpg", "jpg -t9", + "image/pjpeg", "jpg -t9", + "image/png", "png -t9", + "image/ppm", "ppm -t9", + nil, nil, +}; + +char * +getfilter(Rune *r, int x, int y) +{ + char buf[128]; + int i; + + snprint(buf, sizeof(buf), "%S", r); + for(i=0; filtertab[i].mime!=nil; i++) + if(cistrncmp(buf, filtertab[i].mime, strlen(filtertab[i].mime)) == 0) + break; + + if(filtertab[i].filter == nil) + return nil; + + if(x==0 && y==0) + return smprint("%s", filtertab[i].filter); + if(x!=0 && y!=0) + return smprint("%s | resample -x %d -y %d", filtertab[i].filter, x, y); + if(x != 0) + return smprint("%s | resample -x %d", filtertab[i].filter, x); + /* y != 0 */ + return smprint("%s | resample -y %d", filtertab[i].filter, y); +} + +static Cimage *cimages = nil; +static QLock cimagelock; + +static +void +freecimage(Cimage *ci) +{ + Cimage *ci1; + + qlock(&cimagelock); + if(decref(ci) == 0){ + if(ci->i) + freeimage(ci->i); + else if(ci->mi) + freememimage(ci->mi); + urlfree(ci->url); + ci1 = cimages; + if(ci1 == ci) + cimages = ci->next; + else{ + while(ci1){ + if(ci1->next == ci){ + ci1->next = ci->next; + break; + } + ci1 = ci1->next; + } + } + free(ci); + } + qunlock(&cimagelock); +} + +static +void +closeimages(Page *p) +{ + int i; + + for(i=0; i<p->ncimage; i++) + freecimage(p->cimage[i]); + free(p->cimage); + p->cimage =nil; + p->ncimage = 0; +} + +static +Cimage * +loadimg(Rune *src, int x , int y) +{ + Channel *sync; + Cimage *ci; + Runestr rs; + Exec *e; + char *filter; + int fd, p[2], q[2]; + + ci = emalloc(sizeof(Cimage)); + rs. r = src; + rs.nr = runestrlen(rs.r); + ci->url = urlalloc(&rs, nil, HGet); + fd = urlopen(ci->url); + if(fd < 0){ + Err1: + return ci; + } + filter = getfilter(ci->url->ctype.r, x, y); + if(filter == nil){ + werrstr("%S unsupported: %S", ci->url->ctype.r, ci->url->act.r); + Err2: + close(fd); + goto Err1; + } + + if(pipe(p)<0 || pipe(q)<0) + error("can't create pipe"); + close(p[0]); + p[0] = fd; + sync = chancreate(sizeof(ulong), 0); + if(sync == nil) + error("can't create channel"); + e = emalloc(sizeof(Exec)); + e->p[0] = p[0]; + e->p[1] = p[1]; + e->q[0] = q[0]; + e->q[1] = q[1]; + e->cmd = filter; + e->sync = sync; + proccreate(execproc, e, STACK); + recvul(sync); + chanfree(sync); + close(p[0]); + close(p[1]); + close(q[1]); + + ci->mi = readmemimage(q[0]); + close(q[0]); + if(ci->mi == nil){ + werrstr("can't read image"); + goto Err2; + } + free(filter); + return ci; +} + +static +Cimage * +findimg(Rune *s) +{ + Cimage *ci; + + qlock(&cimagelock); + for(ci=cimages; ci!=nil; ci=ci->next) + if(runestrcmp(ci->url->src.r, s) == 0) + break; + + qunlock(&cimagelock); + return ci; +} + +void +loadimages(Page *p) +{ + Cimage *ci; + Iimage *i; + Rune *src; + + addrefresh(p, "loading images..."); + reverseimages(&p->doc->images); + for(i=p->doc->images; i!=nil; i=i->nextimage){ + if(p->aborting) + break; + src = urlcombine(getbase(p), i->imsrc); + ci = findimg(src); + if(ci == nil){ + ci = loadimg(src, i->imwidth, i->imheight); + qlock(&cimagelock); + ci->next = cimages; + cimages = ci; + qunlock(&cimagelock); + } + free(src); + incref(ci); + i->aux = ci; + p->cimage = erealloc(p->cimage, ++p->ncimage*sizeof(Cimage *)); + p->cimage[p->ncimage-1] = ci; + p->changed = TRUE; + addrefresh(p, ""); + } +} + +static char *mimetab[] = { + "text/html", + "application/xhtml", + nil, +}; + +static +void +pageloadproc(void *v) +{ + Page *p; + char buf[BUFSIZE], *s; + long n, l; + int fd, i, ctype; + + threadsetname("pageloadproc"); + rfork(RFFDG); + + p = v; + addrefresh(p, "opening: %S...", p->url->src.r); + fd = urlopen(p->url); + if(fd < 0){ + addrefresh(p, "%S: %r", p->url->src.r); + Err: + p->loading = FALSE; + return; + } + if(runestrlen(p->url->ctype.r) == 0) /* assume .html when headers don't say anyting */ + goto Html; + + snprint(buf, sizeof(buf), "%S", p->url->ctype.r); + for(i=0; mimetab[i]!=nil; i++) + if(cistrncmp(buf, mimetab[i], strlen(mimetab[i])) == 0) + break; + + if(mimetab[i]){ + Html: + ctype = TextHtml; + }else if(cistrncmp(buf, "text/", 5) == 0) + ctype = TextPlain; + else{ + close(fd); + addrefresh(p, "%S: unsupported mime type: '%S'", p->url->act.r, p->url->ctype.r); + goto Err; + } + addrefresh(p, "loading: %S...", p->url->src.r); + s = nil; + l = 0; + while((n=read(fd, buf, sizeof(buf))) > 0){ + if(p->aborting){ + if(s){ + free(s); + s = nil; + } + break; + } + s = erealloc(s, l+n+1); + memmove(s+l, buf, n); + l += n; + s[l] = '\0'; + } + close(fd); + n = l; + if(s){ + s = convert(p->url->ctype, s, &n); + p->items = parsehtml((uchar *)s, n, p->url->act.r, ctype, UTF_8, &p->doc); + free(s); + fixtext(p); + if(ctype==TextHtml && p->aborting==FALSE){ + p->changed = TRUE; + addrefresh(p, ""); + if(p->doc->doctitle){ + p->title.r = erunestrdup(p->doc->doctitle); + p->title.nr = runestrlen(p->title.r); + } + p->loading = XXX; + if(p->doc->kidinfo) + loadchilds(p, p->doc->kidinfo); + else if(p->doc->images) + loadimages(p); + } + } + p->changed = TRUE; + p->loading = FALSE; + addrefresh(p, ""); +} + +static +void +pageload1(Page *p, Url *u, int dohist) +{ + pageclose(p); + p->loading = TRUE; + p->url = u; + if(dohist) + winaddhist(p->w, p->url); + proccreate(pageloadproc, p, STACK); +} + +void +pageload(Page *p, Url *u, int dohist) +{ + if(p->parent == nil) + textset(&p->w->url, u->src.r, u->src.nr); + draw(p->b, p->all, display->white, nil, ZP); + pageload1(p, u, dohist); +} + +void +pageget(Page *p, Runestr *src, Runestr *post, int m, int dohist) +{ + pageload(p, urlalloc(src, post, m), dohist); +} + +void +pageclose(Page *p) +{ + Page *c, *nc; + + if(p == selpage) + selpage = nil; + pageabort(p); + closeimages(p); + urlfree(p->url); + p->url = nil; + if(p->doc){ + freedocinfo(p->doc); + p->doc = nil; + } + layfree(p->lay); + p->lay = nil; + freeitems(p->items); + p->items = nil; + for(c=p->child; c!=nil; c=nc){ + nc = c->next; + pageclose(c); + free(c); + } + p->child = nil; + closerunestr(&p->title); + closerunestr(&p->refresh.rs); + p->refresh.t = 0; + p->pos = ZP; + p->top = ZP; + p->bot = ZP; + p->loading = p->aborting = FALSE; +} + +int +pageabort(Page *p) +{ + Page *c; + + for(c=p->child; c!=nil; c=c->next) + pageabort(c); + + p->aborting = TRUE; + while(p->loading) + sleep(100); + + p->aborting = FALSE; + return TRUE; +} + + +static Image *tmp; + +void +tmpresize(void) +{ + if(tmp) + freeimage(tmp); + + tmp = eallocimage(display, Rect(0,0,Dx(screen->r),Dy(screen->r)), screen->chan, 0, -1); +} + +static +void +renderchilds(Page *p) +{ + Rectangle r; + Kidinfo *k; + Page *c; + int i, j, x, y, *w, *h; + + draw(p->b, p->all, display->white, nil, ZP); + r = p->all; + y = r.min.y; + c = p->child; + k = p->kidinfo; + frdims(k->rows, k->nrows, Dy(r), &h); + frdims(k->cols, k->ncols, Dx(r), &w); + for(i=0; i<k->nrows; i++){ + x = r.min.x; + for(j=0; j<k->ncols; j++){ + if(c->aborting) + return; + c->b = p->b; + c->all = Rect(x,y,x+w[j],y+h[i]); + c->w = p->w; + pagerender(c); + c = c->next; + x += w[j]; + } + y += h[i]; + } + free(w); + free(h); +} + +static +void +pagerender1(Page *p) +{ + Rectangle r; + + r = p->all; + p->hscrollr = r; + p->hscrollr.min.y = r.max.y-Scrollsize; + p->vscrollr = r; + p->vscrollr.max.x = r.min.x+Scrollsize; + r.max.y -= Scrollsize; + r.min.x += Scrollsize; + p->r = r; + p->vscrollr.max.y = r.max.y; + p->hscrollr.min.x = r.min.x; + laypage(p); + pageredraw(p); +} + +void +pagerender(Page *p) +{ + if(p->child && p->loading==FALSE) + renderchilds(p); + else if(p->doc) + pagerender1(p); +} + +void +pageredraw(Page *p) +{ + Rectangle r; + + r = p->lay->r; + if(Dx(r)==0 || Dy(r)==0){ + draw(p->b, p->r, display->white, nil, ZP); + return; + } + if(tmp == nil) + tmpresize(); + + p->selecting = FALSE; + draw(tmp, tmp->r, getbg(p), nil, ZP); + laydraw(p, tmp, p->lay); + draw(p->b, p->r, tmp, nil, tmp->r.min); + r = p->vscrollr; + r.min.y = r.max.y; + r.max.y += Scrollsize; + draw(p->b, r, tagcols[HIGH], nil, ZP); + draw(p->b, insetrect(r, 1), tagcols[BACK], nil, ZP); + pagescrldraw(p); +} + +static +void +pageselect1(Page *p) /* when called, button 1 is down */ +{ + Point mp, npos, opos; + int b, scrled, x, y; + + b = mouse->buttons; + mp = mousectl->xy; + opos = getpt(p, mp); + do{ + x = y = 0; + if(mp.x < p->r.min.x) + x -= p->r.min.x-mp.x; + else if(mp.x > p->r.max.x) + x += mp.x-p->r.max.x; + if(mp.y < p->r.min.y) + y -= (p->r.min.y-mp.y)*Panspeed; + else if(mp.y > p->r.max.y) + y += (mp.y-p->r.max.y)*Panspeed; + + scrled = pagescrollxy(p, x, y); + npos = getpt(p, mp); + if(opos.y < npos.y){ + p->top = opos; + p->bot = npos; + }else{ + p->top = npos; + p->bot = opos; + } + pageredraw(p); + if(scrled == TRUE) + scrsleep(100); + else + readmouse(mousectl); + + mp = mousectl->xy; + }while(mousectl->buttons == b); +} + +static Rune left1[] = { L'{', L'[', L'(', L'<', L'«', 0 }; +static Rune right1[] = { L'}', L']', L')', L'>', L'»', 0 }; +static Rune left2[] = { L'\'', L'"', L'`', 0 }; + +static +Rune *left[] = { + left1, + left2, + nil +}; +static +Rune *right[] = { + right1, + left2, + nil +}; + +void +pagedoubleclick(Page *p) +{ + Point xy; + Line *l; + Box *b; + + xy = getpt(p, mouse->xy); + l = linewhich(p->lay, xy); + if(l==nil || l->hastext==FALSE) + return; + + if(xy.x<l->boxes->r.min.x && hasbrk(l->state)){ /* beginning of line? */ + p->top = l->boxes->r.min; + if(l->next && !hasbrk(l->next->state)){ + for(l=l->next; l->next!=nil; l=l->next) + if(hasbrk(l->next->state)) + break; + } + p->bot = l->lastbox->r.max;; + }else if(xy.x>l->lastbox->r.max.x && hasbrk(l->next->state)){ /* end of line? */ + p->bot = l->lastbox->r.max; + if(!hasbrk(l->state) && l->prev!=nil){ + for(l=l->prev; l->prev!=nil; l=l->prev) + if(hasbrk(l->state)) + break; + } + p->top = l->boxes->r.min; + }else{ + b = pttobox(l, xy); + if(b!=nil && b->i->tag==Itexttag){ + p->top = b->r.min; + p->bot = b->r.max; + } + } + p->top.y += 2; + p->bot.y -= 2; + pageredraw(p); +} + +static uint clickmsec; + +void +pageselect(Page *p) +{ + int b, x, y; + + + selpage = p; + /* + * To have double-clicking and chording, we double-click + * immediately if it might make sense. + */ + b = mouse->buttons; + if(mouse->msec-clickmsec<500){ + pagedoubleclick(p); + x = mouse->xy.x; + y = mouse->xy.y; + /* stay here until something interesting happens */ + do + readmouse(mousectl); + while(mouse->buttons==b && abs(mouse->xy.x-x)<3 && abs(mouse->xy.y-y)<3); + mouse->xy.x = x; /* in case we're calling pageselect1 */ + mouse->xy.y = y; + } + if(mousectl->buttons == b) + pageselect1(p); + + if(eqpt(p->top, p->bot)){ + if(mouse->msec-clickmsec<500) + pagedoubleclick(p); + else + clickmsec = mouse->msec; + } + while(mouse->buttons){ + mouse->msec = 0; + b = mouse->buttons; + if(b & 2) /* snarf only */ + cut(nil, nil, TRUE, FALSE, nil, 0); + while(mouse->buttons == b) + readmouse(mousectl); + } +} + +Page * +pagewhich(Page *p, Point xy) +{ + Page *c; + + if(p->child == nil) + return p; + + for(c=p->child; c!=nil; c=c->next) + if(ptinrect(xy, c->all)) + return pagewhich(c, xy); + + return nil; +} + +void +pagemouse(Page *p, Point xy, int but) +{ + Box *b; + + p = pagewhich(p, xy); + if(p == nil) + return; + + if(pagerefresh(p)) + return; + + if(p->lay == nil) + return; + + if(ptinrect(xy, p->vscrollr)){ + pagescroll(p, but, FALSE); + return; + } + if(ptinrect(xy, p->hscrollr)){ + pagescroll(p, but, TRUE); + return; + } + xy = getpt(p, xy); + b = boxwhich(p->lay, xy); + if(b && b->mouse) + b->mouse(b, p, but); + else if(but == 1) + pageselect(p); +} + +void +pagetype(Page *p, Rune r, Point xy) +{ + Box *b; + int x, y; + + p = pagewhich(p, xy); + if(p == nil) + return; + + if(pagerefresh(p)) + return; + + if(p->lay == nil) + return; + + /* text field? */ + xy = getpt(p, xy); + b = boxwhich(p->lay, xy); + if(b && b->key){ + b->key(b, p, r); + return; + } + /* ^H: same as 'Back' */ + if(r == 0x08){ + wingohist(p->w, FALSE); + return; + } + + x = 0; + y = 0; + switch(r){ + case Kleft: + x -= Dx(p->r)/2; + break; + case Kright: + x += Dx(p->r)/2; + break; + case Kdown: + case Kscrollonedown: + y += Dy(p->r)/2; + break; + case Kpgdown: + y += Dy(p->r); + break; + case Kup: + case Kscrolloneup: + y -= Dy(p->r)/2; + break; + case Kpgup: + y -= Dy(p->r); + break; + case Khome: + y -= Dy(p->lay->r); /* force p->pos.y = 0 */ + break; + case Kend: + y = Dy(p->lay->r) - Dy(p->r); + break; + default: + return; + } + if(pagescrollxy(p, x, y)) + pageredraw(p); +} + +void +pagesnarf(Page *p) +{ + Runestr rs; + + memset(&rs, 0, sizeof(Runestr)); + laysnarf(p, p->lay, &rs); + putsnarf(&rs); + closerunestr(&rs); +} + +void +pagesetrefresh(Page *p) +{ + Runestr rs; + Rune *s, *q, *t; + char *v; + int n; + + if(!p->doc || !p->doc->refresh) + return; + + s = p->doc->refresh; + q = runestrchr(s, L'='); + if(q == nil) + return; + q++; + if(!q) + return; + n = runestrlen(q); + if(*q == L'''){ + q++; + n -= 2; + } + if(n <= 0) + return; + t = runesmprint("%.*S", n, q); + rs.r = urlcombine(getbase(p), t); + rs.nr = runestrlen(rs.r); + copyrunestr(&p->refresh.rs, &rs); + closerunestr(&rs); + free(t); + + /* now the time */ + q = runestrchr(s, L';'); + if(q){ + v = smprint("%.*S", (int)(q-s), s); + p->refresh.t = atoi(v); + free(v); + }else + p->refresh.t = 1; + + p->refresh.t += time(0); +} + +int +pagerefresh(Page *p) +{ + int t; + + if(!p->refresh.t) + return 0; + + t = p->refresh.t - time(0); + if(t > 0) + return 0; + + pageget(p, &p->refresh.rs, nil, HGet, FALSE); + return 1; +} diff --git a/sys/src/cmd/abaco/plumbing b/sys/src/cmd/abaco/plumbing new file mode 100755 index 000000000..140bcbd49 --- /dev/null +++ b/sys/src/cmd/abaco/plumbing @@ -0,0 +1,10 @@ +# to update: cp /usr/$user/lib/plumbing /mnt/plumb/rules + +editor = acme + +include basic + +type is text +data matches 'https?://[a-zA-Z0-9_@\-]+([.:][a-zA-Z0-9_@\-]+)*/?[a-zA-Z0-9_?,%#~&/\-+=]+([:.][a-zA-Z0-9_?,''%#~&/\-+=;]+)*' +plumb to web +plumb client window -dx 900 -dy 800 abaco diff --git a/sys/src/cmd/abaco/rows.c b/sys/src/cmd/abaco/rows.c new file mode 100755 index 000000000..9f27d9c7d --- /dev/null +++ b/sys/src/cmd/abaco/rows.c @@ -0,0 +1,252 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <memdraw.h> +#include <thread.h> +#include <cursor.h> +#include <mouse.h> +#include <keyboard.h> +#include <frame.h> +#include <plumb.h> +#include <html.h> +#include "dat.h" +#include "fns.h" + +void +rowinit(Row *row, Rectangle r) +{ + Rectangle r1; + Text *t; + + draw(screen, r, display->white, nil, ZP); + row->r = r; + row->col = nil; + row->ncol = 0; + r1 = r; + r1.max.y = r1.min.y + font->height; + t = &row->tag; + textinit(t, screen, r1, font, tagcols); + t->what = Rowtag; + t->row = row; + t->w = nil; + t->col = nil; + r1.min.y = r1.max.y; + r1.max.y += Border; + draw(screen, r1, display->black, nil, ZP); + textinsert(t, 0, L"Newcol Google Exit ", 19); + textsetselect(t, t->rs.nr, t->rs.nr); +} + +Column* +rowadd(Row *row, Column *c, int x) +{ + Rectangle r, r1; + Column *d; + int i; + + d = nil; + r = row->r; + r.min.y = row->tag.r.max.y+Border; + if(x<r.min.x && row->ncol>0){ /*steal 40% of last column by default */ + d = row->col[row->ncol-1]; + x = d->r.min.x + 3*Dx(d->r)/5; + } + /* look for column we'll land on */ + for(i=0; i<row->ncol; i++){ + d = row->col[i]; + if(x < d->r.max.x) + break; + } + if(row->ncol > 0){ + if(i < row->ncol) + i++; /* new column will go after d */ + r = d->r; + if(Dx(r) < 100) + return nil; + draw(screen, r, display->white, nil, ZP); + r1 = r; + r1.max.x = min(x, r.max.x-50); + if(Dx(r1) < 50) + r1.max.x = r1.min.x+50; + colresize(d, r1); + r1.min.x = r1.max.x; + r1.max.x = r1.min.x+Border; + draw(screen, r1, display->black, nil, ZP); + r.min.x = r1.max.x; + } + if(c == nil){ + c = emalloc(sizeof(Column)); + colinit(c, r); + }else + colresize(c, r); + c->row = row; + c->tag.row = row; + row->col = realloc(row->col, (row->ncol+1)*sizeof(Column*)); + memmove(row->col+i+1, row->col+i, (row->ncol-i)*sizeof(Column*)); + row->col[i] = c; + row->ncol++; + clearmouse(); + return c; +} + +void +rowresize(Row *row, Rectangle r) +{ + int i, dx, odx; + Rectangle r1, r2; + Column *c; + + dx = Dx(r); + odx = Dx(row->r); + row->r = r; + r1 = r; + r1.max.y = r1.min.y + font->height; + textresize(&row->tag, screen, r1); + r1.min.y = r1.max.y; + r1.max.y += Border; + draw(screen, r1, display->black, nil, ZP); + r.min.y = r1.max.y; + r1 = r; + r1.max.x = r1.min.x; + for(i=0; i<row->ncol; i++){ + c = row->col[i]; + r1.min.x = r1.max.x; + if(i == row->ncol-1) + r1.max.x = r.max.x; + else + r1.max.x = r1.min.x+Dx(c->r)*dx/odx; + if(i > 0){ + r2 = r1; + r2.max.x = r2.min.x+Border; + draw(screen, r2, display->black, nil, ZP); + r1.min.x = r2.max.x; + } + colresize(c, r1); + } +} + +void +rowdragcol(Row *row, Column *c, int) +{ + Rectangle r; + int i, b, x; + Point p, op; + Column *d; + + clearmouse(); + setcursor(mousectl, &boxcursor); + b = mouse->buttons; + op = mouse->xy; + while(mouse->buttons == b) + readmouse(mousectl); + setcursor(mousectl, nil); + if(mouse->buttons){ + while(mouse->buttons) + readmouse(mousectl); + return; + } + + for(i=0; i<row->ncol; i++) + if(row->col[i] == c) + goto Found; + error("can't find column"); + + Found: + if(i == 0) + return; + p = mouse->xy; + if((abs(p.x-op.x)<5 && abs(p.y-op.y)<5)) + return; + if((i>0 && p.x<row->col[i-1]->r.min.x) || (i<row->ncol-1 && p.x>c->r.max.x)){ + /* shuffle */ + x = c->r.min.x; + rowclose(row, c, FALSE); + if(rowadd(row, c, p.x) == nil) /* whoops! */ + if(rowadd(row, c, x) == nil) /* WHOOPS! */ + if(rowadd(row, c, -1)==nil){ /* shit! */ + rowclose(row, c, TRUE); + return; + } + colmousebut(c); + return; + } + d = row->col[i-1]; + if(p.x < d->r.min.x+80+Scrollsize) + p.x = d->r.min.x+80+Scrollsize; + if(p.x > c->r.max.x-80-Scrollsize) + p.x = c->r.max.x-80-Scrollsize; + r = d->r; + r.max.x = c->r.max.x; + draw(screen, r, display->white, nil, ZP); + r.max.x = p.x; + colresize(d, r); + r = c->r; + r.min.x = p.x; + r.max.x = r.min.x; + r.max.x += Border; + draw(screen, r, display->black, nil, ZP); + r.min.x = r.max.x; + r.max.x = c->r.max.x; + colresize(c, r); + colmousebut(c); +} + +void +rowclose(Row *row, Column *c, int dofree) +{ + Rectangle r; + int i; + + for(i=0; i<row->ncol; i++) + if(row->col[i] == c) + goto Found; + error("can't find column"); + Found: + r = c->r; + if(dofree) + colcloseall(c); + memmove(row->col+i, row->col+i+1, (row->ncol-i)*sizeof(Column*)); + row->ncol--; + row->col = realloc(row->col, row->ncol*sizeof(Column*)); + if(row->ncol == 0){ + draw(screen, r, display->white, nil, ZP); + return; + } + if(i == row->ncol){ /* extend last column right */ + c = row->col[i-1]; + r.min.x = c->r.min.x; + r.max.x = row->r.max.x; + }else{ /* extend next window left */ + c = row->col[i]; + r.max.x = c->r.max.x; + } + draw(screen, r, display->white, nil, ZP); + colresize(c, r); +} + +Column* +rowwhichcol(Row *row, Point p) +{ + int i; + Column *c; + + for(i=0; i<row->ncol; i++){ + c = row->col[i]; + if(ptinrect(p, c->r)) + return c; + } + return nil; +} + +Text* +rowwhich(Row *row, Point p, Rune r, int key) +{ + Column *c; + + if(ptinrect(p, row->tag.all)) + return &row->tag; + c = rowwhichcol(row, p); + if(c) + return colwhich(c, p, r, key); + return nil; +} diff --git a/sys/src/cmd/abaco/scrl.c b/sys/src/cmd/abaco/scrl.c new file mode 100755 index 000000000..3b7072f97 --- /dev/null +++ b/sys/src/cmd/abaco/scrl.c @@ -0,0 +1,317 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <memdraw.h> +#include <thread.h> +#include <cursor.h> +#include <mouse.h> +#include <keyboard.h> +#include <frame.h> +#include <plumb.h> +#include <html.h> +#include "dat.h" +#include "fns.h" + +static Image *vscrtmp; +static Image *hscrtmp; + +void +scrlresize(void) +{ + freeimage(vscrtmp); + freeimage(hscrtmp); + vscrtmp = eallocimage(display, Rect(0, 0, 32, screen->r.max.y), screen->chan, 0, DNofill); + hscrtmp = eallocimage(display, Rect(0, 0, screen->r.max.x, 32), screen->chan, 0, DNofill); +} + +static +Rectangle +scrpos(Rectangle r, uint p0, uint p1, uint tot) +{ + Rectangle q; + int h; + + q = r; + h = q.max.y-q.min.y; + if(tot == 0) + return q; + if(tot > 1024*1024){ + tot>>=10; + p0>>=10; + p1>>=10; + } + if(p0 > 0) + q.min.y += h*p0/tot; + if(p1 < tot) + q.max.y -= h*(tot-p1)/tot; + if(q.max.y < q.min.y+2){ + if(q.min.y+2 <= r.max.y) + q.max.y = q.min.y+2; + else + q.min.y = q.max.y-2; + } + return q; +} + +void +textscrdraw(Text *t) +{ + Rectangle r, r1, r2; + Image *b; + + if(vscrtmp == nil) + scrlresize(); + r = t->scrollr; + b = vscrtmp; + r1 = r; + r1.min.x = 0; + r1.max.x = Dx(r); + r2 = scrpos(r1, t->org, t->org+t->nchars, t->rs.nr); + if(!eqrect(r2, t->lastsr)){ + t->lastsr = r2; + draw(b, r1, t->cols[BORD], nil, ZP); + draw(b, r2, t->cols[BACK], nil, ZP); + r2.min.x = r2.max.x-1; + draw(b, r2, t->cols[BORD], nil, ZP); + draw(t->b, r, b, nil, Pt(0, r1.min.y)); +/*flushimage(display, 1);/*BUG?*/ + } +} + +void +scrsleep(uint dt) +{ + Timer *timer; + static Alt alts[3]; + + timer = timerstart(dt); + alts[0].c = timer->c; + alts[0].v = nil; + alts[0].op = CHANRCV; + alts[1].c = mousectl->c; + alts[1].v = &mousectl->Mouse; + alts[1].op = CHANRCV; + alts[2].op = CHANEND; + for(;;) + switch(alt(alts)){ + case 0: + timerstop(timer); + return; + case 1: + timercancel(timer); + return; + } +} + +void +textscroll(Text *t, int but) +{ + uint p0, oldp0; + Rectangle s; + int x, y, my, h, first; + + s = insetrect(t->scrollr, 1); + h = s.max.y-s.min.y; + x = (s.min.x+s.max.x)/2; + oldp0 = ~0; + first = TRUE; + do{ + flushimage(display, 1); + my = mouse->xy.y; + if(my < s.min.y) + my = s.min.y; + if(my >= s.max.y) + my = s.max.y; + if(!eqpt(mouse->xy, Pt(x, my))){ + moveto(mousectl, Pt(x, my)); + readmouse(mousectl); /* absorb event generated by moveto() */ + } + if(but == 2){ + y = my; + p0 = (vlong)t->rs.nr*(y-s.min.y)/h; + if(p0 >= t->q1) + p0 = textbacknl(t, p0, 2); + if(oldp0 != p0) + textsetorigin(t, p0, FALSE); + oldp0 = p0; + readmouse(mousectl); + continue; + } + if(but == 1) + p0 = textbacknl(t, t->org, (my-s.min.y)/t->font->height); + else + p0 = t->org+frcharofpt(t, Pt(s.max.x, my)); + if(oldp0 != p0) + textsetorigin(t, p0, TRUE); + oldp0 = p0; + /* debounce */ + if(first){ + flushimage(display, 1); + sleep(200); + nbrecv(mousectl->c, &mousectl->Mouse); + first = FALSE; + } + scrsleep(80); + }while(mouse->buttons & (1<<(but-1))); + while(mouse->buttons) + readmouse(mousectl); +} + +enum +{ + Scrbord = 1, +}; + +void +pagescrldraw(Page *p) +{ + Rectangle r1; + int t, d, l, h; + + if(vscrtmp == nil) + scrlresize(); + + r1 = Rect(0,0,Dx(p->hscrollr), Dy(p->hscrollr)); + d = Dx(r1); + t = Dx(p->lay->r); + l = muldiv(p->pos.x, d, t); + h = muldiv(p->pos.x+d, d, t); + draw(hscrtmp, r1, tagcols[HIGH], nil, ZP); + r1.max.x = r1.min.x+h; + r1.min.x += l; + r1.min.y += Scrbord; + r1.max.y -= Scrbord; + draw(hscrtmp, r1, tagcols[BACK], nil, ZP); + + r1 = Rect(0,0,Dx(p->vscrollr), Dy(p->vscrollr)); + d = Dy(r1); + t = Dy(p->lay->r); + l = muldiv(p->pos.y, d, t); + h = muldiv(p->pos.y+d, d, t); + draw(vscrtmp, r1, tagcols[HIGH], nil, ZP); + r1.max.y = r1.min.y+h; + r1.min.y += l; + r1.max.x -= Scrbord; + r1.min.x += Scrbord; + draw(vscrtmp, r1, tagcols[BACK], nil, ZP); + + draw(screen, p->vscrollr, vscrtmp, nil, vscrtmp->r.min); + draw(screen, p->hscrollr, hscrtmp, nil, hscrtmp->r.min); +} + +void +pagescroll(Page *p, int but, int horizontal) +{ + uint oldp0, p0; + Rectangle s; + Point mxy; + int i, m, om, first, d, size; + int smin, smax, ss, *pos; + + if(horizontal){ + s = insetrect(p->hscrollr, 1); + ss = s.max.x - s.min.x; + i = (s.min.y+s.max.y)/2; + d = Dx(p->r); + size = Dx(p->lay->r); + p0 = p->pos.x; + pos = &p->pos.x; + smin = s.min.x; + smax = s.max.x; + om = mouse->xy.x; + }else{ + s = insetrect(p->vscrollr, 1); + ss = s.max.y-s.min.y; + i = (s.min.x+s.max.x)/2; + d = Dy(p->r); + size = Dy(p->lay->r); + p0 = p->pos.y; + pos = &p->pos.y; + smin = s.min.y; + smax = s.max.y; + om = mouse->xy.y; + } + oldp0 = ~0; + first = TRUE; + do{ + flushimage(display, 1); + if(horizontal) + m = mouse->xy.x; + else + m = mouse->xy.y; + + if(m > om) + m += (m-om)*Panspeed; + else if(m < om) + m -= (om-m)*Panspeed; + + if(m < smin) + m = smin; + if(m > smax) + m = smax; + + om = m; + if(horizontal) + mxy = Pt(m, i); + else + mxy = Pt(i, m); + if(!eqpt(mouse->xy, mxy)){ + moveto(mousectl, mxy); + readmouse(mousectl); /* absorb event generated by moveto() */ + } + if(but == 2){ + p0 = muldiv(m-smin, size, ss); + p0 = max(p0, 0); + p0 = min(p0,size-d); + if(oldp0 != p0){ + *pos = p0; + pageredraw(p); + } + oldp0 = p0; + readmouse(mousectl); + continue; + } + if(but == 1) + p0 -= (d/2); + else + p0 += d/2; + p0 = min(p0, size-d); + p0 = max(p0, 0); + if(oldp0 != p0){ + *pos = p0; + pageredraw(p); + } + oldp0 = p0; + /* debounce */ + if(first){ + flushimage(display, 1); + sleep(200); + nbrecv(mousectl->c, &mousectl->Mouse); + first = FALSE; + } + scrsleep(80); + }while(mouse->buttons & (1<<(but-1))); + while(mouse->buttons) + readmouse(mousectl); +} + +int +pagescrollxy(Page *p, int x, int y) +{ + int scrled; + + scrled = FALSE; + if(x != 0){ + p->pos.x += x; + p->pos.x = max(p->pos.x, 0); + p->pos.x = min(p->pos.x, Dx(p->lay->r)-Dx(p->r)); + scrled =TRUE; + } + if(y != 0){ + p->pos.y += y; + p->pos.y = max(p->pos.y, 0); + p->pos.y = min(p->pos.y, Dy(p->lay->r)-Dy(p->r)); + scrled =TRUE; + } + return scrled; +} diff --git a/sys/src/cmd/abaco/tabs.c b/sys/src/cmd/abaco/tabs.c new file mode 100755 index 000000000..eda3f5132 --- /dev/null +++ b/sys/src/cmd/abaco/tabs.c @@ -0,0 +1,332 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <memdraw.h> +#include <thread.h> +#include <cursor.h> +#include <mouse.h> +#include <keyboard.h> +#include <frame.h> +#include <plumb.h> +#include <html.h> +#include "dat.h" +#include "fns.h" + +void +drawtable(Box *b, Page *p, Image *im) +{ + Rectangle r, cr; + Tablecell *c; + Table *t; + + t = ((Itable *)b->i)->table; + r = rectsubpt(b->r, p->pos); + draw(im, r, getcolor(t->background.color), nil, ZP); + if(t->border) + border(im, r, t->border, display->black, ZP); + for(c=t->cells; c!=nil; c=c->next){ + cr = rectsubpt(c->lay->r, p->pos); + if(c->background.color != t->background.color) + draw(im, cr, getcolor(c->background.color), nil, ZP); + if(t->border) + border(im, cr, t->border, display->black, ZP); + laydraw(p, im, c->lay); + } +} + +enum +{ + Tablemax = 2000, + Ttoplevel = 1<<0, + +}; + +static +void +settable(Table *t) +{ + Tablecell *c; + Lay *lay; + + for(c=t->cells; c!=nil; c=c->next){ + lay = layitems(c->content, Rect(0,0,0,0), FALSE); + c->minw = Dx(lay->r); + layfree(lay); + if(dimenkind(c->wspec) == Dnone){ + lay = layitems(c->content, Rect(0,0,Tablemax,0), FALSE); + c->maxw = Dx(lay->r); + layfree(lay); + } + } +} + +void +settables(Page *p) +{ + Table *t; + Item *i; + + if(p->doc==nil) + return; + for(i=p->items; i!=nil; i=i->next) + if(i->tag == Itabletag) + ((Itable *)i)->table->flags |= Ttoplevel; + + for(t=p->doc->tables; t!=nil; t=t->next) + settable(t); +} + +static +int +cellwidth(Table *t, Tablecell *c, int sep) +{ + int w, i, n; + + n = c->colspan; + if(n == 1) + return t->cols[c->col].width; + if(n == 0) + n = t->ncol - c->col; + + w = t->cellspacing*(n-1) + n*sep; + for(i=c->col; i<c->col+n; i++) + w += t->cols[i].width; + + return w; +} + +static +int +cellheight(Table *t, Tablecell *c, int sep) +{ + int h, i, n; + + n = c->rowspan; + if(n == 1) + return t->rows[c->row].height; + if(n == 0) + n = t->nrow - c->row; + + h = t->cellspacing*(n-1) + n*sep; + for(i=c->row; i<c->row+n; i++) + h += t->rows[i].height; + + return h; +} + +static +int +getwidth(int *w, int n) +{ + int i, tot; + + tot = 0; + for(i=0; i<n; i++) + tot += w[i]; + + return tot; +} + +static +void +fixcols(Table *t, int *width, int sep, int domax) +{ + Tablecell *c; + int w, aw, i, d, n, rem; + + + for(c=t->cells; c!=nil; c=c->next){ + if(c->colspan == 1) + continue; + + n = c->colspan; + if(n == 0) + n = t->ncol - c->col; + + w = domax ? c->maxw : c->minw; + w -= t->cellspacing*(n-1) + n*sep; + + aw = 0; + for(i=c->col; i<c->col+n; i++) + aw += width[i]; + + rem = w-aw; + if(rem <= 0) + continue; + + for(i=c->col; i<c->col+n; i++){ + if(aw > 0){ + d = width[i]*100/aw; + d = d*rem/100; + }else + d = rem/n; + width[i] += d; + } + } +} + +static +int +tablewidth(Table *t, int tw, int sep) +{ + Tablecell *c; + int i, w, tmin, tmax, d; + int *maxw, *minw; + int totw; + + maxw = emalloc(sizeof(int)*t->ncol); + minw = emalloc(sizeof(int)*t->ncol); + for(c=t->cells; c!=nil; c=c->next){ + if(dimenkind(c->wspec) != Dnone){ + d = c->minw; + c->minw = c->maxw = max(dimwidth(c->wspec, tw), c->minw); + c->minw = d; + } + if(c->colspan != 1) + continue; + maxw[c->col] = max(maxw[c->col], c->maxw); + minw[c->col] = max(minw[c->col], c->minw); + } + totw = 0; + fixcols(t, maxw, sep, TRUE); + tmax = getwidth(maxw, t->ncol); + if(tmax <= tw){ + d = 0; + if(tw>tmax && dimenkind(t->width)!=Dnone && t->availw!=Tablemax) + d = (tw-tmax)/t->ncol; + for(i=0; i<t->ncol; i++){ + t->cols[i].width = maxw[i] + d; + totw += t->cols[i].width; + } + }else{ + fixcols(t, minw, sep, FALSE); + tmin = getwidth(minw, t->ncol); + w = tw - tmin; + d = tmax - tmin; + for(i=0; i<t->ncol; i++){ + if(w<=0 || d<=0) + t->cols[i].width = minw[i]; + else + t->cols[i].width = minw[i] + (maxw[i] - minw[i])*w/d; + totw += t->cols[i].width; + } + } + free(minw); + free(maxw); + + return totw; +} + +static +void +fixrows(Table *t, int sep) +{ + Tablecell *c; + Lay *lay; + int h, ah, i, d, n, rem; + + for(c=t->cells; c!=nil; c=c->next){ + if(c->rowspan == 1) + continue; + n = c->rowspan; + if(n==0 || c->row+n>t->nrow) + n = t->nrow - c->row; + + lay = layitems(c->content, Rect(0,0,cellwidth(t, c, sep),0), FALSE); + h = max(Dy(lay->r), c->hspec); + layfree(lay); + h -= t->cellspacing*(n-1) + n*sep; + ah = 0; + for(i=c->row; i<c->row+n; i++) + ah += t->rows[i].height; + + rem = h-ah; + if(rem <= 0) + continue; + + for(i=c->row; i<c->row+n; i++){ + if(ah > 0){ + d = t->rows[i].height*100/ah; + d = d*rem/100; + }else + d = rem/n; + + t->rows[i].height += d; + } + } +} + +static +int +tableheight(Table *t, int sep) +{ + Tablecell *c; + Lay *lay; + int i, h, toth; + + for(i=0; i<t->nrow; i++){ + h = 0; + for(c=t->rows[i].cells; c!=nil; c=c->nextinrow){ + if(c->rowspan != 1) + continue; + lay = layitems(c->content, Rect(0, 0, cellwidth(t, c, sep), 0), FALSE); + h = max(h, max(Dy(lay->r), c->hspec)); + layfree(lay); + } + t->rows[i].height = h; + } + fixrows(t, sep); + toth = 0; + for(i=0; i<t->nrow; i++) + toth += t->rows[i].height; + + return toth; +} + +void +tablesize(Table *t, int availw) +{ + int w, sep, hsep, vsep; + + t->availw = availw; + sep = 2*(t->border+t->cellpadding); + hsep = t->cellspacing*(t->ncol+1) + 2*t->border + t->ncol*sep; + vsep = t->cellspacing*(t->nrow+1) + 2*t->border + t->nrow*sep; + w = dimwidth(t->width, availw); + w -= hsep; + w = w>0 ? w : 0; + t->totw = tablewidth(t, w, sep); + t->totw += hsep; + t->toth = tableheight(t, sep); + t->toth += vsep; +} + +void +laytable(Itable *it, Rectangle r) +{ + Rectangle cr; + Tablecell *c; + Table *t; + int x, y, h, w; + int sep, i; + + t = it->table; + + sep = (t->cellpadding+t->border) * 2; + r = insetrect(r, t->cellspacing+t->border); + for(c=t->cells; c!=nil; c=c->next){ + w = cellwidth(t, c, sep); + h = cellheight(t, c, sep); + x = r.min.x; + if(c->col > 0) + for(i=0; i<c->col; i++) + x += t->cols[i].width + sep + t->cellspacing; + y = r.min.y; + if(c->row > 0) + for(i=0;i <c->row; i++) + y += t->rows[i].height + sep + t->cellspacing; + cr = Rect(x, y, x+w+sep, y+h+sep); + c->lay = layitems(c->content, insetrect(cr, sep/2), TRUE); + c->lay->r = cr; + } +} diff --git a/sys/src/cmd/abaco/tcs.h b/sys/src/cmd/abaco/tcs.h new file mode 100755 index 000000000..d0533e300 --- /dev/null +++ b/sys/src/cmd/abaco/tcs.h @@ -0,0 +1,167 @@ +"iso_8859-1:1987", "8859-1", +"iso-ir-100", "8859-1", +"iso_8859-1", "8859-1", +"iso-8859-1", "8859-1", +"latin1", "8859-1", +"l1", "8859-1", +"ibm819", "8859-1", +"cp819", "8859-1", +"csisolatin1", "8859-1", +"iso_8859-2:1987", "8859-2", +"iso-ir-101", "8859-2", +"iso_8859-2", "8859-2", +"iso-8859-2", "8859-2", +"latin2", "8859-2", +"l2", "8859-2", +"csisolatin2", "8859-2", +"iso_8859-3:1988", "8859-3", +"iso-ir-109", "8859-3", +"iso_8859-3", "8859-3", +"iso-8859-3", "8859-3", +"latin3", "8859-3", +"l3", "8859-3", +"csisolatin3", "8859-3", +"iso_8859-4:1988", "8859-4", +"iso-ir-110", "8859-4", +"iso_8859-4", "8859-4", +"iso-8859-4", "8859-4", +"latin4", "8859-4", +"l4", "8859-4", +"csisolatin4", "8859-4", +"iso_8859-5:1988", "8859-5", +"iso-ir-144", "8859-5", +"iso_8859-5", "8859-5", +"iso-8859-5", "8859-5", +"cyrillic", "8859-5", +"csisolatincyrillic", "8859-5", +"iso_8859-6:1987", "8859-6", +"iso-ir-127", "8859-6", +"iso_8859-6", "8859-6", +"iso-8859-6", "8859-6", +"ecma-114", "8859-6", +"asmo-708", "8859-6", +"arabic", "8859-6", +"csisolatinarabic", "8859-6", +"iso_8859-7:1987", "8859-7", +"iso-ir-126", "8859-7", +"iso_8859-7", "8859-7", +"iso-8859-7", "8859-7", +"elot_928", "8859-7", +"ecma-118", "8859-7", +"greek", "8859-7", +"greek8", "8859-7", +"csisolatingreek", "8859-7", +"iso_8859-8:1988", "8859-8", +"iso-ir-138", "8859-8", +"iso_8859-8", "8859-8", +"iso-8859-8", "8859-8", +"hebrew", "8859-8", +"csisolatinhebrew", "8859-8", +"iso_8859-9:1989", "8859-9", +"iso-ir-148", "8859-9", +"iso_8859-9", "8859-9", +"iso-8859-9", "8859-9", +"latin5", "8859-9", +"l5", "8859-9", +"csisolatin5", "8859-9", +"iso-8859-15", "8859-15", +"iso_8859-15", "8859-15", +"latin-9", "8859-15", +"ansi_x3.4-1968", "ascii", +"iso-ir-6", "ascii", +"ansi_x3.4-1986", "ascii", +"iso_646.irv:1991", "ascii", +"ascii", "ascii", +"iso646-us", "ascii", +"us-ascii", "ascii", +"us", "ascii", +"ibm367", "ascii", +"cp367", "ascii", +"csascii", "ascii", +"big5", "big5", +"csbig5", "big5", +"ibm437", "ibm437", +"cp437", "ibm437", +"437", "ibm437", +"cspc8codepage437", "ibm437", +"ibm850", "ibm850", +"cp850", "ibm850", +"850", "ibm850", +"cspc850multilingual", "ibm850", +"ibm852", "ibm852", +"cp852", "ibm852", +"852", "ibm852", +"cspcp852", "ibm852", +"ibm855", "ibm855", +"cp855", "ibm855", +"855", "ibm855", +"csibm855", "ibm855", +"ibm857", "ibm857", +"cp857", "ibm857", +"857", "ibm857", +"csibm857", "ibm857", +"ibm862", "ibm862", +"cp862", "ibm862", +"862", "ibm862", +"cspc862latinhebrew", "ibm862", +"ibm866", "ibm866", +"cp866", "ibm866", +"866", "ibm866", +"csibm866", "ibm866", +"windows-1250", "windows-1250", +"windows-1251", "windows-1251", +"windows-1252", "windows-1252", +"windows-1253", "windows-1253", +"windows-1254", "windows-1254", +"windows-1255", "windows-1255", +"windows-1256", "windows-1256", +"windows-1257", "windows-1257", +"windows-1258", "windows-1258", +"ks_c_5601-1987", "euc-k", +"iso-ir-149", "euc-k", +"ks_c_5601-1989", "euc-k", +"ksc_5601", "euc-k", +"korean", "euc-k", +"csksc56011987", "euc-k", +"euc-kr", "euc-k", +"cseuckr", "euc-k", +"gb2312", "gb", +"csgb2312", "gb", +"gb_2312-80", "gb", +"iso-ir-58", "gb", +"chinese", "gb", +"csiso58gb231280", "gb", +"iso-2022-jp", "jis-kanji", +"csiso2022jp", "jis-kanji", +"koi8-r", "koi8", +"cskoi8r", "koi8", +"macintosh", "macrom", +"mac", "macrom", +"csmacintosh", "macrom", +"ibm865", "msdos2", +"cp865", "msdos2", +"865", "msdos2", +"csibm865", "msdos2", +"shift_jis", "ms-kanji", +"ms_kanji", "ms-kanji", +"csshiftjis", "ms-kanji", +"sen_850200_b", "sf1", +"iso-ir-10", "sf1", +"fi", "sf1", +"iso646-fi", "sf1", +"iso646-se", "sf1", +"se", "sf1", +"csiso10swedish", "sf1", +"sen_850200_c", "sf2", +"iso-ir-11", "sf2", +"iso646-se2", "sf2", +"se2", "sf2", +"csiso11swedishfornames", "sf2", +"tis-620", "tis", +"extended_unix_code_packed_format_for_japanese", "ujis", +"cseucpkdfmtjapanese", "ujis", +"euc-jp", "ujis", +"iso-10646-utf-1", "utf1", +"csiso10646utf1", "utf1", +"viscii", "viscii", +"csviscii", "viscii", diff --git a/sys/src/cmd/abaco/tcs.txt b/sys/src/cmd/abaco/tcs.txt new file mode 100755 index 000000000..8aa98345a --- /dev/null +++ b/sys/src/cmd/abaco/tcs.txt @@ -0,0 +1,58 @@ +iso_8859-1 8859-1 +iso_8859-2 8859-2 +iso_8859-3 8859-3 +iso_8859-4 8859-4 +iso_8859-5 8859-5 +iso_8859-6 8859-6 +iso_8859-7 8859-7 +iso_8859-8 8859-8 +iso_8859-9 8859-9 +iso_8859-10 8859-10 +iso_8859-15 8859-15 +ascii ascii + atari + av +big5 big5 +ibm437 ibm437 + ibm720 + ibm737 +ibm735 ibm775 +ibm850 ibm850 +ibm852 ibm852 +ibm855 ibm855 +ibm857 ibm857 + ibm858 +ibm862 ibm862 +ibm866 ibm866 + ibm874 +windows-1250 windows-1250 +windows-1251 windows-1251 +windows-1252 windows-1252 +windows-1253 windows-1253 +windows-1254 windows-1254 +windows-1255 windows-1255 +windows-1256 windows-1256 +windows-1257 windows-1257 +windows-1258 windows-1258 + ebcdic +korean euc-k +euc-kr euc-k +gb2312 gb +gb_2312-80 gb +iso-2022-jp jis-kanji +koi8-r koi8 +macintosh macrom +ibm865 msdos2 +shift_jis ms-kanji + next + ov +se sf1 +se2 sf2 +tis-620 tis + ucode +euc-jp ujis +utf16 unicode +iso-10646-utf-1 utf1 +viscii-1 viet1 +viscii-2 viet2 +viscii viscii diff --git a/sys/src/cmd/abaco/text.c b/sys/src/cmd/abaco/text.c new file mode 100755 index 000000000..8c145a154 --- /dev/null +++ b/sys/src/cmd/abaco/text.c @@ -0,0 +1,880 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <memdraw.h> +#include <thread.h> +#include <cursor.h> +#include <mouse.h> +#include <keyboard.h> +#include <frame.h> +#include <plumb.h> +#include <html.h> +#include "dat.h" +#include "fns.h" + +Image *tagcols[NCOL]; +Image *textcols[NCOL]; + + +void +textinit(Text *t, Image *b, Rectangle r, Font *f, Image *cols[NCOL]) +{ + t->all = r; + t->scrollr = r; + t->scrollr.max.x = r.min.x+Scrollsize; + t->lastsr = ZR; + r.min.x += Scrollsize+Scrollgap; + t->rs.nr = 0; + memmove(t->Frame.cols, cols, sizeof t->Frame.cols); + textredraw(t, r, f, b); +} + +void +textredraw(Text *t, Rectangle r, Font *f, Image *b) +{ + Rectangle r1; + + frinit(t, r, f, b, t->Frame.cols); + r1 = t->r; + r1.min.x -= Scrollsize+Scrollgap; /* back fill to scroll bar */ + draw(t->b, r1, t->cols[BACK], nil, ZP); + t->maxtab = Maxtab*stringwidth(f, "0"); + textfill(t); + textsetselect(t, t->q0, t->q1); +} + +int +textresize(Text *t, Image *b, Rectangle r) +{ + if(Dy(r) > 0) + r.max.y -= Dy(r)%t->font->height; + else + r.max.y = r.min.y; + + t->all = r; + t->scrollr = r; + t->scrollr.max.x = r.min.x+Scrollsize; + t->lastsr = ZR; + r.min.x += Scrollsize+Scrollgap; + frclear(t, 0); + textredraw(t, r, t->font, b); + if(t->what == Textarea) + textscrdraw(t); + return r.max.y; +} + +void +textclose(Text *t) +{ + closerunestr(&t->rs); + frclear(t, 1); +} + +void +textinsert(Text *t, uint q0, Rune *r, uint n) +{ + if(n == 0) + return; + + t->rs.r = runerealloc(t->rs.r, t->rs.nr+n); + runemove(t->rs.r+q0+n, t->rs.r+q0, t->rs.nr-q0); + runemove(t->rs.r+q0, r, n); + t->rs.nr += n; + if(q0 < t->q1) + t->q1 += n; + if(q0 < t->q0) + t->q0 += n; + if(q0 < t->org) + t->org += n; + else if(q0 <= t->org+t->nchars) + frinsert(t, r, r+n, q0-t->org); +} + +void +textfill(Text *t) +{ + Rune *rp; + int i, n, m, nl; + + if(t->lastlinefull) + return; + rp = runemalloc(BUFSIZE*8); + do{ + n = t->rs.nr-(t->org+t->nchars); + if(n == 0) + break; + if(n > 2000) /* educated guess at reasonable amount */ + n = 2000; + runemove(rp, t->rs.r+(t->org+t->nchars), n); + /* + * it's expensive to frinsert more than we need, so + * count newlines. + */ + nl = t->maxlines-t->nlines; + m = 0; + for(i=0; i<n; ){ + if(rp[i++] == '\n'){ + m++; + if(m >= nl) + break; + } + } + frinsert(t, rp, rp+i, t->nchars); + }while(t->lastlinefull == FALSE); + free(rp); +} + +void +textdelete(Text *t, uint q0, uint q1) +{ + uint n, p0, p1; + + n = q1-q0; + if(n == 0) + return; + + runemove(t->rs.r+q0, t->rs.r+q1, t->rs.nr-q1); + t->rs.nr -= n; + if(q0 < t->q0) + t->q0 -= min(n, t->q0-q0); + if(q0 < t->q1) + t->q1 -= min(n, t->q1-q0); + if(q1 <= t->org) + t->org -= n; + else if(q0 < t->org+t->nchars){ + p1 = q1 - t->org; + if(p1 > t->nchars) + p1 = t->nchars; + if(q0 < t->org){ + t->org = q0; + p0 = 0; + }else + p0 = q0 - t->org; + frdelete(t, p0, p1); + textfill(t); + } + t->rs.r[t->rs.nr] = L'\0'; +} + +int +textbswidth(Text *t, Rune c) +{ + uint q, eq; + Rune r; + int skipping; + + /* there is known to be at least one character to erase */ + if(c == 0x08) /* ^H: erase character */ + return 1; + q = t->q0; + skipping = TRUE; + while(q > 0){ + r = t->rs.r[q-1]; + if(r == '\n'){ /* eat at most one more character */ + if(q == t->q0) /* eat the newline */ + --q; + break; + } + if(c == 0x17){ + eq = isalnum(r); + if(eq && skipping) /* found one; stop skipping */ + skipping = FALSE; + else if(!eq && !skipping) + break; + } + --q; + } + return t->q0-q; +} + +void +texttype(Text *t, Rune r) +{ + uint q0, q1; + int nb, n; + int nr; + Rune *rp; + + if(t->what!=Textarea && r=='\n'){ + if(t->what==Urltag) + get(t, t, XXX, XXX, nil, 0); + return; + } + if(t->what==Tag && (r==Kscrollonedown || r==Kscrolloneup)) + return; + + nr = 1; + rp = &r; + switch(r){ + case Kleft: + if(t->q0 > 0) + textshow(t, t->q0-1, t->q0-1, TRUE); + return; + case Kright: + if(t->q1 < t->rs.nr) + textshow(t, t->q1+1, t->q1+1, TRUE); + return; + case Kdown: + n = t->maxlines/3; + goto case_Down; + case Kscrollonedown: + n = mousescrollsize(t->maxlines); + if(n <= 0) + n = 1; + goto case_Down; + case Kpgdown: + n = 2*t->maxlines/3; + case_Down: + q0 = t->org+frcharofpt(t, Pt(t->r.min.x, t->r.min.y+n*t->font->height)); + textsetorigin(t, q0, TRUE); + return; + case Kup: + n = t->maxlines/3; + goto case_Up; + case Kscrolloneup: + n = mousescrollsize(t->maxlines); + goto case_Up; + case Kpgup: + n = 2*t->maxlines/3; + case_Up: + q0 = textbacknl(t, t->org, n); + textsetorigin(t, q0, TRUE); + return; + case Khome: + textshow(t, 0, 0, FALSE); + return; + case Kend: + textshow(t, t->rs.nr, t->rs.nr, FALSE); + return; + case 0x01: /* ^A: beginning of line */ + /* go to where ^U would erase, if not already at BOL */ + nb = 0; + if(t->q0>0 && t->rs.r[t->q0-1]!='\n') + nb = textbswidth(t, 0x15); + textshow(t, t->q0-nb, t->q0-nb, TRUE); + return; + case 0x05: /* ^E: end of line */ + q0 = t->q0; + while(q0<t->rs.nr && t->rs.r[q0]!='\n') + q0++; + textshow(t, q0, q0, TRUE); + return; + } + if(t->q1 > t->q0) + cut(t, t, TRUE, TRUE, nil, 0); + + textshow(t, t->q0, t->q0, TRUE); + switch(r){ + case 0x08: /* ^H: erase character */ + case 0x15: /* ^U: erase line */ + case 0x17: /* ^W: erase word */ + if(t->q0 == 0) /* nothing to erase */ + return; + nb = textbswidth(t, r); + q1 = t->q0; + q0 = q1-nb; + /* if selection is at beginning of window, avoid deleting invisible text */ + if(q0 < t->org){ + q0 = t->org; + nb = q1-q0; + } + if(nb > 0){ + textdelete(t, q0, q0+nb); + textsetselect(t, q0, q0); + } + return; + } + /* otherwise ordinary character; just insert */ + textinsert(t, t->q0, &r, 1); + if(rp != &r) + free(rp); + textsetselect(t, t->q0+nr, t->q0+nr); + if(t->what == Textarea) + textscrdraw(t); +} + +static Text *clicktext; +static uint clickmsec; +static Text *selecttext; +static uint selectq; + +/* + * called from frame library + */ +void +framescroll(Frame *f, int dl) +{ + if(f != &selecttext->Frame) + error("frameselect not right frame"); + textframescroll(selecttext, dl); +} + +void +textframescroll(Text *t, int dl) +{ + uint q0; + + if(dl == 0){ + scrsleep(100); + return; + } + if(dl < 0){ + q0 = textbacknl(t, t->org, -dl); + if(selectq > t->org+t->p0) + textsetselect(t, t->org+t->p0, selectq); + else + textsetselect(t, selectq, t->org+t->p0); + }else{ + if(t->org+t->nchars == t->rs.nr) + return; + q0 = t->org+frcharofpt(t, Pt(t->r.min.x, t->r.min.y+dl*t->font->height)); + if(selectq > t->org+t->p1) + textsetselect(t, t->org+t->p1, selectq); + else + textsetselect(t, selectq, t->org+t->p1); + } + textsetorigin(t, q0, TRUE); +} + +void +textselect(Text *t) +{ + uint q0, q1; + int b, x, y; + int state; + + selecttext = t; + /* + * To have double-clicking and chording, we double-click + * immediately if it might make sense. + */ + b = mouse->buttons; + q0 = t->q0; + q1 = t->q1; + selectq = t->org+frcharofpt(t, mouse->xy); + if(clicktext==t && mouse->msec-clickmsec<500) + if(q0==q1 && selectq==q0){ + textdoubleclick(t, &q0, &q1); + textsetselect(t, q0, q1); + flushimage(display, 1); + x = mouse->xy.x; + y = mouse->xy.y; + /* stay here until something interesting happens */ + do + readmouse(mousectl); + while(mouse->buttons==b && abs(mouse->xy.x-x)<3 && abs(mouse->xy.y-y)<3); + mouse->xy.x = x; /* in case we're calling frselect */ + mouse->xy.y = y; + q0 = t->q0; /* may have changed */ + q1 = t->q1; + selectq = q0; + } + if(mouse->buttons == b){ + t->Frame.scroll = framescroll; + frselect(t, mousectl); + /* horrible botch: while asleep, may have lost selection altogether */ + if(selectq > t->rs.nr) + selectq = t->org + t->p0; + t->Frame.scroll = nil; + if(selectq < t->org) + q0 = selectq; + else + q0 = t->org + t->p0; + if(selectq > t->org+t->nchars) + q1 = selectq; + else + q1 = t->org+t->p1; + } + if(q0 == q1){ + if(q0==t->q0 && clicktext==t && mouse->msec-clickmsec<500){ + textdoubleclick(t, &q0, &q1); + clicktext = nil; + }else{ + clicktext = t; + clickmsec = mouse->msec; + } + }else + clicktext = nil; + textsetselect(t, q0, q1); + flushimage(display, 1); + state = 0; /* undo when possible; +1 for cut, -1 for paste */ + while(mouse->buttons){ + mouse->msec = 0; + b = mouse->buttons; + if((b&1) && (b&6)){ + if(b & 2){ + if(state==-1 && t->what==Textarea){ + textsetselect(t, q0, t->q0); + state = 0; + }else if(state != 1){ + cut(t, t, TRUE, TRUE, nil, 0); + state = 1; + } + }else{ + if(state==1 && t->what==Textarea){ + textsetselect(t, q0, t->q1); + state = 0; + }else if(state != -1){ + paste(t, t, TRUE, FALSE, nil, 0); + state = -1; + } + } + textscrdraw(t); + } + flushimage(display, 1); + while(mouse->buttons == b) + readmouse(mousectl); + clicktext = nil; + } +} + +void +textshow(Text *t, uint q0, uint q1, int doselect) +{ + int qe; + int nl; + uint q; + + if(t->what != Textarea){ + if(doselect) + textsetselect(t, q0, q1); + return; + } + if(doselect) + textsetselect(t, q0, q1); + qe = t->org+t->nchars; + if(t->org<=q0 && (q0<qe || (q0==qe && qe==t->rs.nr))) + textscrdraw(t); + else{ + nl = t->maxlines/4; + q = textbacknl(t, q0, nl); + /* avoid going backwards if trying to go forwards - long lines! */ + if(!(q0>t->org && q<t->org)) + textsetorigin(t, q, TRUE); + while(q0 > t->org+t->nchars) + textsetorigin(t, t->org+1, FALSE); + } +} + +static +int +region(int a, int b) +{ + if(a < b) + return -1; + if(a == b) + return 0; + return 1; +} + +void +selrestore(Frame *f, Point pt0, uint p0, uint p1) +{ + if(p1<=f->p0 || p0>=f->p1){ + /* no overlap */ + frdrawsel0(f, pt0, p0, p1, f->cols[BACK], f->cols[TEXT]); + return; + } + if(p0>=f->p0 && p1<=f->p1){ + /* entirely inside */ + frdrawsel0(f, pt0, p0, p1, f->cols[HIGH], f->cols[HTEXT]); + return; + } + + /* they now are known to overlap */ + + /* before selection */ + if(p0 < f->p0){ + frdrawsel0(f, pt0, p0, f->p0, f->cols[BACK], f->cols[TEXT]); + p0 = f->p0; + pt0 = frptofchar(f, p0); + } + /* after selection */ + if(p1 > f->p1){ + frdrawsel0(f, frptofchar(f, f->p1), f->p1, p1, f->cols[BACK], f->cols[TEXT]); + p1 = f->p1; + } + /* inside selection */ + frdrawsel0(f, pt0, p0, p1, f->cols[HIGH], f->cols[HTEXT]); +} + +void +textsetselect(Text *t, uint q0, uint q1) +{ + int p0, p1; + + /* t->p0 and t->p1 are always right; t->q0 and t->q1 may be off */ + t->q0 = q0; + t->q1 = q1; + /* compute desired p0,p1 from q0,q1 */ + p0 = q0-t->org; + p1 = q1-t->org; + if(p0 < 0) + p0 = 0; + if(p1 < 0) + p1 = 0; + if(p0 > t->nchars) + p0 = t->nchars; + if(p1 > t->nchars) + p1 = t->nchars; + if(p0==t->p0 && p1==t->p1) + return; + /* screen disagrees with desired selection */ + if(t->p1<=p0 || p1<=t->p0 || p0==p1 || t->p1==t->p0){ + /* no overlap or too easy to bother trying */ + frdrawsel(t, frptofchar(t, t->p0), t->p0, t->p1, 0); + frdrawsel(t, frptofchar(t, p0), p0, p1, 1); + goto Return; + } + /* overlap; avoid unnecessary painting */ + if(p0 < t->p0){ + /* extend selection backwards */ + frdrawsel(t, frptofchar(t, p0), p0, t->p0, 1); + }else if(p0 > t->p0){ + /* trim first part of selection */ + frdrawsel(t, frptofchar(t, t->p0), t->p0, p0, 0); + } + if(p1 > t->p1){ + /* extend selection forwards */ + frdrawsel(t, frptofchar(t, t->p1), t->p1, p1, 1); + }else if(p1 < t->p1){ + /* trim last part of selection */ + frdrawsel(t, frptofchar(t, p1), p1, t->p1, 0); + } + + Return: + t->p0 = p0; + t->p1 = p1; +} + + +/* + * Release the button in less than DELAY ms and it's considered a null selection + * if the mouse hardly moved, regardless of whether it crossed a char boundary. + */ +enum { + DELAY = 2, + MINMOVE = 4, +}; + +uint +xselect(Frame *f, Mousectl *mc, Image *col, uint *p1p) /* when called, button is down */ +{ + uint p0, p1, q, tmp; + ulong msec; + Point mp, pt0, pt1, qt; + int reg, b; + + mp = mc->xy; + b = mc->buttons; + msec = mc->msec; + + /* remove tick */ + if(f->p0 == f->p1) + frtick(f, frptofchar(f, f->p0), 0); + p0 = p1 = frcharofpt(f, mp); + pt0 = frptofchar(f, p0); + pt1 = frptofchar(f, p1); + reg = 0; + frtick(f, pt0, 1); + do{ + q = frcharofpt(f, mc->xy); + if(p1 != q){ + if(p0 == p1) + frtick(f, pt0, 0); + if(reg != region(q, p0)){ /* crossed starting point; reset */ + if(reg > 0) + selrestore(f, pt0, p0, p1); + else if(reg < 0) + selrestore(f, pt1, p1, p0); + p1 = p0; + pt1 = pt0; + reg = region(q, p0); + if(reg == 0) + frdrawsel0(f, pt0, p0, p1, col, display->white); + } + qt = frptofchar(f, q); + if(reg > 0){ + if(q > p1) + frdrawsel0(f, pt1, p1, q, col, display->white); + + else if(q < p1) + selrestore(f, qt, q, p1); + }else if(reg < 0){ + if(q > p1) + selrestore(f, pt1, p1, q); + else + frdrawsel0(f, qt, q, p1, col, display->white); + } + p1 = q; + pt1 = qt; + } + if(p0 == p1) + frtick(f, pt0, 1); + flushimage(f->display, 1); + readmouse(mc); + }while(mc->buttons == b); + if(mc->msec-msec < DELAY && p0!=p1 + && abs(mp.x-mc->xy.x)<MINMOVE + && abs(mp.y-mc->xy.y)<MINMOVE) { + if(reg > 0) + selrestore(f, pt0, p0, p1); + else if(reg < 0) + selrestore(f, pt1, p1, p0); + p1 = p0; + } + if(p1 < p0){ + tmp = p0; + p0 = p1; + p1 = tmp; + } + pt0 = frptofchar(f, p0); + if(p0 == p1) + frtick(f, pt0, 0); + selrestore(f, pt0, p0, p1); + /* restore tick */ + if(f->p0 == f->p1) + frtick(f, frptofchar(f, f->p0), 1); + flushimage(f->display, 1); + *p1p = p1; + return p0; +} + +int +textselect23(Text *t, uint *q0, uint *q1, Image *high, int mask) +{ + uint p0, p1; + int buts; + + p0 = xselect(t, mousectl, high, &p1); + buts = mousectl->buttons; + if((buts & mask) == 0){ + *q0 = p0+t->org; + *q1 = p1+t->org; + } + + while(mousectl->buttons) + readmouse(mousectl); + return buts; +} + +int +textselect2(Text *t, uint *q0, uint *q1, Text **tp) +{ + int buts; + + *tp = nil; + buts = textselect23(t, q0, q1, but2col, 4); + if(buts & 4) + return 0; + if(buts & 1){ /* pick up argument */ + *tp = argtext; + return 1; + } + return 1; +} + +int +textselect3(Text *t, uint *q0, uint *q1) +{ + int h; + + h = (textselect23(t, q0, q1, but3col, 1|2) == 0); + return h; +} + +static Rune left1[] = { L'{', L'[', L'(', L'<', L'«', 0 }; +static Rune right1[] = { L'}', L']', L')', L'>', L'»', 0 }; +static Rune left2[] = { L'\n', 0 }; +static Rune left3[] = { L'\'', L'"', L'`', 0 }; + +static +Rune *left[] = { + left1, + left2, + left3, + nil +}; +static +Rune *right[] = { + right1, + left2, + left3, + nil +}; + +void +textdoubleclick(Text *t, uint *q0, uint *q1) +{ + int c, i; + Rune *r, *l, *p; + uint q; + + if(t->rs.nr == 0) + return; + + for(i=0; left[i]!=nil; i++){ + q = *q0; + l = left[i]; + r = right[i]; + /* try matching character to left, looking right */ + if(q == 0) + c = '\n'; + else + c = t->rs.r[q-1]; + p = runestrchr(l, c); + if(p != nil){ + if(textclickmatch(t, c, t->rs.r[p-l], 1, &q)) + *q1 = q-(c!='\n'); + return; + } + /* try matching character to right, looking left */ + if(q == t->rs.nr) + c = '\n'; + else + c = t->rs.r[q]; + p = runestrchr(r, c); + if(p != nil){ + if(textclickmatch(t, c, l[p-r], -1, &q)){ + *q1 = *q0+(*q0<t->rs.nr && c=='\n'); + *q0 = q; + if(c!='\n' || q!=0 || t->rs.r[0]=='\n') + (*q0)++; + } + return; + } + } + /* try filling out word to right */ + while(*q1<t->rs.nr && isalnum(t->rs.r[*q1])) + (*q1)++; + /* try filling out word to left */ + while(*q0>0 && isalnum(t->rs.r[*q0-1])) + (*q0)--; +} + +int +textclickmatch(Text *t, int cl, int cr, int dir, uint *q) +{ + Rune c; + int nest; + + nest = 1; + for(;;){ + if(dir > 0){ + if(*q == t->rs.nr) + break; + c = t->rs.r[*q]; + (*q)++; + }else{ + if(*q == 0) + break; + (*q)--; + c = t->rs.r[*q]; + } + if(c == cr){ + if(--nest==0) + return 1; + }else if(c == cl) + nest++; + } + return cl=='\n' && nest==1; +} + +uint +textbacknl(Text *t, uint p, uint n) +{ + int i, j; + + /* look for start of this line if n==0 */ + if(n==0 && p>0 && t->rs.r[p-1]!='\n') + n = 1; + i = n; + while(i-->0 && p>0){ + --p; /* it's at a newline now; back over it */ + if(p == 0) + break; + /* at 128 chars, call it a line anyway */ + for(j=128; --j>0 && p>0; p--) + if(t->rs.r[p-1]=='\n') + break; + } + return p; +} + +void +textsetorigin(Text *t, uint org, int exact) +{ + int i, a, fixup; + Rune *r; + uint n; + + if(org>0 && !exact){ + /* org is an estimate of the char posn; find a newline */ + /* don't try harder than 256 chars */ + for(i=0; i<256 && org<t->rs.nr; i++){ + if(t->rs.r[org] == '\n'){ + org++; + break; + } + org++; + } + } + a = org-t->org; + fixup = 0; + if(a>=0 && a<t->nchars){ + frdelete(t, 0, a); + fixup = 1; /* frdelete can leave end of last line in wrong selection mode; it doesn't know what follows */ + }else if(a<0 && -a<t->nchars){ + n = t->org - org; + r = runemalloc(n); + runemove(r, t->rs.r+org, n); + frinsert(t, r, r+n, 0); + free(r); + }else + frdelete(t, 0, t->nchars); + t->org = org; + textfill(t); + textscrdraw(t); + textsetselect(t, t->q0, t->q1); + if(fixup && t->p1 > t->p0) + frdrawsel(t, frptofchar(t, t->p1-1), t->p1-1, t->p1, 1); +} + +void +textset(Text *t, Rune*r, int n) +{ + textdelete(t, 0, t->rs.nr); + textinsert(t, 0, r, n); + textsetselect(t, t->q0, t->q1); +} + +void +textmouse(Text *t, Point xy, int but) +{ + Text *argt; + uint q0, q1; + + if(ptinrect(xy, t->scrollr)){ + if(t->what == Columntag) + rowdragcol(&row, t->col, but); + else if(t->what == Tag) + coldragwin(t->col, t->w, but); + else if(t->what == Textarea) + textscroll(t, but); + if(t->col) + activecol = t->col; + return; + } + if(but == 1){ + selpage = nil; + textselect(t); + argtext = t; + seltext = t; + }else if(but == 2){ + if(textselect2(t, &q0, &q1, &argt)) + execute(t, q0, q1, argt); + }else if(but == 3){ + if(textselect3(t, &q0, &q1)) + look3(t, q0, q1); + } +} diff --git a/sys/src/cmd/abaco/time.c b/sys/src/cmd/abaco/time.c new file mode 100755 index 000000000..e92a99bb8 --- /dev/null +++ b/sys/src/cmd/abaco/time.c @@ -0,0 +1,119 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <memdraw.h> +#include <thread.h> +#include <cursor.h> +#include <mouse.h> +#include <keyboard.h> +#include <frame.h> +#include <plumb.h> +#include <html.h> +#include "dat.h" +#include "fns.h" + +static Channel* ctimer; /* chan(Timer*)[100] */ +static Timer *timer; + +static +uint +msec(void) +{ + return nsec()/1000000; +} + +void +timerstop(Timer *t) +{ + t->next = timer; + timer = t; +} + +void +timercancel(Timer *t) +{ + t->cancel = TRUE; +} + +static +void +timerproc(void*) +{ + int i, nt, na, dt, del; + Timer **t, *x; + uint old, new; + + threadsetname("timerproc"); + rfork(RFFDG); + t = nil; + na = 0; + nt = 0; + old = msec(); + for(;;){ + sleep(1); /* will sleep minimum incr */ + new = msec(); + dt = new-old; + old = new; + if(dt < 0) /* timer wrapped; go around, losing a tick */ + continue; + for(i=0; i<nt; i++){ + x = t[i]; + x->dt -= dt; + del = FALSE; + if(x->cancel){ + timerstop(x); + del = TRUE; + }else if(x->dt <= 0){ + /* + * avoid possible deadlock if client is + * now sending on ctimer + */ + if(nbsendul(x->c, 0) > 0) + del = TRUE; + } + if(del){ + memmove(&t[i], &t[i+1], (nt-i-1)*sizeof t[0]); + --nt; + --i; + } + } + if(nt == 0){ + x = recvp(ctimer); + gotit: + if(nt == na){ + na += 10; + t = erealloc(t, na*sizeof(Timer*)); + } + t[nt++] = x; + old = msec(); + } + if(nbrecv(ctimer, &x) > 0) + goto gotit; + } +} + +void +timerinit(void) +{ + ctimer = chancreate(sizeof(Timer*), 100); + proccreate(timerproc, nil, STACK); +} + +Timer* +timerstart(int dt) +{ + Timer *t; + + t = timer; + if(t) + timer = timer->next; + else{ + t = emalloc(sizeof(Timer)); + t->c = chancreate(sizeof(int), 0); + } + t->next = nil; + t->dt = dt; + t->cancel = FALSE; + sendp(ctimer, t); + return t; +} diff --git a/sys/src/cmd/abaco/urls.c b/sys/src/cmd/abaco/urls.c new file mode 100755 index 000000000..9386cb164 --- /dev/null +++ b/sys/src/cmd/abaco/urls.c @@ -0,0 +1,230 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <memdraw.h> +#include <thread.h> +#include <cursor.h> +#include <mouse.h> +#include <keyboard.h> +#include <frame.h> +#include <plumb.h> +#include <html.h> +#include "dat.h" +#include "fns.h" + +Url * +urlalloc(Runestr *src, Runestr *post, int m) +{ + Url *u; + + u = emalloc(sizeof(Url)); + copyrunestr(&u->src, src); + if(m==HPost) + copyrunestr(&u->post, post); + u->method = m; + incref(u); + return u; +} + +void +urlfree(Url *u) +{ + if(u && decref(u)==0){ + closerunestr(&u->src); + closerunestr(&u->act); + closerunestr(&u->post); + closerunestr(&u->ctype); + free(u); + } +} + +Url * +urldup(Url *a) +{ + Url *b; + + b = emalloc(sizeof(Url)); + b->method = a->method; + copyrunestr(&b->src, &a->src); + copyrunestr(&b->act, &a->act); + copyrunestr(&b->post, &a->post); + copyrunestr(&b->ctype, &a->ctype); + return b; +} + +static +Runestr +getattr(int conn, char *s) +{ + char buf[BUFSIZE]; + int fd, n; + + snprint(buf, sizeof(buf), "%s/%d/%s", webmountpt, conn, s); + fd = open(buf, OREAD); + if(fd < 0) + error("can't open attr file"); + + n = read(fd, buf, sizeof(buf)-1); + if(n < 0) + error("can't read"); + + close(fd); + buf[n] = '\0'; + return (Runestr){runesmprint("%s", buf), n}; +} + +int +urlopen(Url *u) +{ + char buf[BUFSIZE]; + int cfd, fd, conn, n; + + snprint(buf, sizeof(buf), "%s/clone", webmountpt); + cfd = open(buf, ORDWR); + if(cfd < 0) + error("can't open clone file"); + + n = read(cfd, buf, sizeof(buf)-1); + if(n <= 0) + error("reading clone"); + + buf[n] = '\0'; + conn = atoi(buf); + + snprint(buf, sizeof(buf), "url %S", u->src.r); + if(write(cfd, buf, strlen(buf)) < 0){ +// fprint(2, "write: %s: %r\n", buf); + Err: + close(cfd); + return -1; + } + if(u->method==HPost && u->post.r != nil){ + snprint(buf, sizeof(buf), "%s/%d/postbody", webmountpt, conn); + fd = open(buf, OWRITE); + if(fd < 0){ +// fprint(2, "urlopen: bad query: %s: %r\n", buf); + goto Err; + } + snprint(buf, sizeof(buf), "%S", u->post.r); + if(write(fd, buf, strlen(buf)) < 0) + fprint(2, "urlopen: bad query: %s: %r\n", buf); + + close(fd); + } + snprint(buf, sizeof(buf), "%s/%d/body", webmountpt, conn); + fd = open(buf, OREAD); + if(fd < 0){ +// fprint(2, "open: %S: %r\n", u->src.r); + goto Err; + } + u->ctype = getattr(conn, "contenttype"); + u->act = getattr(conn, "parsed/url"); + if(u->act.nr == 0) + copyrunestr(&u->act, &u->src); + close(cfd); + return fd; +} + +void +urlcanon(Rune *name){ + Rune *s, *t; + Rune **comp, **p, **q; + int rooted; + + name = runestrchr(name, L'/')+2; + rooted=name[0]==L'/'; + /* + * Break the name into a list of components + */ + comp=emalloc(runestrlen(name)*sizeof(char *)); + p=comp; + *p++=name; + for(s=name;;s++){ + if(*s==L'/'){ + *p++=s+1; + *s='\0'; + } + else if(*s=='\0') + break; + } + *p=0; + /* + * go through the component list, deleting components that are empty (except + * the last component) or ., and any .. and its non-.. predecessor. + */ + p=q=comp; + while(*p){ + if(runestrcmp(*p, L"")==0 && p[1]!=0 + || runestrcmp(*p, L".")==0) + p++; + else if(runestrcmp(*p, L"..")==0 && q!=comp && runestrcmp(q[-1], L"..")!=0){ + --q; + p++; + } + else + *q++=*p++; + } + *q=0; + /* + * rebuild the path name + */ + s=name; + if(rooted) *s++='/'; + for(p=comp;*p;p++){ + t=*p; + while(*t) *s++=*t++; + if(p[1]!=0) *s++='/'; + } + *s='\0'; + free(comp); +} + +/* this is a HACK */ +Rune * +urlcombine(Rune *b, Rune *u) +{ + Rune *p, *q, *sep, *s; + Rune endrune[] = { L'?', L'#' }; + int i, restore; + + if(u == nil) + error("urlcombine: u == nil"); + + if(validurl(u)) + return erunestrdup(u); + + if(b==nil || !validurl(b)) + error("urlcombine: b==nil || !validurl(b)"); + + if(runestrncmp(u, L"//", 2) == 0){ + q = runestrchr(b, L':'); + return runesmprint("%.*S:%S", (int)(q-b), b, u); + } + p = runestrstr(b, L"://")+3; + sep = L""; + q = nil; + if(*u ==L'/') + q = runestrchr(p, L'/'); + else if(*u==L'#' || *u==L'?'){ + for(i=0; i<nelem(endrune); i++) + if(q = runestrchr(p, endrune[i])) + break; + }else{ + sep = L"/"; + restore = 0; + s = runestrchr(p, L'?'); + if(s != nil){ + *s = '\0'; + restore = 1; + } + q = runestrrchr(p, L'/'); + if(restore) + *s = L'?'; + } + if(q == nil) + p = runesmprint("%S%S%S", b, sep, u); + else + p = runesmprint("%.*S%S%S", (int)(q-b), b, sep, u); + urlcanon(p); + return p; +} diff --git a/sys/src/cmd/abaco/util.c b/sys/src/cmd/abaco/util.c new file mode 100755 index 000000000..cd7e7b3da --- /dev/null +++ b/sys/src/cmd/abaco/util.c @@ -0,0 +1,1293 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <draw.h> +#include <memdraw.h> +#include <thread.h> +#include <cursor.h> +#include <mouse.h> +#include <keyboard.h> +#include <frame.h> +#include <plumb.h> +#include <html.h> +#include <regexp.h> +#include "dat.h" +#include "fns.h" + +static Point prevmouse; +static Window *mousew; + +int +min(int a, int b) +{ + if(a < b) + return a; + return b; +} + +int +max(int a, int b) +{ + if(a > b) + return a; + return b; +} + +void +cvttorunes(char *p, int n, Rune *r, int *nb, int *nr, int *nulls) +{ + uchar *q; + Rune *s; + int j, w; + + /* + * Always guaranteed that n bytes may be interpreted + * without worrying about partial runes. This may mean + * reading up to UTFmax-1 more bytes than n; the caller + * knows this. If n is a firm limit, the caller should + * set p[n] = 0. + */ + q = (uchar*)p; + s = r; + for(j=0; j<n; j+=w){ + if(*q < Runeself){ + w = 1; + *s = *q++; + }else{ + w = chartorune(s, (char*)q); + q += w; + } + if(*s) + s++; + else if(nulls) + *nulls = TRUE; + } + *nb = (char*)q-p; + *nr = s-r; +} + +void +bytetorunestr(char *s, Runestr *rs) +{ + Rune *r; + int nb, nr; + + nb = strlen(s); + r = runemalloc(nb+1); + cvttorunes(s, nb, r, &nb, &nr, nil); + r[nr] = '\0'; + rs->nr = nr; + rs->r = r; +} + +void +error(char *s) +{ + fprint(2, "abaco: %s: %r\n", s); +// abort(); + threadexitsall(s); +} + +void* +emalloc(ulong n) +{ + void *p; + + p = malloc(n); + if(p == nil) + error("malloc failed"); + setmalloctag(p, getcallerpc(&n)); + memset(p, 0, n); + return p; +} + +void* +erealloc(void *p, ulong n) +{ + p = realloc(p, n); + if(p == nil) + error("realloc failed"); + setmalloctag(p, getcallerpc(&n)); + return p; +} + +Rune* +erunestrdup(Rune *r) +{ + void *p; + + if(r == nil) + return nil; + p = runestrdup(r); + if(p == nil) + error("runestrdup failed"); + setmalloctag(p, getcallerpc(&r)); + return p; +} + +char* +estrdup(char *s) +{ + char *t; + + t = strdup(s); + if(t == nil) + error("strdup failed"); + setmalloctag(t, getcallerpc(&s)); + return t; +} + +int +runestreq(Runestr a, Runestr b) +{ + return runeeq(a.r, a.nr, b.r, b.nr); +} + +int +runeeq(Rune *s1, uint n1, Rune *s2, uint n2) +{ + if(n1 != n2) + return FALSE; + return memcmp(s1, s2, n1*sizeof(Rune)) == 0; +} + +void +closerunestr(Runestr *rs) +{ + + rs->nr = 0; + if(rs->r) + free(rs->r); + rs->r = nil; +} + +void +copyrunestr(Runestr *a, Runestr *b) +{ + closerunestr(a); + a->r = runemalloc(b->nr+1); + runemove(a->r, b->r, b->nr); + a->r[b->nr] = 0; + a->nr = b->nr; +} + +int +isalnum(Rune c) +{ + /* + * Hard to get absolutely right. Use what we know about ASCII + * and assume anything above the Latin control characters is + * potentially an alphanumeric. + */ + if(c <= ' ') + return FALSE; + if(0x7F<=c && c<=0xA0) + return FALSE; + if(utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c)) + return FALSE; + return TRUE; +} + +Rune* +skipbl(Rune *r, int n, int *np) +{ + while(n>0 && (*r==' ' || *r=='\t' || *r=='\n')){ + --n; + r++; + } + *np = n; + return r; +} + +Rune* +findbl(Rune *r, int n, int *np) +{ + while(n>0 && *r!=' ' && *r!='\t' && *r!='\n'){ + --n; + r++; + } + *np = n; + return r; +} + +int +istextfield(Item *i) +{ + Formfield *ff; + + ff = ((Iformfield *)i)->formfield; + if(ff->ftype==Ftext || ff->ftype==Ftextarea || ff->ftype==Fpassword) + return TRUE; + + return FALSE; +} + +int +forceitem(Item *i) +{ + if(i->state&IFwrap && i->tag!=Iruletag && i->tag!=Itabletag) + return FALSE; + + return TRUE; +} + +int +dimwidth(Dimen d, int w) +{ + int s, k; + + k = dimenkind(d); + if(k == Dnone) + return w; + s = dimenspec(d); + if(k == Dpixels) + w = s; + else if(k==Dpercent && s<100) + w = s*w/100; + + return w; +} + +void +frdims(Dimen *d, int n, int t, int **ret) +{ + int totpix, totpcnt, totrel; + double spix, spcnt, relu, vd; + int tt, trest, totpixrel, minrelu, i; + int *x, *spec, *kind; + + if(n == 1){ + *ret = x = emalloc(sizeof(int)); + x[0] = t; + return; + } + totpix = totpcnt = totrel = 0; + spec = emalloc(n*sizeof(int)); + kind = emalloc(n*sizeof(int)); + for(i=0; i<n; i++){ + spec[i] = dimenspec(d[i]); + if(spec[i] < 0) + spec[i] = 0; + kind[i] = dimenkind(d[i]); + switch(kind[i]){ + case Dpixels: + totpix += spec[i]; + break; + case Dpercent: + totpcnt += spec[i]; + break; + case Drelative: + totrel += spec[i]; + break; + case Dnone: + totrel++; + break; + } + } + spix = spcnt = 1.0; + minrelu = 0; + if(totrel > 0) + minrelu = Scrollsize+Scrollgap; + relu = (double)minrelu; + tt = totpix + t*totpcnt/100 + totrel*minrelu; + if(tt < t){ + if(totrel == 0){ + if(totpcnt != 0) + spcnt = (double)((t-totpix)*100)/(double)(t*totpcnt); + else + spix = (double)t/(double)totpix; + }else + relu += (double)(t-tt)/(double)totrel; + }else{ + totpixrel = totpix + totrel*minrelu; + if(totpixrel < t) + spcnt = (double)((t-totpixrel)*100)/(double)(t*totpcnt); + else{ + trest = t - totrel*minrelu; + if(trest > 0) + spcnt = (double)trest/(double)(totpix + (t*totpcnt/100)); + else{ + spcnt = (double)t/(double)tt; + relu = 0.0; + } + spix = spcnt; + } + } + x = emalloc(n * sizeof(int)); + tt = 0; + for(i=0; i<n-1; i++){ + vd = (double)spec[i]; + switch(kind[i]){ + case Dpixels: + vd = vd*spix; + break; + case Dpercent: + vd = vd*(double)t*spcnt/100.0; + break; + case Drelative: + vd = vd*relu; + break; + case Dnone: + vd = relu; + break; + } + x[i] = (int)(vd+.5); + tt += x[i]; + } + x[n - 1] = t - tt; + *ret = x; + free(spec); + free(kind); +} + +Image * +getbg(Page *p) +{ + Docinfo *d; + Cimage *ci; + Image *bg; + + d = p->doc; + if(d->backgrounditem){ + if(d->backgrounditem->aux){ + ci = d->backgrounditem->aux; + if(ci->mi) + getimage(ci, d->backgrounditem->altrep); + bg = ci->i; + }else + bg = display->white; + }else + bg = getcolor(d->background.color); + + return bg; +} + +Rune * +getbase(Page *p) +{ + if(p->doc) + return p->doc->base; + if(p->url->act.r) + return p->url->act.r; + return p->url->src.r; +} + +Image * +eallocimage(Display *d, Rectangle r, ulong chan, int repl, int col) +{ + Image *i; + + i = allocimage(d, r, chan, repl, col); + if(i == nil) + error("allocimage failed"); + return i; +} + +void +rect3d(Image *im, Rectangle r, int i, Image **c, Point sp) +{ + Point p[6]; + + if(i < 0){ + r = insetrect(r, i); + sp = addpt(sp, Pt(i,i)); + i = -i; + } + draw(im, Rect(r.min.x+i, r.min.y+i, r.max.x-i, r.max.y-i), c[2], nil, sp); + p[0] = r.min; + p[1] = Pt(r.min.x, r.max.y); + p[2] = Pt(r.min.x+i, r.max.y-i); + p[3] = Pt(r.min.x+i, r.min.y+i); + p[4] = Pt(r.max.x-i, r.min.y+i); + p[5] = Pt(r.max.x, r.min.y); + fillpoly(im, p, 6, 0, c[0], sp); + p[0] = r.max; + p[1] = Pt(r.min.x, r.max.y); + p[2] = Pt(r.min.x+i, r.max.y-i); + p[3] = Pt(r.max.x-i, r.max.y-i); + p[4] = Pt(r.max.x-i, r.min.y+i); + p[5] = Pt(r.max.x, r.min.y); + fillpoly(im, p, 6, 0, c[1], sp); +} + +void +ellipse3d(Image *im, Point p, int rad, int i, Image **c, Point sp) +{ + fillarc(im, p, rad, rad, c[0], sp, 45, 180); + fillarc(im, p, rad, rad, c[1], sp, 45, -180); + fillellipse(im, p, rad-i, rad-i, c[2], sp); +} + +void +colarray(Image **c, Image *c0, Image *c1, Image *c2, int checked) +{ + if(checked){ + c[0] = c0; + c[1] = c1; + }else{ + c[0] = c1; + c[1] = c0; + } + c[2] = c2; +} + +static char *deffontpaths[] = { +#include "fonts.h" +}; + +static char *fontpaths[NumFnt]; +static Font *fonts[NumFnt]; + +void +initfontpaths(void) +{ + Biobufhdr *bp; + char buf[128]; + int i; + + /* we don't care if getenv(2) fails */ + snprint(buf, sizeof(buf)-1, "%s/lib/abaco.fonts", getenv("home")); + if((bp=Bopen(buf, OREAD)) == nil) + goto Default; + + for(i=0; i<NumFnt; i++) + if((fontpaths[i]=Brdstr(bp, '\n', 1)) == nil) + goto Error; + + Bterm(bp); + return; +Error: + fprint(2, "abaco: not enough fontpaths in '%s'\n", buf); + Bterm(bp); + for(i--; i>=0; i--) + free(fontpaths[i]); +Default: + for(i=0; i<NumFnt; i++) + fontpaths[i] = deffontpaths[i]; +} + +Font * +getfont(int i) +{ + if(fonts[i] == nil){ + fonts[i] = openfont(display, fontpaths[i]); + if(fonts[i] == nil) + error("can't open font file"); + } + return fonts[i]; +} + +typedef struct Color Color; + +struct Color { + int rgb; + Image *i; + Color *next; +}; + +enum { + NHASH = 19, +}; + +static Color *colortab[NHASH]; + +Image * +getcolor(int rgb) +{ + Color *c; + int h; + + if(rgb == 0xFFFFFF) + return display->white; + else if(rgb == 0x000000) + return display->black; + + h = rgb%NHASH; + for(c=colortab[h]; c!=nil; c=c->next) + if(c->rgb == rgb){ + flushimage(display, 0); /* BUG? */ + return c->i; + } + c = emalloc(sizeof(Color)); + c->i = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, (rgb<<8)|0xFF); + c->rgb = rgb; + c->next = colortab[h]; + colortab[h] = c; + + return c->i; +} + +int +plumbrunestr(Runestr *rs, char *attr) +{ + Plumbmsg *m; + int i; + + i = -1; + if(plumbsendfd >= 0){ + m = emalloc(sizeof(Plumbmsg)); + m->src = estrdup("abaco"); + m->dst = nil; + m->wdir = estrdup("/tmp"); + m->type = estrdup("text"); + if(attr) + m->attr = plumbunpackattr(attr); + else + m->attr = nil; + m->data = smprint("%.*S", rs->nr, rs->r); + m->ndata = -1; + i = plumbsend(plumbsendfd, m); + plumbfree(m); + } + return i; +} + +int +hexdigit(int v) +{ + if(0<=v && v<=9) + return '0' + v; + else + return 'A' + v - 10; +} + +static int +inclass(char c, Rune* cl) +{ + int n, ans, negate, i; + + n = runestrlen(cl); + if(n == 0) + return 0; + ans = 0; + negate = 0; + if(cl[0] == '^'){ + negate = 1; + cl++; + n--; + } + for(i=0; i<n; i++){ + if(cl[i]=='-' && i>0 && i<n-1){ + if(c>=cl[i - 1] && c<=cl[i+1]){ + ans = 1; + break; + } + i++; + } + else if(c == cl[i]){ + ans = 1; + break; + } + } + if(negate) + ans = !ans; + return ans; +} + +Rune* +ucvt(Rune* s) +{ + Rune* u; + char *t; + int i, c, n, j, len; + + t = smprint("%S", s); + n = strlen(t); + len = 0; + for(i=0; i<n; i++){ + c = t[i]; + if(inclass(c, L"- /$_@.!*'(),a-zA-Z0-9")) + len++; + else + len += 3; + } + u = runemalloc(len+1); + j = 0; + + for(i=0; i<n; i++){ + c = t[i]; + if(inclass(c, L"-/$_@.!*'(),a-zA-Z0-9")) + u[j++] = c; + else if(c == ' ') + u[j++] = '+'; + else { + u[j++] = '%'; + u[j++] = hexdigit((c >> 4)&15); + u[j++] = hexdigit(c&15); + } + } + u[j] = 0; + free(t); + return u; +} + +void +reverseimages(Iimage **head) +{ + Iimage *r, *c, *n; + + r = nil; + for(c=*head; c!=nil; c=n){ + n = c->nextimage; + c->nextimage = r; + r = c; + } + *head = r; +} + +char urlexpr[] = "^(https?|ftp|file|gopher|mailto|news|nntp|telnet|wais|" + "prospero)://([a-zA-Z0-9_@\\-]+([.:][a-zA-Z0-9_@\\-]+)*)"; +Reprog *urlprog; + +int +validurl(Rune *r) +{ + Resub rs[10]; + + if(urlprog == nil){ + urlprog = regcomp(urlexpr); + if(urlprog == nil) + error("regcomp"); + } + memset(rs, 0, sizeof(rs)); + if(rregexec(urlprog, r, rs, nelem(rs)) == 0) + return FALSE; + return TRUE; +} + +void +execproc(void *v) +{ + Channel *sync; + Exec *e; + int p[2], q[2]; + char *cmd; + + threadsetname("execproc"); + e = v; + p[0] = e->p[0]; + p[1] = e->p[1]; + q[0] = e->q[0]; + q[1] = e->q[1]; + cmd = e->cmd; + sync = e->sync; + rfork(RFFDG); + free(e); + dup(p[0], 0); + close(p[0]); + close(p[1]); + if(q[0]){ + dup(q[1], 1); + close(q[0]); + close(q[1]); + } + if(!procstderr) + close(2); + procexecl(sync, "/bin/rc", "rc", "-c", cmd, 0); + error("can't exec"); +} + +static void +writeproc(void *v) +{ + Channel *sync; + void **a; + char *s; + long np; + int fd, i, n; + + threadsetname("writeproc"); + a = v; + sync = a[0]; + fd = (int)a[1]; + s = a[2]; + np =(long)a[3]; + free(a); + + for(i=0; i<np; i+=n){ + n = np-i; + if(n > BUFSIZE) + n = BUFSIZE; + if(write(fd, s+i, n) != n) + break; + } + close(fd); + sendul(sync, i); +} + +struct { + char *mime; + char *tcs; +}tcstab[] = { + +#include "tcs.h" + + /* not generated by the script */ + "euc_jp", "jis", + "euc_kr", "euc-k", + "windows-874", "tis", + nil, nil, +}; + +enum { + Winstart = 127, + Winend = 159 +}; + +static int winchars[] = { + 8226, /* 8226 is a bullet */ + 8226, 8226, 8218, 402, 8222, 8230, 8224, 8225, + 710, 8240, 352, 8249, 338, 8226, 8226, 8226, + 8226, 8216, 8217, 8220, 8221, 8226, 8211, 8212, + 732, 8482, 353, 8250, 339, 8226, 8226, 376 +}; + +char * +tcs(char *cs, char *s, long *np) +{ + Channel *sync; + Exec *e; + Rune r; + long i, n; + void **a; + uchar *us; + char buf[BUFSIZE], cmd[50]; + char *t, *u; + int p[2], q[2]; + + + if(s==nil || *s=='\0' || *np==0){ + werrstr("tcs failed: no data"); + return s; + } + + if(cs == nil){ + werrstr("tcs failed: no charset"); + return s; + } + + if(cistrncmp(cs, "utf-8", 5)==0 || cistrncmp(cs, "utf8", 4)==0) + return s; + + for(i=0; tcstab[i].mime!=nil; i++) + if(cistrncmp(cs, tcstab[i].mime, strlen(tcstab[i].mime)) == 0) + break; + + if(tcstab[i].mime == nil){ + fprint(2, "abaco: charset: %s not supported\n", cs); + goto latin1; + } + if(cistrcmp(tcstab[i].tcs, "8859-1")==0 || cistrcmp(tcstab[i].tcs, "ascii")==0){ +latin1: + n = 0; + for(us=(uchar*)s; *us; us++) + n += runelen(*us); + n++; + t = emalloc(n); + for(us=(uchar*)s, u=t; *us; us++){ + if(*us>=Winstart && *us<=Winend) + *u++ = winchars[*us-Winstart]; + else{ + r = *us; + u += runetochar(u, &r); + } + } + *u = 0; + free(s); + return t; + } + + if(pipe(p)<0 || pipe(q)<0) + error("can't create pipe"); + + sync = chancreate(sizeof(ulong), 0); + if(sync == nil) + error("can't create channel"); + + snprint(cmd, sizeof cmd, "tcs -f %s", tcstab[i].tcs); + e = emalloc(sizeof(Exec)); + e->p[0] = p[0]; + e->p[1] = p[1]; + e->q[0] = q[0]; + e->q[1] = q[1]; + e->cmd = cmd; + e->sync = sync; + proccreate(execproc, e, STACK); + recvul(sync); + chanfree(sync); + close(p[0]); + close(q[1]); + + /* in case tcs fails */ + t = s; + sync = chancreate(sizeof(ulong), 0); + if(sync == nil) + error("can't create channel"); + + a = emalloc(4*sizeof(void *)); + a[0] = sync; + a[1] = (void *)p[1]; + a[2] = s; + a[3] = (void *)*np; + proccreate(writeproc, a, STACK); + + s = nil; + while((n = read(q[0], buf, sizeof(buf))) > 0){ + s = erealloc(s, i+n+1); + memmove(s+i, buf, n); + i += n; + s[i] = '\0'; + } + n = recvul(sync); + if(n != *np) + fprint(2, "tcs: did not write %ld; wrote %uld\n", *np, n); + + *np = i; + chanfree(sync); + close(q[0]); + + if(s == nil){ + fprint(2, "tcs failed: can't convert charset=%s to %s\n", cs, tcstab[i].tcs); + return t; + } + free(t); + + return s; +} + +static +int +isspace(char c) +{ + return c==' ' || c== '\t' || c=='\r' || c=='\n'; +} + +static +int +findctype(char *b, int l, char *keyword, char *s) +{ + char *p, *e; + int i; + + p = cistrstr(s, keyword); + if(!p) + return -1; + p += strlen(keyword); + while(*p && isspace(*p)) + p++; + if(*p != '=') + return -1; + p++; + while(*p && isspace(*p)) + p++; + if(!*p) + return -1; + if(*p == '"'){ + p++; + e = strchr(p, '"'); + if(!e) + return -1; + }else + for(e = p; *e < 127 && *e > ' ' ; e++) + ; + i = e-p; + if(i < 1) + return -1; + snprint(b, l, "%.*s", i, p); + return 0; +} + +static +int +finddocctype(char *b, int l, char *s) +{ + char *p, *e; + + p = cistrstr(s, "<meta"); + if(!p) + return -1; + p += 5; + e = strchr(s, '>'); + if(!e) + return -1; + snprint(b, l, "%.*s", (int)(e-p), p); + return 0; +} + +static +int +findxmltype(char *b, int l, char *s) +{ + char *p, *e; + + p = cistrstr(s, "<?xml "); + if(!p) + return -1; + + p += 6; + e = strstr(p, "?>"); + if(!e) + return -1; + snprint(b, l, "%.*s", (int)(e-p), p); + + return 0; +} + +/* + * servers can lie about lie about the charset, + * so we use the charset based on the priority. + */ +char * +convert(Runestr ctype, char *s, long *np) +{ + char t[25], buf[256]; + + *t = '\0'; + if(ctype.nr){ + snprint(buf, sizeof(buf), "%.*S", ctype.nr, ctype.r); + findctype(t, sizeof(t), "charset", buf); + } + if(findxmltype(buf, sizeof(buf), s)==0) + findctype(t, sizeof(t), "encoding", buf); + if(finddocctype(buf, sizeof(buf), s) == 0) + findctype(t, sizeof(t), "charset", buf); + + if(*t == '\0') + strcpy(t, charset); + return tcs(t, s, np); +} + +int +xtofchar(Rune *s, Font *f, long p) +{ + Rune *r; + int q; + + if(p == 0) + return 0; + + q = 0; + for(r=s; *r!=L'\0'; r++){ + p -= runestringnwidth(f, r, 1); + if(p < 0) + break; + q++; + } + return q; +} + +int +istextsel(Page *p, Rectangle r, int *q0, int *q1, Rune *s, Font *f) +{ + int topinr, botinr; + + *q0 = *q1 = 0; + topinr= ptinrect(p->top, r); + if(topinr || (r.min.y>p->top.y && r.max.y<p->bot.y)) + p->selecting = TRUE; + botinr = ptinrect(p->bot, r); + if(botinr || r.min.y>p->bot.y) + p->selecting = FALSE; + + if(topinr || botinr){ + if(topinr) + *q0 = xtofchar(s, f, p->top.x-r.min.x); + if(botinr) + *q1 = xtofchar(s, f, p->bot.x-r.min.x); + if(*q0!=0 || *q1!=0) + return TRUE; + } + return p->selecting; +} + +Point +getpt(Page *p, Point xy) +{ + xy.x = xy.x-p->r.min.x+p->pos.x; + xy.y = xy.y-p->r.min.y+p->pos.y; + + return xy; +} + +void +getimage(Cimage *ci, Rune *altr) +{ + Rectangle r; + Memimage *mi; + Image *i, *i2; + char buf[128]; + uchar *bits; + int nbits; + + mi = ci->mi; + if(mi == nil){ + snprint(buf, sizeof(buf), "[%S]", altr ? altr : L"IMG"); + r.min = Pt(0, 0); + r.max.x = 2*Space + stringwidth(font, buf); + r.max.y = 2*Space + font->height; + ci->i = eallocimage(display, r, GREY1, 1, DBlack); + r.min.x += Space; + r.min.y += Space; + string(ci->i, r.min, display->white, ZP, font, buf); + return; + } + nbits = bytesperline(mi->r, mi->depth)*Dy(mi->r); + bits = emalloc(nbits); + unloadmemimage(mi, mi->r, bits, nbits); +/* + /* get rid of alpha channel from transparent gif * / + + if(mi->depth == 16){ + for(y=1; y<nbits; y+=2) + bits[y>>1] = bits[y]; + } +*/ + i = eallocimage(display, mi->r, mi->chan, 0, DNofill); + loadimage(i, i->r, bits, nbits); + i2 = eallocimage(display, i->r, RGB24, 1, DNofill); + draw(i2, i2->r, display->black, nil, ZP); + draw(i2, i2->r, i, nil, i->r.min); + free(bits); + freememimage(mi); + freeimage(i); + ci->i = i2; + ci->mi = nil; +} + +static +void +fixtext1(Item **list) +{ + Itext *text, *ntext; + Item *it, *prev; + Rune *s, *s1, *s2; + int n; + + if(*list == nil) + return; + + prev = nil; + for(it=*list; it!=nil; it=prev->next){ + if(it->tag!=Itexttag || forceitem(it)) + goto Continue; + + text = (Itext *)it; + s = text->s; + while(*s && isspacerune(*s)) + s++; + if(!*s){ + if(prev == nil) + prev = *list = it->next; + else + prev->next = it->next; + + it->next = nil; + freeitems(it); + if(prev == nil) + return; + continue; + } + n = 0; + while(s[n] && !isspacerune(s[n])) + n++; + + if(!s[n]) + goto Continue; + + s1 = runemalloc(n+1); + s1 = runemove(s1, s, n); + s1[n] = L'\0'; + s += n; + + while(*s && isspacerune(*s)) + s++; + + if(*s){ + n = runestrlen(s); + s2 = runemalloc(n+1); + runemove(s2, s, n); + s2[n] = L'\0'; + ntext = emalloc(sizeof(Itext)); + ntext->s = s2; + ntext->ascent = text->ascent; + ntext->anchorid = text->anchorid; + ntext->state = text->state&~(IFbrk|IFbrksp|IFnobrk|IFcleft|IFcright); + ntext->tag = text->tag; + ntext->fnt = text->fnt; + ntext->fg = text->fg; + ntext->ul = text->ul; + ntext->next = (Item *)text->next; + text->next = (Item *)ntext; + } + free(text->s); + text->s = s1; + Continue: + prev = it; + } +} + +void +fixtext(Page *p) +{ + Tablecell *c; + Table *t; + + fixtext1(&p->items); + for(t=p->doc->tables; t!=nil; t=t->next) + for(c=t->cells; c!=nil; c=c->next) + fixtext1(&c->content); +} + +typedef struct Refresh Refresh; + +struct Refresh +{ + Page *p; + Refresh *next; +}; + +static Refresh *refreshs = nil; +static QLock refreshlock; + +void +addrefresh(Page *p, char *fmt, ...) +{ + Refresh *r; + Rune *s; + va_list arg; + + if(p->aborting) + return; + + va_start(arg, fmt); + s = runevsmprint(fmt, arg); + va_end(arg); + if(s == nil) + error("runevsmprint failed"); + + if(p->status){ + free(p->status); + p->status = nil; + } + p->status = s; + qlock(&refreshlock); + for(r=refreshs; r!=nil; r=r->next) + if(r->p == p) + goto Return; + + incref(p->w); /* flushrefresh will decref */ + r = emalloc(sizeof(Refresh)); + r->p = p; + r->next = refreshs; + refreshs = r; + + Return: + nbsendp(crefresh, nil); + qunlock(&refreshlock); +} + +/* called while row is locked */ +void +flushrefresh(void) +{ + Refresh *r, *next; + Page *p; + + qlock(&refreshlock); + for(r=refreshs; r!=nil; r=next){ + p = r->p; + if(p->changed==TRUE && p->aborting==FALSE){ + p->changed = FALSE; + if(p->parent==nil || p->loading==FALSE) + pagerender(p); + if(!p->refresh.t) + pagesetrefresh(p); + } + if(p->status){ + winsetstatus(p->w, p->status); + free(p->status); + p->status = nil; + } + winseturl(p->w); + winsettag(p->w); + decref(p->w); + next = r->next; + free(r); + } + refreshs = nil; + qunlock(&refreshlock); +} + +void +savemouse(Window *w) +{ + prevmouse = mouse->xy; + mousew = w; +} + +void +restoremouse(Window *w) +{ + if(mousew!=nil && mousew==w) + moveto(mousectl, prevmouse); + mousew = nil; +} + +void +clearmouse() +{ + mousew = nil; +} + +/* + * Heuristic city. + */ +Window* +makenewwindow(Page *p) +{ + Column *c; + Window *w, *bigw, *emptyw; + Page *emptyp; + int i, y, el; + + if(activecol) + c = activecol; + else if(selpage && selpage->col) + c = selpage->col; + else if(p && p->col) + c = p->col; + else{ + if(row.ncol==0 && rowadd(&row, nil, -1)==nil) + error("can't make column"); + c = row.col[row.ncol-1]; + } + activecol = c; + if(p==nil || p->w==nil || c->nw==0) + return coladd(c, nil, nil, -1); + + /* find biggest window and biggest blank spot */ + emptyw = c->w[0]; + bigw = emptyw; + for(i=1; i<c->nw; i++){ + w = c->w[i]; + /* use >= to choose one near bottom of screen */ + if(Dy(w->page.all) >= Dy(bigw->page.all)) + bigw = w; + if(w->page.lay==nil && Dy(w->page.all) >= Dy(emptyw->page.all)) + emptyw = w; + } + emptyp = &emptyw->page; + el = Dy(emptyp->all); + /* if empty space is big, use it */ + if(el>15 || (el>3 && el>(Dy(bigw->page.all)-1)/2)) + y = emptyp->all.max.y; + else{ + /* if this window is in column and isn't much smaller, split it */ + if(p->col==c && Dy(p->w->r)>2*Dy(bigw->r)/3) + bigw = p->w; + y = (bigw->r.min.y + bigw->r.max.y)/2; + } + w = coladd(c, nil, nil, y); + colgrow(w->col, w, 1); + return w; +} diff --git a/sys/src/cmd/abaco/wind.c b/sys/src/cmd/abaco/wind.c new file mode 100755 index 000000000..fd108e75f --- /dev/null +++ b/sys/src/cmd/abaco/wind.c @@ -0,0 +1,383 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <memdraw.h> +#include <thread.h> +#include <cursor.h> +#include <mouse.h> +#include <keyboard.h> +#include <frame.h> +#include <plumb.h> +#include <html.h> +#include "dat.h" +#include "fns.h" + +void +wininit(Window *w, Window *, Rectangle r) +{ + Rectangle r1, br; + + incref(w); + w->r = r; + w->tag.w = w; + w->url.w = w; + w->page.w = w; + w->status.w = w; + r1 = r; + r1.max.y = r1.min.y + font->height; + textinit(&w->tag, screen, r1, font, tagcols); + w->tag.what = Tag; + r1.min.y = r1.max.y++; + draw(screen, r1, tagcols[BORD], nil, ZP); + br.min = w->tag.scrollr.min; + br.max.x = br.min.x + Dx(button->r); + br.max.y = br.min.y + Dy(button->r); + draw(screen, br, button, nil, button->r.min); + r1.min.y = r1.max.y; + r1.max.y += font->height; + textinit(&w->url, screen, r1, font, tagcols); + w->url. + w->url.what = Urltag; + r1.min.y = r1.max.y++; + draw(screen, r1, tagcols[BORD], nil, ZP); + r1.min.y = r1.max.y; + r1.max.y = r.max.y - font->height - 1; + w->page.all = r1; + w->page.b = screen; + draw(screen, r1, display->white, nil, ZP); + r1.min.y = r1.max.y++; + draw(screen, r1, tagcols[BORD], nil, ZP); + r1.min.y = r1.max.y; + r1.max.y += font->height; + textinit(&w->status, screen, r1, font, tagcols); + w->status.what = Statustag; +} + +int +winresize(Window *w, Rectangle r, int safe) +{ + Rectangle r1, br; + + w->r = r; + r1 = r; + r1.max.y = r1.min.y + font->height; + if(!safe || !eqrect(w->tag.r, r1)){ + textresize(&w->tag, screen, r1); + br.min = w->tag.scrollr.min; + br.max.x = r1.min.x + Dx(button->r); + br.max.y = r1.min.y + Dy(button->r); + draw(screen, br, button, nil, button->r.min); + r1.min.y = r1.max.y++; + draw(screen, r1, tagcols[BORD], nil, ZP); + r1.min.y = r1.max.y; + r1.max.y += font->height; + textresize(&w->url, screen, r1); + r1.min.y = r1.max.y++; + draw(screen, r1, tagcols[BORD], nil, ZP); + } + r1.min.y = r1.max.y; + r1.max.y = r.max.y - font->height - 1; + w->page.b = screen; + if(!safe || !eqrect(w->page.all, r1)){ + if(Dy(r1) <= 0){ + w->page.all = ZR; + pagerender(&w->page); + w->r = r; + w->r.max.y = r1.min.y; + return w->r.max.y; + } + draw(screen, r1, display->white, nil, ZP); + w->page.all = r1; + pagerender(&w->page); + r1.min.y = r1.max.y++; + draw(screen, r1, tagcols[BORD], nil, ZP); + r1.min.y = r1.max.y; + r1.max.y = r.max.y; + textresize(&w->status, screen, r1); + } + return w->r.max.y; +} + +void +winclose1(Window *w) +{ + int i; + + if(decref(w) == 0){ + textclose(&w->tag); + textclose(&w->url); + textclose(&w->status); + if(w->history.url){ + for(i=0; i<w->history.nurl; i++) + urlfree(w->history.url[i]); + free(w->history.url); + } + free(w); + } +} + +void +winclose(Window *w) +{ + pageclose(&w->page); + winclose1(w); +} + +void +winlock(Window *w, int owner) +{ + incref(w); + qlock(w); + w->owner = owner; +} + +void +winunlock(Window *w) +{ + w->owner = 0; + qunlock(w); + winclose1(w); +} + +void +winsettag1(Window *w) +{ + int i, j, k, n, bar; + Rune *new, *r; + Image *b; + uint q0, q1; + Rectangle br; + Runestr old; + + memset(&old, 0, sizeof(Runestr)); + copyrunestr(&old, &w->tag.rs); + for(i=0; i<w->tag.rs.nr; i++) + if(old.r[i]==' ' || old.r[i]=='\t') + break; + + if(runestreq(old, w->page.title) == FALSE){ + textdelete(&w->tag, 0, i); + textinsert(&w->tag, 0, w->page.title.r, w->page.title.nr); + closerunestr(&old); + copyrunestr(&old, &w->tag.rs); + } + new = runemalloc(w->page.title.nr+100); + i = 0; + runemove(new+i, L" Del Snarf", 10); + i += 10; + if(w->history.nurl){ + if(w->history.cid > 0){ + runemove(new+i, L" Back", 5); + i += 5; + } + if(w->history.cid < w->history.nurl-1){ + runemove(new+i, L" Next", 5); + i += 5; + } + if(w->page.loading){ + runemove(new+i, L" Stop", 5); + i += 5; + } + } + runemove(new+i, L" Get", 4); + i += 4; + runemove(new+i, L" | ", 3); + i += 3; + runemove(new+i, w->page.title.r, w->page.title.nr); + i += w->page.title.nr; +/* + r = runestrchr(old.r, '|'); + r = nil; + if(r) + k = r-old.r+1; + else{ + k = w->tag.rs.nr; + if(w->page.url){ + runemove(new+i, L" Look ", 6); + i += 6; + } + } +*/ + k = w->tag.rs.nr; + if(runeeq(new, i, old.r, k) == FALSE){ + n = k; + if(n > i) + n = i; + for(j=0; j<n; j++) + if(old.r[j] != new[j]) + break; + q0 = w->tag.q0; + q1 = w->tag.q1; + textdelete(&w->tag, j, k); + textinsert(&w->tag, j, new+j, i-j); + /* try to preserve user selection */ + r = runestrchr(old.r, '|'); + if(r){ + bar = r-old.r; + if(q0 > bar){ + bar = (runestrchr(new, '|')-new)-bar; + w->tag.q0 = q0+bar; + w->tag.q1 = q1+bar; + } + } + } + closerunestr(&old); + free(new); + n = w->tag.rs.nr; + if(w->tag.q0 > n) + w->tag.q0 = n; + if(w->tag.q1 > n) + w->tag.q1 = n; + textsetselect(&w->tag, w->tag.q0, w->tag.q1); + b = button; + br.min = w->tag.scrollr.min; + br.max.x = br.min.x + Dx(b->r); + br.max.y = br.min.y + Dy(b->r); + draw(screen, br, b, nil, b->r.min); +} + + +void +winsettag(Window *w) +{ + if(w->col && w->col->safe) + winsettag1(w); +} + +void +winseturl(Window *w) +{ + if(w->page.url && runestreq(w->url.rs, w->page.url->act)==FALSE) + textset(&w->url, w->page.url->act.r, w->page.url->act.nr); +} + +void +winsetstatus(Window *w, Rune *r) +{ + if(w->col && w->col->safe) + textset(&w->status, r, runestrlen(r)); +} + +void +winaddhist(Window *w, Url *u) +{ + Url **url; + int cid, n, i; + + url = w->history.url; + n = w->history.nurl; + cid = w->history.cid; + if(cid < n-1){ + for(i=cid+1; i<n; i++) + urlfree(url[i]); + n = cid+1; + } + w->history.url = erealloc(w->history.url, ++n*sizeof(Url *)); + w->history.url[n-1] = u; + w->history.cid = u->id = n-1; + w->history.nurl = n; + incref(u); +} + +void +wingohist(Window *w, int isnext) +{ + Page *p; + int n, id; + + n = w->history.nurl; + p = &w->page; + if(!p->url) + return; + + id = p->url->id; + + if(isnext) + id++; + else + id--; + + if(n==0 || id<0 || id==n) + return; + + incref(w->history.url[id]); + pageload(p, w->history.url[id], FALSE); + w->history.cid = id; +} + +Text * +wintext(Window *w, Point xy) +{ + w->inpage = FALSE; + if(ptinrect(xy, w->tag.all)) + return &w->tag; + if(ptinrect(xy, w->url.all)) + return &w->url; + if(ptinrect(xy, w->status.all)) + return &w->status; + if(ptinrect(xy, w->page.all)) + w->inpage = TRUE; + + return nil; +} + +Text * +wintype(Window *w, Point xy, Rune r) +{ + Text *t; + + t = wintext(w, xy); + if(t && !ptinrect(xy, t->scrollr)) + return t; + if(w->inpage) + pagetype(&w->page, r, xy); + + return nil; +} + +Text * +winmouse(Window *w, Point xy, int but) +{ + Text *t; + + t = wintext(w, xy); + if(t) + return t; + if(w->inpage) + pagemouse(&w->page, xy, but); + + return nil; +} + +void +winmousebut(Window *w) +{ + moveto(mousectl, divpt(addpt(w->tag.scrollr.min, w->tag.scrollr.max), 2)); +} + +int +winclean(Window *, int) +{ + return TRUE; +} + +void +windebug(Window *w) +{ + Page *p; + int i; + + p = &w->page; + fprint(2, "title:\t%S\n", p->title.r); + fprint(2, "url:\t%.*S\n",w->url.rs.nr, w->url.rs.r); + fprint(2, "aborting:\t%s\n", istrue(p->aborting)); + fprint(2, "changed:\t%s\n", istrue(p->changed)); + fprint(2, "loading:\t%s\n", istrue(p->loading)); + fprint(2, "status:\t%S\n", p->status); + fprint(2, "HISTORY:\n"); + for(i=0; i<w->history.nurl; i++) + fprint(2, "url[%d]: %S\n", i, w->history.url[i]->act.r); + + if(p->kidinfo) + fprint(2, "name: %S\n", p->kidinfo->name); +} |