168 lines
3.6 KiB
JavaScript
168 lines
3.6 KiB
JavaScript
|
/*
|
||
|
* Stairs
|
||
|
* Copyright 2017 (c) Mark van Renswoude
|
||
|
*
|
||
|
* https://git.x2software.net/pub/Stairs
|
||
|
*/
|
||
|
'use strict';
|
||
|
|
||
|
// Borrowed heavily from gulp-concat:
|
||
|
// https://github.com/contra/gulp-concat/
|
||
|
//
|
||
|
// It's very much hardcoded for the ESP8266 Arduino at the moment,
|
||
|
// but feel free to hack away at it if you need it for other purposes!
|
||
|
var through = require('through2');
|
||
|
var path = require('path');
|
||
|
var File = require('vinyl');
|
||
|
var _ = require('lodash');
|
||
|
var Readable = require('stream').Readable;
|
||
|
|
||
|
|
||
|
function escapeContent(content, lineLength)
|
||
|
{
|
||
|
var lineRegexp = new RegExp('(.{1,' + (lineLength - 1) + '}[^\\\\])', 'g');
|
||
|
|
||
|
return content
|
||
|
.replace(/\\/g, '\\\\')
|
||
|
.replace(/"/g, '\\"')
|
||
|
.replace(/\r?\n/g, '\\r\\n')
|
||
|
.replace(lineRegexp, ' "$1"\r\n')
|
||
|
.replace(/\r\n$/, '');
|
||
|
};
|
||
|
|
||
|
|
||
|
function escapeContentAsByteArray(content, lineLength)
|
||
|
{
|
||
|
var bytesPerLine = Math.floor(lineLength / 5);
|
||
|
var lineRegexp = new RegExp('((?:0x..,){1,' + bytesPerLine + '})', 'g');
|
||
|
|
||
|
return content
|
||
|
.replace(/(.{2})/g, '0x$1,')
|
||
|
.replace(lineRegexp, ' $1\r\n')
|
||
|
.replace(/,\r\n$/, '');
|
||
|
};
|
||
|
|
||
|
|
||
|
function encodeFile(file, opts)
|
||
|
{
|
||
|
var variableName;
|
||
|
|
||
|
if (opts.map.hasOwnProperty(file.relative))
|
||
|
variableName = opts.map[file.relative];
|
||
|
else
|
||
|
variableName = file.relative.replace(/[^a-zA-Z0-9_]/g, '_');
|
||
|
|
||
|
if (variableName === null)
|
||
|
return '';
|
||
|
|
||
|
variableName = opts.variablePrefix + variableName;
|
||
|
|
||
|
var escapedContent;
|
||
|
var output;
|
||
|
|
||
|
if (opts.byteArray)
|
||
|
{
|
||
|
escapedContent = escapeContentAsByteArray(file.contents.toString('hex'), opts.lineLength);
|
||
|
output = "const uint8_t " + variableName + "[] PROGMEM = {\r\n" + escapedContent + "};\r\n\r\n";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
escapedContent = escapeContent(file.contents.toString('utf-8'), opts.lineLength);
|
||
|
output = "const char " + variableName + "[] PROGMEM = \r\n" + escapedContent + ";\r\n\r\n";
|
||
|
}
|
||
|
|
||
|
return output;
|
||
|
}
|
||
|
|
||
|
|
||
|
module.exports = function(file, opts)
|
||
|
{
|
||
|
if (!file)
|
||
|
throw new Error('gulp-cppstringify: Missing file option');
|
||
|
|
||
|
opts = _.extend({
|
||
|
map: [],
|
||
|
headerDefineName: '__Embedded',
|
||
|
variablePrefix: 'Embedded',
|
||
|
lineLength: 100,
|
||
|
byteArray: false
|
||
|
}, opts || {});
|
||
|
|
||
|
var fileName;
|
||
|
var latestFile = false;
|
||
|
var latestMod = 0;
|
||
|
var output = null;
|
||
|
|
||
|
|
||
|
if (typeof file === 'string')
|
||
|
fileName = file;
|
||
|
else if (typeof file.path === 'string')
|
||
|
fileName = path.basename(file.path);
|
||
|
else
|
||
|
throw new Error('gulp-cppstringify: Missing path in file options');
|
||
|
|
||
|
|
||
|
function bufferContents(file, enc, cb)
|
||
|
{
|
||
|
if (file.isNull())
|
||
|
{
|
||
|
cb();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (file.isStream())
|
||
|
{
|
||
|
this.emit('error', new Error('gulp-cppstringify: Streaming not supported'));
|
||
|
cb();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!latestMod || file.stat && file.stat.mtime > latestMod)
|
||
|
{
|
||
|
latestFile = file;
|
||
|
latestMod = file.stat && file.stat.mtime;
|
||
|
}
|
||
|
|
||
|
if (output == null)
|
||
|
{
|
||
|
output = new Readable();
|
||
|
output._read = function noop() {};
|
||
|
|
||
|
output.push("#ifndef " + opts.headerDefineName + "\r\n");
|
||
|
output.push("#define " + opts.headerDefineName + "\r\n\r\n");
|
||
|
output.push("#include <pgmspace.h>\r\n\r\n");
|
||
|
}
|
||
|
|
||
|
output.push(encodeFile(file, opts));
|
||
|
cb();
|
||
|
}
|
||
|
|
||
|
|
||
|
function endStream(cb)
|
||
|
{
|
||
|
if (!latestFile)
|
||
|
{
|
||
|
cb();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var headerFile;
|
||
|
|
||
|
if (typeof file === 'string')
|
||
|
{
|
||
|
headerFile = latestFile.clone({contents: false});
|
||
|
headerFile.path = path.join(latestFile.base, file);
|
||
|
}
|
||
|
else
|
||
|
headerFile = new File(file);
|
||
|
|
||
|
output.push("#endif\r\n");
|
||
|
output.push(null);
|
||
|
headerFile.contents = output;
|
||
|
|
||
|
this.push(headerFile);
|
||
|
cb();
|
||
|
}
|
||
|
|
||
|
return through.obj(bufferContents, endStream);
|
||
|
};
|