— y2sunlight 2021-12-02
マクロを以下フォルダに設置する。
{ユーザフォルダ}\AppData\Roaming\sakura
以上でショートカットキーでマクロを実行することが出来るようになります。 ショートカットキー以外で実行する時は、[ツール][名前を指定してマクロ実行]を押し、マクロを選択します。
// -----------------------------------------------
// 1行の最大文字数を指定して改行を入れる
// ファイル名に.chopを付けて保存する(改行コードは入力する)
// 0x0Dが含まれる時は確認メッセージ表示
// [はい]:0x0D を 0x0F に変換する
// [いいえ]: 何もしない
// ※ 0x0D:'-' 0x0C:'+' 0x0F:' '
// -----------------------------------------------
main();
function main() {
// 0x0d(\r)検索
Editor.SearchNext('\\r', 36);
if(Editor.GetSelectedString()){
if(Editor.YesNoBox('0x0Dが含まれます。0x0Fに変換して続けますか?') == 6) {
// はい
// 変換
Editor.ReplaceAll('\\r','\\x0F',4);
// 再描画
Editor.ReDraw(0);
} else {
// いいえ
return;
}
}
// 最大文字数取得
var maxLen = parseInt(Editor.InputBox('1行の最大文字数を入力してください', 100));
if(isNaN(maxLen)) return;
// 元の折り返し桁数と折り返し桁数設定
var oldWrapColm = Editor.ChangeWrapColm(maxLen);
// 全て選択
Editor.SelectAll();
// 折り返し位置に改行をつけてコピー
Editor.CopyAddCRLF(0);
// 折り返し桁数を元に戻す
Editor.ChangeWrapColm(oldWrapColm);
// ペースト
Editor.Paste(0);
// 改行コード
var code = parseInt(Editor.InputBox('[0]変換なし | [1]CRLF | [2]LF | [3]CR を入力して下さい。', 0));
if(isNaN(code)){
Editor.WarnMsg('改行コードの入力が無いので、ファイルを保存しません。');
return;
}
// 名前を指定して保存
var fileName = Editor.GetFilename() + '.chop';
Editor.FileSaveAs(fileName, 0, code);
}
// -----------------------------------------------
// 0x00(NUL)~0x1f(US)を0x20(SPC)に変更する
// 0x0a(LF),0x0d(CR)除く
// -----------------------------------------------
var isSelected = Editor.IsTextSelected();
if(isSelected == 0){
// -----------------------
// 非選択状態(0)
// -----------------------
// 全て選択
Editor.SelectAll();
} else {
// -----------------------
// 選択中(1),矩形選択中(2)
// -----------------------
}
// 置換
// 第3引数 正規表現(0x004=4),選択範囲(0x080=128)
Editor.ReplaceAll('[\\x00\\x00-\\x1f\\x00&&[^\\x0a\\x00\\x0d\\x00]]', '\\x20', 132);
Editor.ReDraw(0); // 再描画
// -----------------------------------------------
// コードの置換
// 置換前のコードと置換後のコードはコロン(:)で区切る
// 複数置換の場合はカンマ(,)で区切る
// 0x00と0x01を0x20に置換する場合の入力例 00:20,01:20
// -----------------------------------------------
main();
function main() {
var txt = Editor.InputBox('制御コード(16進2桁)を入力して下さい。');
if(!txt) return;
var arr = txt.split(',');
for(var key in arr){
var hexArr = arr[key].split(':');
if(hexArr.length == 2) {
var before = '\\x' + hexArr[0] + '\\x00';
var after = '\\x' + hexArr[1];
Editor.ReplaceAll(before,after,4);
}
}
// 再描画
Editor.ReDraw(0);
}
// -----------------------------------------------
// 固定長の〇文字目から?文字でソートする
// -----------------------------------------------
main();
function main() {
// 〇文字目から
var startPos = parseInt(Editor.InputBox('何文字目から?', 1));
if(isNaN(startPos)) return;
// ?文字
var maxLen = parseInt(Editor.InputBox('何文字でソート', 1));
if(isNaN(maxLen)) return;
// カーソル移動
Editor.MoveCursor(1, startPos, 0);
// 矩形範囲選択開始
Editor.BeginBoxSelect(0);
// 範囲選択
for(var col = 1; col < maxLen+1; col++) {
Editor.Right_Sel(0);
}
var rowCnt = Editor.GetLineCount(0);
for(var row = 1; row < rowCnt; row++) {
Editor.Down_Sel(0);
}
// 選択行の昇順ソート
Editor.SortAsc(0);
}
// -----------------------------------------------
// 複数キーのソート
// [入力方法]{開始位置}:{文字長},{開始位置}:{文字長},asc desc
// -----------------------------------------------
main();
function main() {
// キー
var input = Editor.InputBox('{開始位置}:{文字長},{開始位置}:{文字長},asc desc');
if(!input) return;
var keys = [];
var inputWords = input.split(',');
var orderWords = inputWords[inputWords.length-1].split(' ');
if(inputWords.length - 1 == orderWords.length) {
for(var i=0; i<inputWords.length-1; i++){
var words = inputWords[i].split(':');
if(words.length == 2){
var pos = 0;
var len = 0;
var order = '';
pos = parseInt(words[0]);
len = parseInt(words[1]);
order = orderWords[i];
var obj = new Key(pos, len, order);
keys.push(obj);
}
}
} else {
Editor.ErrorMsg('キーの数とソート順の数があっていません。');
return;
}
// 行
var items = [];
for(var i=1; i<=Editor.GetLineCount(0); i++){
var line = GetLineStr(i);
var itemKeys = [];
for(var j=0; j<keys.length; j++){
itemKeys[j] = line.substr(keys[j].pos-1, keys[j].len);
}
var objItem = new Item(i, itemKeys);
items.push(objItem);
}
// ソート
items.sort(function(a, b) {
for(var i=0; i<a.key.length; i++){
if(a.key[i] !== b.key[i]) {
if (a.key[i] < b.key[i]) {
return (keys[i].order.toUpperCase() == 'DESC') ? 1 : -1;
}
if (a.key[i] > b.key[i]) {
return (keys[i].order.toUpperCase() == 'DESC') ? -1 : 1;
}
}
}
return 0;
});
var sortTxt = '';
for(var i=0; i<items.length; i++){
sortTxt += GetLineStr(items[i].lineNo);
}
// 上書き
Editor.SelectAll();
Editor.InsText(sortTxt);
}
function Key(pos, len, order) {
this.pos = pos;
this.len = len;
this.order = order;
}
function Item(lineNo, key) {
this.lineNo = lineNo;
this.key = key;
}
// -----------------------------------------------
// バイナリーを16進ASCIIに変換
// -----------------------------------------------
main();
function main() {
var isSelected = Editor.IsTextSelected();
if(isSelected == 0) {
Editor.MessageBox('範囲を選択して下さい。');
return;
}
var colFrom = GetSelectColumnFrom(); // 選択開始桁
var colTo = GetSelectColumnTo(); // 選択終了桁
var lineFrom = GetSelectLineFrom(); // 選択開始行
var lineTo = GetSelectLineTo(); // 選択終了行
// 選択範囲の文字列取得
var selectText = GetSelectedString(0);
// 最後の改行削除
selectText = selectText.replace(/\r\n$/, '');
// 改行で分割
var selectArr = selectText.split('\r\n');
for(var i=0; i<selectArr.length; i++){
var changeText = '';
for(var j=0; j<selectArr[i].length; j++) {
changeText += ('00' + selectArr[i].charCodeAt(j).toString(16)).slice(-2);
}
// 範囲選択
Editor.MoveCursor(lineFrom + i, colFrom, 0);
for(var col=colFrom; col < colTo; col++) {
Editor.Right_Sel(0);
}
// 上書き
Editor.InsText(changeText);
}
}
// -----------------------------------------------
// 16進ASCIIをバイナリーに変換
// -----------------------------------------------
main();
function main()
{
var isSelected = Editor.IsTextSelected();
if(isSelected == 0) {
Editor.MessageBox('範囲を選択して下さい。');
return;
}
var colFrom = GetSelectColumnFrom(); // 選択開始桁
var colTo = GetSelectColumnTo(); // 選択終了桁
var lineFrom = GetSelectLineFrom(); // 選択開始行
var lineTo = GetSelectLineTo(); // 選択終了行
// 選択範囲の文字列取得
var selectText = GetSelectedString(0);
// 最後の改行削除
selectText = selectText.replace(/\r\n$/, '');
// 改行で分割
var selectArr = selectText.split('\r\n');
loop: for(var i=0; i<selectArr.length; i++){
// 2文字ずつに分ける
var hexArr = selectArr[i].match(/.{2}/g);
if(!hexArr) continue;
var changeText = '';
for (var j=0; j<hexArr.length; j++) {
if(hexArr[j].toUpperCase() == '0A' || hexArr[j].toLowerCase() == '0D') {
Editor.WarnMsg('「0A」または「0D」が入っています');
break loop;
}
changeText += String.fromCharCode(parseInt(hexArr[j], 16));
}
// 範囲選択
Editor.MoveCursor(lineFrom + i, colFrom, 0);
for(var col=colFrom; col < colTo; col++) {
Editor.Right_Sel(0);
}
// 上書き
Editor.InsText(changeText);
}
}
// -----------------------------------------------
// ルーラー追加
// -----------------------------------------------
// 1行目の文字列取得(改行なし)
var txt = Editor.GetLineStr(1).replace(/\r\n/,'');
// カーソル移動
Editor.MoveCursor(1, 1, 0);
// 改行追加
Editor.Char(13);
Editor.Char(13);
var rowOne = '';
var rowTwo = '';
for(var j = 1; j <= txt.length; j++) {
rowTwo += String(j % 10);
if((j % 10)==0){
rowOne += (' ' + String(j/10)).slice(-10);
}
}
// 1行目
Editor.MoveCursor(1, 1, 0);
Editor.InsText(rowOne);
// 2行目
Editor.MoveCursor(2, 1, 0);
Editor.InsText(rowTwo);
// -----------------------------------------------
// パック10進をゾーン10進に変換
// -----------------------------------------------
main();
function main() {
var isSelected = Editor.IsTextSelected();
if(isSelected == 0) {
Editor.MessageBox('範囲を選択して下さい。');
return;
}
var colFrom = GetSelectColumnFrom(); // 選択開始桁
var colTo = GetSelectColumnTo(); // 選択終了桁
var lineFrom = GetSelectLineFrom(); // 選択開始行
var lineTo = GetSelectLineTo(); // 選択終了行
// 選択範囲の文字列取得
var selectText = GetSelectedString(0);
// 最後の改行削除
selectText = selectText.replace(/\r\n$/, '');
// 改行で分割
var selectArr = selectText.split('\r\n');
Editor.CancelMode();
for(var i=0; i<selectArr.length; i++){
var changeText = '';
for(var j=0; j<selectArr[i].length; j++) {
changeText += ('00' + selectArr[i].charCodeAt(j).toString(16)).slice(-2);
}
var change = '';
for(var k=0; k<changeText.length; k++){
var char = changeText.charAt(k).toUpperCase();
if(char == 'D'){
change = '-' + change;
} else if(char == 'C') {
change = '+' + change;
} else if(char == 'A' || char == 'B' || char == 'E' || char == 'F') {
change = ' ' + change;
} else {
change += char;
}
}
// 範囲選択
Editor.MoveCursor(lineFrom + i, colFrom, 0);
for(var col=colFrom; col < colTo; col++) {
Editor.Right_Sel(0);
}
// 上書き
Editor.InsText(change);
}
}
// -----------------------------------------------
// 選択範囲のコメント行を抽出
// コメント行とは7桁目に「*」または「/」をもつ行
// -----------------------------------------------
main()
function main(){
var isSelected = Editor.IsTextSelected();
if(isSelected == 1) {
// 行選択しているか
var txt = Editor.GetSelectedString(0);
var lines = txt.match(/^\d{6}[\s\S]*(\n|\r\n|\r)$/);
if(!lines){
Editor.MessageBox('行を選択して下さい');
return;
}
}else{
Editor.MessageBox('行を選択して下さい');
return;
}
// 選択範囲の文字列取得
var allText = GetSelectedString(0);
var arr = allText.match(/\d{6}(\*|\/).*(\n|\r\n|\r)/g);
if(arr){
// 通常コピー
Editor.SetClipboard(0, arr.join(''));
Editor.MessageBox('クリップボードにコピーしました');
} else {
// コメント無し
Editor.MessageBox('コメント行はありません');
}
}
// -----------------------------------------------
// 選択範囲のコメント行を除く
// コメント行とは7桁目に「*」または「/」をもつ行
// -----------------------------------------------
main()
function main(){
var isSelected = Editor.IsTextSelected();
if(isSelected == 1) {
// 行選択しているか
var txt = Editor.GetSelectedString(0);
var lines = txt.match(/^\d{6}[\s\S]*(\n|\r\n|\r)$/);
if(!lines){
Editor.MessageBox('行を選択して下さい');
return;
}
}else{
Editor.MessageBox('行を選択して下さい');
return;
}
// 選択範囲の文字列取得
var allText = GetSelectedString(0);
var arr = allText.match(/\d{6}(?!\*|\/).*(\n|\r\n|\r)/g);
if(arr){
// 通常コピー
Editor.SetClipboard(0, arr.join(''));
Editor.MessageBox('クリップボードにコピーしました');
}
}
// -----------------------------------------------
// pic句のバイト数を集計
// PICTURE文字列がN, CR, DBはサポートしていません。
// REDEFINES と OCCURS は未サポートです。
// ・出現した時は警告を出します。
// ・出てきた数を数えて警告に表示します。
// -----------------------------------------------
var fileName = null;
var occursNumber = 0;
var redefinesNumber = 0;
main();
function main() {
var isSelected = Editor.IsTextSelected();
if(isSelected == 1) {
// 行選択しているか
var txt = Editor.GetSelectedString(0);
var lines = txt.match(/^\d{6}[\s\S]*(\n|\r\n|\r)$/);
if(!lines){
Editor.MessageBox('行を選択して下さい');
return;
}
}else{
Editor.MessageBox('行を選択して下さい');
return;
}
var lineFrom = Editor.GetSelectLineFrom(); // 選択開始行
var lineTo = Editor.GetSelectLineTo(); // 選択終了行
var picArr = [];
var note = '';
for(var i=lineFrom; i<lineTo; i++){
// 行取得
var txt = Editor.GetLineStr(i);
// コメント行
var arr = txt.match(/\d{6}(\*|\/)/);
if(arr){
note = getNote(txt);
continue;
}
// PicObj取得
var pic = getPic(txt, note);
if(!pic) continue;
// バイト数計算
var byte = getByte(pic.type, pic.option);
if(byte == 0) {
return;
}
pic.byte = byte;
// 位置計算
if(picArr.length > 0) {
pic.position = getPosition(picArr[picArr.length - 1].byte, picArr[picArr.length - 1].position);
} else {
pic.position = 1;
}
// 配列に入れる
picArr.push(pic);
note = '';
}
// 出力
output(picArr);
// REDEFINEとOCCURSの数
if(occursNumber > 0 || redefinesNumber > 0) {
var msg = '';
if(occursNumber > 0) {
msg += 'OCCURS が ' + occursNumber + ' 箇所あります。';
}
if(redefinesNumber > 0) {
if(msg) msg += '\n';
msg += 'REDEFINES が ' + redefinesNumber + ' 箇所あります。';
}
Editor.MessageBox(msg);
}
}
function Pic(no, name, type, option, byte, position, note) {
this.no = no;
this.name = name;
this.type = type;
this.option = option;
this.byte = byte;
this.position = position;
this.note = note;
}
/**
* コメント行の備考を取得
*/
function getNote(line) {
var note = '';
var words = line.split(';');
if(words.length == 2) {
var wds = words[1].split(/\s/);
if(wds.length == 2) {
note = wds[1];
}
}
return note;
}
/**
* 1行をPicにいれて返す
*/
function getPic(line, note) {
var pic = null;
// インラインコメント削除
var commentIndex = line.indexOf(';');
if(commentIndex > 0) line = line.substring(0, commentIndex);
commentIndex = line.indexOf('*>');
if(commentIndex > 0) line = line.substring(0, commentIndex);
var found = line.match(/\s\d{2}\s.+/);
if(found){
// スペースで区切る
var words = found[0].split(/\s/);
// 最後のピリオド削除
words[words.length-1] = words[words.length-1].replace(/.$/, '');
// 最初の変数名をファイル名とする
if(!fileName) {
if(words && words.length >= 1) fileName = words[1];
}
// PICは何番目か取得
var picPos = 0;
for(var index in words){
if(words[index] == 'PIC' || words[index] == 'PICTURE'){
picPos = Number(index);
}
}
// オプション(レベル、変数名以外)
var option = [];
var j = 0;
for(var i=2; i<words.length; i++){
option[j++] = words[i];
if(words[i].toUpperCase() == 'REDEFINES'){
redefinesNumber++;
}
if(words[i].toUpperCase() == 'OCCURS'){
occursNumber++;
}
}
if(picPos > 1) {
pic = new Pic(words[0], words[1], words[picPos+1], option, 0, 0, note);
}
}
return pic;
}
/**
* 型からバイト数計算
*/
function getByte(type, option){
var byte = 0;
var state = 0; // 状態
var beforeType = ''; // 型
var byteStr = ''; // バイト数(文字列)
for(var i=0; i<type.length; i++){
// 1文字取得
var char = type.charAt(i);
switch(char){
case 'A':
case 'X':
case '/':
case 'Z':
case ',':
case '.':
case '*':
case '+':
case '-':
beforeType = char;
byte += 1;
break;
case 'N':
Editor.WarnMsg('PIC文字[N]はサポートしていません。');
return 0;
case 'D':
case 'C':
beforeType = char;
break;
case 'R':
if(beforeType == 'C'){
Editor.WarnMsg('PIC文字[CR]はサポートしていません。');
return 0;
}
break;
case 'B':
if(beforeType == 'D'){
Editor.WarnMsg('PIC文字[DB]はサポートしていません。');
return 0;
} else {
beforeType = char;
byte += 1;
}
break;
case '0':
case '9':
if(state ==1){
byteStr += char;
} else {
beforeType = char;
byte += 1;
}
break;
case '(':
if(beforeType){
state = 1;
}
break;
case ')':
if(state == 1){
byte += Number(byteStr) - 1;
state = 0;
beforeType = '';
byteStr = '';
}
break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
if(state == 1) {
byteStr += char;
}
break;
}
}
// PACKED-DECIMAL or COMP-3 or COMPUTATIONAL-3
if(isOptions(option, 'PACKED-DECIMAL') || isOptions(option, 'COMP-3') || isOptions(option, 'COMPUTATIONAL-3')) {
byte = Math.floor(byte / 2 + 1);
}
// BINARY or COMP or COMPUTATIONAL
if(isOptions(option, 'BINARY') || isOptions(option, 'COMP') || isOptions(option, 'COMPUTATIONAL')) {
if(1<=byte && byte<=4) {
byte = 2;
} else if(5<=byte && byte<=9) {
byte = 4;
} else if(10<=byte && byte<=18) {
byte = 8;
}
}
return byte;
}
/**
* 位置計算
* @param beforeByte 1つ前のバイト数
* @param beforePos 1つ前の位置
*/
function getPosition(beforeByte, beforePos){
return beforePos + beforeByte;
}
/**
* オプション中に指定文字列があるか
* @param array option
* @param string str
* @return true/false
*/
function isOptions(option, str) {
var flg = false;
for(var index in option) {
if(option[index].toUpperCase() == str){
flg = true;
break;
}
}
return flg;
}
/**
* 出力
*/
function output(picArr){
// ファイルに保存かクリップボードに保存かキャンセル
var result = Editor.MessageBox('ファイル出力の場合は[はい]をクリップボードの場合は[いいえ]を押して下さい。',3);
if(result == 6){
// 全選択
Editor.SelectAll();
// 上書き
Editor.InsText(changeText(picArr));
// 名前を指定して保存(開いているファイルのパス)
Editor.FileSaveAs(fileName);
}else if(result == 7){
// クリップボードにコピー
Editor.SetClipboard(0, changeText(picArr));
Editor.MessageBox('クリップボードにコピーしました');
}
}
/**
* オプション
*/
function getOption(option) {
for(var index in option) {
if(option[index]=='PACKED-DECIMAL' || option[index]=='COMP-3' || option[index]=='COMPUTATIONAL-3'
|| option[index]=='BINARY' || option[index]=='COMP' || option[index]=='COMPUTATIONAL'){
return option[index];
}
}
return '';
}
/**
* Pic配列を文字列に変換
*/
function changeText(picArr) {
var txt = "";
for(var i=0; i<picArr.length; i++){
txt += picArr[i].no
txt += '\t';
txt += picArr[i].name;
txt += '\t';
txt += picArr[i].type;
var option = getOption(picArr[i].option)
if(option){
txt += ' ' + getOption(picArr[i].option);
}
txt += '\t';
txt += picArr[i].byte;
txt += '\t';
txt += picArr[i].position;
txt += '\t';
txt += picArr[i].note;
txt += '\r\n';
}
return txt;
}